import {
  useEffect,
  useRef,
  useState,
  type KeyboardEvent,
  type PointerEvent,
  type ReactNode
} from "react";
import { cn } from "@/shared/ui/cn";
import {
  getMobileWorkbenchSheetHeight,
  type MobileWorkbenchSheetSnap
} from "./mobile-workbench-sheet-layout";

export type { MobileWorkbenchSheetSnap } from "./mobile-workbench-sheet-layout";

type MobileWorkbenchSheetProps = {
  label: string;
  snap: MobileWorkbenchSheetSnap;
  onSnapChange: (snap: MobileWorkbenchSheetSnap) => void;
  onClose: () => void;
  children: ReactNode;
  className?: string;
};

const SNAP_ORDER: MobileWorkbenchSheetSnap[] = ["half", "full"];

export function MobileWorkbenchSheet({
  label,
  snap,
  onSnapChange,
  onClose,
  children,
  className
}: MobileWorkbenchSheetProps) {
  const pointerStartRef = useRef<{ y: number; height: number } | null>(null);
  const draggedRef = useRef(false);
  const [dragHeight, setDragHeight] = useState<number | null>(null);
  const [viewportHeight, setViewportHeight] = useState(
    typeof window === "undefined" ? 844 : window.innerHeight
  );
  const restingHeight = getMobileWorkbenchSheetHeight(snap, viewportHeight);

  useEffect(() => {
    const updateViewportHeight = () => setViewportHeight(window.innerHeight);
    window.addEventListener("resize", updateViewportHeight);
    window.visualViewport?.addEventListener("resize", updateViewportHeight);
    return () => {
      window.removeEventListener("resize", updateViewportHeight);
      window.visualViewport?.removeEventListener("resize", updateViewportHeight);
    };
  }, []);

  useEffect(() => {
    const handleEscape = (event: globalThis.KeyboardEvent) => {
      if (event.key === "Escape") {
        onClose();
      }
    };

    window.addEventListener("keydown", handleEscape);
    return () => window.removeEventListener("keydown", handleEscape);
  }, [onClose]);

  function handlePointerDown(event: PointerEvent<HTMLButtonElement>) {
    pointerStartRef.current = {
      y: event.clientY,
      height: restingHeight
    };
    draggedRef.current = false;
    event.currentTarget.setPointerCapture(event.pointerId);
  }

  function handlePointerMove(event: PointerEvent<HTMLButtonElement>) {
    const start = pointerStartRef.current;
    if (!start) {
      return;
    }

    const delta = start.y - event.clientY;
    if (Math.abs(delta) > 4) {
      draggedRef.current = true;
    }

    const minHeight = getMobileWorkbenchSheetHeight("half", window.innerHeight);
    const maxHeight = getMobileWorkbenchSheetHeight("full", window.innerHeight);
    setDragHeight(Math.min(maxHeight, Math.max(minHeight, start.height + delta)));
  }

  function handlePointerUp(event: PointerEvent<HTMLButtonElement>) {
    if (!pointerStartRef.current) {
      return;
    }

    const finalHeight = dragHeight ?? pointerStartRef.current.height;
    pointerStartRef.current = null;
    setDragHeight(null);
    event.currentTarget.releasePointerCapture(event.pointerId);

    if (!draggedRef.current) {
      return;
    }

    onSnapChange(getClosestSnap(finalHeight, window.innerHeight));
  }

  function handleClick() {
    if (draggedRef.current) {
      draggedRef.current = false;
      return;
    }

    const currentIndex = SNAP_ORDER.indexOf(snap);
    onSnapChange(SNAP_ORDER[(currentIndex + 1) % SNAP_ORDER.length] ?? "half");
  }

  function handleKeyDown(event: KeyboardEvent<HTMLButtonElement>) {
    if (event.key === "ArrowUp") {
      event.preventDefault();
      onSnapChange(getAdjacentSnap(snap, 1));
      return;
    }

    if (event.key === "ArrowDown") {
      event.preventDefault();
      onSnapChange(getAdjacentSnap(snap, -1));
      return;
    }

    if (event.key === "Home") {
      event.preventDefault();
      onSnapChange("half");
      return;
    }

    if (event.key === "End") {
      event.preventDefault();
      onSnapChange("full");
    }
  }

  return (
    <section
      aria-label={label}
      data-snap={snap}
      className={cn(
        "mobile-workbench-sheet acrylic-panel pointer-events-auto absolute bottom-0 left-0 right-0 z-40 flex min-h-0 flex-col overflow-hidden rounded-t-[20px] border-x border-t transition-[height] duration-200 ease-[cubic-bezier(0.16,1,0.3,1)] motion-reduce:transition-none lg:hidden",
        className
      )}
      style={{ height: dragHeight ?? restingHeight }}
    >
      <div className="mobile-workbench-sheet-handle relative z-40 flex h-7 shrink-0 items-center">
        <button
          type="button"
          aria-label={`${label}高度，当前${getSnapLabel(snap)}`}
          className="group flex h-7 flex-1 touch-none items-center justify-center"
          onClick={handleClick}
          onKeyDown={handleKeyDown}
          onPointerDown={handlePointerDown}
          onPointerMove={handlePointerMove}
          onPointerUp={handlePointerUp}
        >
          <span className="h-1 w-10 rounded-full bg-slate-400/70 transition-[width,background-color] group-focus-visible:w-12 group-focus-visible:bg-blue-600" />
        </button>
      </div>
      <div className="min-h-0 flex-1 overscroll-contain">{children}</div>
    </section>
  );
}

function getAdjacentSnap(
  current: MobileWorkbenchSheetSnap,
  direction: -1 | 1
): MobileWorkbenchSheetSnap {
  const currentIndex = SNAP_ORDER.indexOf(current);
  const nextIndex = Math.min(SNAP_ORDER.length - 1, Math.max(0, currentIndex + direction));
  return SNAP_ORDER[nextIndex] ?? current;
}

function getClosestSnap(height: number, viewportHeight: number): MobileWorkbenchSheetSnap {
  return SNAP_ORDER.reduce((closest, candidate) => {
    const candidateDistance = Math.abs(
      getMobileWorkbenchSheetHeight(candidate, viewportHeight) - height
    );
    const closestDistance = Math.abs(
      getMobileWorkbenchSheetHeight(closest, viewportHeight) - height
    );
    return candidateDistance < closestDistance ? candidate : closest;
  }, "half");
}

function getSnapLabel(snap: MobileWorkbenchSheetSnap) {
  if (snap === "half") {
    return "半屏档";
  }

  return "全屏档";
}
