"use client";

import { useCallback, useEffect, useRef, useState } from "react";
import { useEscapeKey, useFocusTrap } from "@/lib/hooks/useModalA11y";

interface BottomSheetProps {
  open: boolean;
  onClose: () => void;
  children: React.ReactNode;
  ariaLabel?: string;
}

const SNAP_POINTS = { PEEK: 0.4, HALF: 0.55, FULL: 0.92 };
const VELOCITY_THRESHOLD = 0.5;

export default function BottomSheet({ open, onClose, children, ariaLabel = "상세 정보" }: BottomSheetProps) {
  const sheetRef = useRef<HTMLDivElement>(null);
  const contentRef = useRef<HTMLDivElement>(null);
  const [height, setHeight] = useState(SNAP_POINTS.PEEK);
  const [dragging, setDragging] = useState(false);
  const dragState = useRef({ startY: 0, startH: 0, lastY: 0, lastTime: 0 });

  useEscapeKey(open, onClose);
  useFocusTrap(open, sheetRef);

  // Reset to peek when opened
  useEffect(() => {
    if (open) setHeight(SNAP_POINTS.PEEK);
  }, [open]);

  const snapTo = useCallback((h: number, velocity: number) => {
    // If fast downward swipe, close
    if (velocity > VELOCITY_THRESHOLD && h < SNAP_POINTS.HALF) {
      onClose();
      return;
    }
    // Snap to nearest point
    const points = [SNAP_POINTS.PEEK, SNAP_POINTS.HALF, SNAP_POINTS.FULL];
    let best = points[0];
    let bestDist = Math.abs(h - best);
    for (const p of points) {
      const d = Math.abs(h - p);
      if (d < bestDist) { best = p; bestDist = d; }
    }
    // If dragged below peek, close
    if (h < SNAP_POINTS.PEEK * 0.6) {
      onClose();
      return;
    }
    setHeight(best);
  }, [onClose]);

  const onTouchStart = useCallback((e: React.TouchEvent) => {
    // Don't intercept if scrolling inside content that has scrollable area
    const content = contentRef.current;
    if (content && content.scrollTop > 0 && height >= SNAP_POINTS.FULL - 0.05) return;

    const y = e.touches[0].clientY;
    dragState.current = { startY: y, startH: height, lastY: y, lastTime: Date.now() };
    setDragging(true);
  }, [height]);

  const onTouchMove = useCallback((e: React.TouchEvent) => {
    if (!dragging) return;
    const y = e.touches[0].clientY;
    const vh = window.innerHeight;
    const deltaRatio = (dragState.current.startY - y) / vh;
    const newH = Math.max(0.1, Math.min(SNAP_POINTS.FULL, dragState.current.startH + deltaRatio));
    setHeight(newH);
    dragState.current.lastY = y;
    dragState.current.lastTime = Date.now();
  }, [dragging]);

  const onTouchEnd = useCallback(() => {
    if (!dragging) return;
    setDragging(false);
    const dt = (Date.now() - dragState.current.lastTime) / 1000 || 0.1;
    const dy = (dragState.current.startY - dragState.current.lastY) / window.innerHeight;
    const velocity = -dy / dt; // positive = downward
    snapTo(height, velocity);
  }, [dragging, height, snapTo]);

  if (!open) return null;

  return (
    <>
      {/* Backdrop */}
      <div
        className="fixed inset-0 z-40 bg-black/20 md:hidden"
        style={{ opacity: Math.min(1, (height - 0.2) * 2) }}
        onClick={onClose}
      />

      {/* Sheet */}
      <div
        ref={sheetRef}
        role="dialog"
        aria-modal="true"
        aria-label={ariaLabel}
        tabIndex={-1}
        className="fixed bottom-0 left-0 right-0 z-50 md:hidden flex flex-col bg-surface/85 backdrop-blur-xl rounded-t-2xl shadow-2xl"
        style={{
          height: `${height * 100}vh`,
          transition: dragging ? "none" : "height 0.3s cubic-bezier(0.2, 0, 0, 1)",
        }}
        onTouchStart={onTouchStart}
        onTouchMove={onTouchMove}
        onTouchEnd={onTouchEnd}
      >
        {/* Handle bar */}
        <div className="flex justify-center pt-2 pb-1 shrink-0 cursor-grab">
          <div className="w-10 h-1 bg-gray-300 dark:bg-gray-600 rounded-full" />
        </div>

        {/* Content */}
        <div
          ref={contentRef}
          className="flex-1 overflow-y-auto overscroll-contain"
        >
          {children}
        </div>
      </div>
    </>
  );
}
