import { useCallback, useEffect, useRef, type ReactNode } from "react";
import { createPortal } from "react-dom";

export const DITHERED_SHADOW = `
  3px 3px 0 0 var(--border), 5px 3px 0 0 transparent, 7px 3px 0 0 var(--border),
  4px 4px 0 0 transparent, 6px 4px 0 0 var(--border),
  3px 5px 0 0 var(--border), 5px 5px 0 0 transparent, 7px 5px 0 0 var(--border),
  4px 6px 0 0 var(--border), 6px 6px 0 0 transparent
`;

export interface FloatingWindowProps {
  id: string;
  title: string;
  x: number;
  y: number;
  w: number;
  h: number;
  zIndex: number;
  focused: boolean;
  onUpdate: (id: string, patch: { x?: number; y?: number; w?: number; h?: number }) => void;
  onClose: (id: string) => void;
  onFocus: (id: string) => void;
  minW?: number;
  minH?: number;
  addressBar?: ReactNode;
  footer?: ReactNode;
  containerRef?: React.RefObject<HTMLDivElement | null>;
  children: ReactNode;
}

export default function FloatingWindow({
  id, title, x, y, w, h, zIndex, focused,
  onUpdate, onClose, onFocus,
  minW = 320, minH = 200,
  addressBar, footer, containerRef, children,
}: FloatingWindowProps) {
  const internalRef = useRef<HTMLDivElement>(null);
  const ref = containerRef ?? internalRef;
  const dragRef = useRef<{ startX: number; startY: number; origX: number; origY: number } | null>(null);
  const resizeRef = useRef<{ startX: number; startY: number; origW: number; origH: number } | null>(null);
  const velocityRef = useRef({ vx: 0, vy: 0, lastX: 0, lastY: 0, lastT: 0 });
  const inertiaRef = useRef(0);
  const posRef = useRef({ x, y });
  posRef.current = { x, y };

  useEffect(() => { if (focused) ref.current?.focus(); }, [focused]);

  // Cancel any running inertia animation
  const stopInertia = useCallback(() => {
    if (inertiaRef.current) { cancelAnimationFrame(inertiaRef.current); inertiaRef.current = 0; }
  }, []);

  const onDragStart = useCallback((e: React.MouseEvent) => {
    if ((e.target as HTMLElement).closest("button")) return;
    e.preventDefault(); onFocus(id);
    ref.current?.focus();
    stopInertia();
    dragRef.current = { startX: e.clientX, startY: e.clientY, origX: x, origY: y };
    velocityRef.current = { vx: 0, vy: 0, lastX: e.clientX, lastY: e.clientY, lastT: performance.now() };
    document.documentElement.classList.add("cursor-grabbing");

    const onMove = (ev: MouseEvent) => {
      if (!dragRef.current) return;
      const now = performance.now();
      const dt = now - velocityRef.current.lastT;
      if (dt > 0) {
        const smooth = 0.3;
        const rawVx = (ev.clientX - velocityRef.current.lastX) / dt * 16;
        const rawVy = (ev.clientY - velocityRef.current.lastY) / dt * 16;
        velocityRef.current.vx = velocityRef.current.vx * (1 - smooth) + rawVx * smooth;
        velocityRef.current.vy = velocityRef.current.vy * (1 - smooth) + rawVy * smooth;
        velocityRef.current.lastX = ev.clientX;
        velocityRef.current.lastY = ev.clientY;
        velocityRef.current.lastT = now;
      }
      onUpdate(id, {
        x: dragRef.current.origX + (ev.clientX - dragRef.current.startX),
        y: Math.max(0, dragRef.current.origY + (ev.clientY - dragRef.current.startY)),
      });
    };

    const onUp = () => {
      const { vx, vy } = velocityRef.current;
      dragRef.current = null;
      document.documentElement.classList.remove("cursor-grabbing");
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);

      // Kick off inertia if there's meaningful velocity
      if (Math.abs(vx) > 0.5 || Math.abs(vy) > 0.5) {
        let curVx = vx;
        let curVy = vy;
        const friction = 0.92;
        const el = ref.current;
        const tick = () => {
          curVx *= friction;
          curVy *= friction;
          if (Math.abs(curVx) < 0.3 && Math.abs(curVy) < 0.3) {
            inertiaRef.current = 0;
            // Sync final position to React state once
            onUpdate(id, posRef.current);
            return;
          }
          posRef.current = { x: posRef.current.x + curVx, y: Math.max(0, posRef.current.y + curVy) };
          // Direct DOM update during animation — skip React reconciliation
          if (el) {
            el.style.left = `${posRef.current.x}px`;
            el.style.top = `${posRef.current.y}px`;
          }
          inertiaRef.current = requestAnimationFrame(tick);
        };
        inertiaRef.current = requestAnimationFrame(tick);
      }
    };

    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
  }, [id, x, y, onUpdate, onFocus, stopInertia]);

  const onResizeStart = useCallback((e: React.MouseEvent) => {
    e.preventDefault(); e.stopPropagation(); onFocus(id);
    resizeRef.current = { startX: e.clientX, startY: e.clientY, origW: w, origH: h };
    document.documentElement.classList.add("cursor-nwse-resize");
    const onMove = (ev: MouseEvent) => { if (!resizeRef.current) return; onUpdate(id, { w: Math.max(minW, resizeRef.current.origW + (ev.clientX - resizeRef.current.startX)), h: Math.max(minH, resizeRef.current.origH + (ev.clientY - resizeRef.current.startY)) }); };
    const onUp = () => { resizeRef.current = null; document.documentElement.classList.remove("cursor-nwse-resize"); document.removeEventListener("mousemove", onMove); document.removeEventListener("mouseup", onUp); };
    document.addEventListener("mousemove", onMove); document.addEventListener("mouseup", onUp);
  }, [id, w, h, minW, minH, onUpdate, onFocus]);

  return createPortal(
    <div ref={ref} tabIndex={-1} onKeyDown={(e) => { if (e.key === "Escape") onClose(id); }} onMouseDown={() => onFocus(id)}
      className="fixed z-999 flex flex-col bg-popover text-popover-foreground border-2 rounded-lg outline-none transition-[border-color,opacity] duration-150"
      style={{ left: x, top: y, width: w, height: h, zIndex: 999 + zIndex, borderColor: focused ? "var(--primary)" : "var(--border)", opacity: focused ? 1 : 0.85, boxShadow: DITHERED_SHADOW }}>
      {/* Title bar */}
      <div onMouseDown={onDragStart} className="flex items-center gap-2 px-3 py-1.5 border-b-2 border-border cursor-grab active:cursor-grabbing select-none shrink-0 bg-muted/30 rounded-t-lg">
        <div className="flex items-center gap-1.5">
          <button onClick={() => onClose(id)} className="w-2.5 h-2.5 rounded-full bg-destructive hover:brightness-125 transition-all" />
          <span className="w-2.5 h-2.5 rounded-full bg-muted-foreground/30" /><span className="w-2.5 h-2.5 rounded-full bg-muted-foreground/30" />
        </div>
        <span className="flex-1 text-[10px] font-semibold uppercase tracking-wider truncate text-center">{title}</span>
      </div>
      {/* Optional address bar */}
      {addressBar}
      {/* Content */}
      <div className="flex-1 min-h-0">
        {children}
      </div>
      {/* Optional footer */}
      {footer}
      {/* Resize handle */}
      <div onMouseDown={onResizeStart} className="absolute bottom-0 right-0 w-4 h-4 cursor-nwse-resize" style={{ touchAction: "none" }}>
        <svg viewBox="0 0 16 16" className="w-full h-full text-muted-foreground/50"><path d="M14 14L8 14L14 8Z" fill="currentColor" /><path d="M14 14L11 14L14 11Z" fill="currentColor" opacity="0.5" /></svg>
      </div>
    </div>, document.body);
}
