"use client";

import React, { useRef, useState, useEffect, useLayoutEffect, useCallback } from "react";
import { X, RotateCw, ChevronDown } from "lucide-react";
import { useTabStore, selectTabs, selectActiveTabId, Tab } from "@/stores/tabStore";
import { menuScreenApi } from "@/lib/api/screen";
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { cn } from "@/lib/utils";

const TAB_WIDTH = 180;
const TAB_GAP = 2;
const TAB_UNIT = TAB_WIDTH + TAB_GAP;
const OVERFLOW_BTN_WIDTH = 48;
const DRAG_THRESHOLD = 5;
const SETTLE_MS = 70;
const DROP_SETTLE_MS = 180;
const BAR_PAD_X = 8;

interface DragState {
  tabId: string;
  pointerId: number;
  startX: number;
  currentX: number;
  tabRect: DOMRect;
  fromIndex: number;
  targetIndex: number;
  activated: boolean;
  settling: boolean;
}

interface DropGhost {
  title: string;
  startX: number;
  startY: number;
  targetIdx: number;
  tabCountAtCreation: number;
}

export function TabBar() {
  const tabs = useTabStore(selectTabs);
  const activeTabId = useTabStore(selectActiveTabId);
  const {
    switchTab,
    closeTab,
    refreshTab,
    closeOtherTabs,
    closeTabsToLeft,
    closeTabsToRight,
    closeAllTabs,
    updateTabOrder,
    openTab,
  } = useTabStore();

  // --- Refs ---
  const containerRef = useRef<HTMLDivElement>(null);
  const settleTimer = useRef<ReturnType<typeof setTimeout> | null>(null);
  const dragActiveRef = useRef(false);
  const dragLeaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
  const dropGhostRef = useRef<HTMLDivElement>(null);
  const prevTabCountRef = useRef(tabs.length);

  // --- State ---
  const [visibleCount, setVisibleCount] = useState(tabs.length);
  const [contextMenu, setContextMenu] = useState<{
    x: number;
    y: number;
    tabId: string;
  } | null>(null);
  const [dragState, setDragState] = useState<DragState | null>(null);
  const [externalDragIdx, setExternalDragIdx] = useState<number | null>(null);
  const [dropGhost, setDropGhost] = useState<DropGhost | null>(null);

  dragActiveRef.current = !!dragState;

  // --- 타이머 정리 ---
  useEffect(() => {
    return () => {
      if (settleTimer.current) clearTimeout(settleTimer.current);
      if (dragLeaveTimerRef.current) clearTimeout(dragLeaveTimerRef.current);
    };
  }, []);

  // --- 드롭 고스트: Web Animations API로 드롭 위치 → 목표 슬롯 이동 ---
  useEffect(() => {
    if (!dropGhost) return;
    const el = dropGhostRef.current;
    const bar = containerRef.current?.getBoundingClientRect();
    if (!el || !bar) return;

    const targetX = bar.left + BAR_PAD_X + dropGhost.targetIdx * TAB_UNIT;
    const targetY = bar.bottom - 28;
    const dx = dropGhost.startX - targetX;
    const dy = dropGhost.startY - targetY;

    const anim = el.animate(
      [
        { transform: `translate(${dx}px, ${dy}px)`, opacity: 0.85 },
        { transform: "translate(0, 0)", opacity: 1 },
      ],
      {
        duration: DROP_SETTLE_MS,
        easing: "cubic-bezier(0.25, 1, 0.5, 1)",
        fill: "forwards",
      },
    );

    anim.onfinish = () => {
      setDropGhost(null);
      setExternalDragIdx(null);
    };

    const safety = setTimeout(() => {
      setDropGhost(null);
      setExternalDragIdx(null);
    }, DROP_SETTLE_MS + 500);

    return () => {
      anim.cancel();
      clearTimeout(safety);
    };
  }, [dropGhost]);

  // --- 오버플로우 계산 (드래그 중 재계산 방지) ---
  const recalcVisible = useCallback(() => {
    if (dragActiveRef.current) return;
    if (!containerRef.current) return;
    const w = containerRef.current.clientWidth;
    setVisibleCount(Math.max(1, Math.floor((w - OVERFLOW_BTN_WIDTH) / TAB_UNIT)));
  }, []);

  useEffect(() => {
    recalcVisible();
    const obs = new ResizeObserver(recalcVisible);
    if (containerRef.current) obs.observe(containerRef.current);
    return () => obs.disconnect();
  }, [recalcVisible]);

  useLayoutEffect(() => {
    recalcVisible();
  }, [tabs.length, recalcVisible]);

  const visibleTabs = tabs.slice(0, visibleCount);
  const overflowTabs = tabs.slice(visibleCount);
  const hasOverflow = overflowTabs.length > 0;

  const activeInOverflow = activeTabId && overflowTabs.some((t) => t.id === activeTabId);
  let displayVisible = visibleTabs;
  let displayOverflow = overflowTabs;

  if (activeInOverflow && activeTabId) {
    const activeTab = tabs.find((t) => t.id === activeTabId)!;
    displayVisible = [...visibleTabs.slice(0, -1), activeTab];
    displayOverflow = overflowTabs.filter((t) => t.id !== activeTabId);
    if (visibleTabs.length > 0) {
      displayOverflow = [visibleTabs[visibleTabs.length - 1], ...displayOverflow];
    }
  }

  // ============================================================
  // 사이드바 -> 탭 바 드롭 (네이티브 DnD + 삽입 위치 애니메이션)
  // ============================================================

  useLayoutEffect(() => {
    if (tabs.length !== prevTabCountRef.current && externalDragIdx !== null) {
      setExternalDragIdx(null);
    }
    prevTabCountRef.current = tabs.length;
  }, [tabs.length, externalDragIdx]);

  const resolveMenuAndOpenTab = async (
    menuName: string,
    menuObjid: string | number,
    url: string,
    insertIndex?: number,
  ) => {
    const numericObjid = typeof menuObjid === "string" ? parseInt(menuObjid) : menuObjid;
    try {
      const screens = await menuScreenApi.getScreensByMenu(numericObjid);
      if (screens.length > 0) {
        openTab(
          { type: "screen", title: menuName, screenId: screens[0].screenId, menuObjid: numericObjid },
          insertIndex,
        );
        return;
      }
    } catch {
      /* ignore */
    }
    if (url && url !== "#") {
      openTab({ type: "admin", title: menuName, adminUrl: url }, insertIndex);
    } else {
      setExternalDragIdx(null);
    }
  };

  const handleBarDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.dataTransfer.dropEffect = "copy";
    if (dragLeaveTimerRef.current) {
      clearTimeout(dragLeaveTimerRef.current);
      dragLeaveTimerRef.current = null;
    }
    const bar = containerRef.current?.getBoundingClientRect();
    if (bar) {
      const idx = Math.max(
        0,
        Math.min(Math.round((e.clientX - bar.left - BAR_PAD_X) / TAB_UNIT), displayVisible.length),
      );
      setExternalDragIdx(idx);
    }
  };

  const handleBarDragLeave = (e: React.DragEvent) => {
    if (!containerRef.current?.contains(e.relatedTarget as Node)) {
      dragLeaveTimerRef.current = setTimeout(() => {
        setExternalDragIdx(null);
        dragLeaveTimerRef.current = null;
      }, 50);
    }
  };

  const createDropGhost = (e: React.DragEvent, title: string, targetIdx: number) => {
    setDropGhost({
      title,
      startX: e.clientX - TAB_WIDTH / 2,
      startY: e.clientY - 14,
      targetIdx,
      tabCountAtCreation: tabs.length,
    });
  };

  const handleBarDrop = (e: React.DragEvent) => {
    e.preventDefault();
    if (dragLeaveTimerRef.current) {
      clearTimeout(dragLeaveTimerRef.current);
      dragLeaveTimerRef.current = null;
    }
    const insertIdx = externalDragIdx ?? undefined;
    const ghostIdx = insertIdx ?? displayVisible.length;

    const pending = e.dataTransfer.getData("application/tab-menu-pending");
    if (pending) {
      try {
        const { menuName, menuObjid, url } = JSON.parse(pending);
        createDropGhost(e, menuName, ghostIdx);
        resolveMenuAndOpenTab(menuName, menuObjid, url, insertIdx);
      } catch {
        setExternalDragIdx(null);
      }
      return;
    }
    const menuData = e.dataTransfer.getData("application/tab-menu");
    if (menuData && menuData.length > 2) {
      try {
        const parsed = JSON.parse(menuData);
        createDropGhost(e, parsed.title || "새 탭", ghostIdx);
        setExternalDragIdx(null);
        openTab(parsed, insertIdx);
      } catch {
        setExternalDragIdx(null);
      }
    } else {
      setExternalDragIdx(null);
    }
  };

  // ============================================================
  // 탭 드래그 (Pointer Events) - 임계값 + settling 애니메이션
  // ============================================================

  const calcTarget = useCallback(
    (clientX: number, startX: number, fromIndex: number): number => {
      const delta = Math.round((clientX - startX) / TAB_UNIT);
      return Math.max(0, Math.min(fromIndex + delta, displayVisible.length - 1));
    },
    [displayVisible.length],
  );

  const handlePointerDown = (e: React.PointerEvent, tabId: string, idx: number) => {
    if ((e.target as HTMLElement).closest("button")) return;
    if (dragState?.settling) return;

    if (settleTimer.current) {
      clearTimeout(settleTimer.current);
      settleTimer.current = null;
    }

    e.preventDefault();
    (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId);

    setDragState({
      tabId,
      pointerId: e.pointerId,
      startX: e.clientX,
      currentX: e.clientX,
      tabRect: (e.currentTarget as HTMLElement).getBoundingClientRect(),
      fromIndex: idx,
      targetIndex: idx,
      activated: false,
      settling: false,
    });
  };

  const handlePointerMove = useCallback(
    (e: React.PointerEvent) => {
      if (!dragState || dragState.settling) return;
      if (e.pointerId !== dragState.pointerId) return;
      const bar = containerRef.current?.getBoundingClientRect();
      if (!bar) return;

      const clampedX = Math.max(bar.left, Math.min(e.clientX, bar.right));

      if (!dragState.activated) {
        if (Math.abs(clampedX - dragState.startX) < DRAG_THRESHOLD) return;
        setDragState((p) =>
          p
            ? {
                ...p,
                activated: true,
                currentX: clampedX,
                targetIndex: calcTarget(clampedX, p.startX, p.fromIndex),
              }
            : null,
        );
        return;
      }

      setDragState((p) =>
        p ? { ...p, currentX: clampedX, targetIndex: calcTarget(clampedX, p.startX, p.fromIndex) } : null,
      );
    },
    [dragState, calcTarget],
  );

  const handlePointerUp = useCallback(
    (e: React.PointerEvent) => {
      if (!dragState || dragState.settling) return;
      if (e.pointerId !== dragState.pointerId) return;
      (e.currentTarget as HTMLElement).releasePointerCapture(e.pointerId);

      if (!dragState.activated) {
        switchTab(dragState.tabId);
        setDragState(null);
        return;
      }

      const { fromIndex, targetIndex, tabId } = dragState;

      setDragState((p) => (p ? { ...p, settling: true } : null));

      if (targetIndex === fromIndex) {
        settleTimer.current = setTimeout(() => setDragState(null), SETTLE_MS + 10);
        return;
      }

      const actualFrom = tabs.findIndex((t) => t.id === tabId);
      const tgtTab = displayVisible[targetIndex];
      const actualTo = tgtTab ? tabs.findIndex((t) => t.id === tgtTab.id) : actualFrom;

      settleTimer.current = setTimeout(() => {
        setDragState(null);
        if (actualFrom !== -1 && actualTo !== -1 && actualFrom !== actualTo) {
          updateTabOrder(actualFrom, actualTo);
        }
      }, SETTLE_MS + 10);
    },
    [dragState, tabs, displayVisible, switchTab, updateTabOrder],
  );

  const handleLostPointerCapture = useCallback(() => {
    if (dragState && !dragState.settling) {
      setDragState(null);
      if (settleTimer.current) {
        clearTimeout(settleTimer.current);
        settleTimer.current = null;
      }
    }
  }, [dragState]);

  // ============================================================
  // 스타일 계산
  // ============================================================

  const getTabAnimStyle = (tabId: string, index: number): React.CSSProperties => {
    if (externalDragIdx !== null && !dragState) {
      return {
        transform: index >= externalDragIdx ? `translateX(${TAB_UNIT}px)` : "none",
        transition: `transform ${DROP_SETTLE_MS}ms cubic-bezier(0.25, 1, 0.5, 1)`,
      };
    }

    if (!dragState || !dragState.activated) return {};

    const { fromIndex, targetIndex, tabId: draggedId } = dragState;

    if (tabId === draggedId) {
      return { opacity: 0, transition: "none" };
    }

    let shift = 0;
    if (fromIndex < targetIndex) {
      if (index > fromIndex && index <= targetIndex) shift = -TAB_UNIT;
    } else if (fromIndex > targetIndex) {
      if (index >= targetIndex && index < fromIndex) shift = TAB_UNIT;
    }

    return {
      transform: shift !== 0 ? `translateX(${shift}px)` : "none",
      transition: `transform ${SETTLE_MS}ms cubic-bezier(0.25, 1, 0.5, 1)`,
    };
  };

  const getGhostStyle = (): React.CSSProperties | null => {
    if (!dragState || !dragState.activated) return null;
    const bar = containerRef.current?.getBoundingClientRect();
    if (!bar) return null;

    const base: React.CSSProperties = {
      position: "fixed",
      top: dragState.tabRect.top,
      width: TAB_WIDTH,
      height: dragState.tabRect.height,
      zIndex: 100,
      pointerEvents: "none",
      opacity: 0.9,
    };

    if (dragState.settling) {
      return {
        ...base,
        left: bar.left + BAR_PAD_X + dragState.targetIndex * TAB_UNIT,
        opacity: 1,
        boxShadow: "none",
        transition: `left ${SETTLE_MS}ms cubic-bezier(0.25, 1, 0.5, 1), box-shadow 80ms ease-out`,
      };
    }

    const offsetX = dragState.currentX - dragState.startX;
    const rawLeft = dragState.tabRect.left + offsetX;
    return {
      ...base,
      left: Math.max(bar.left, Math.min(rawLeft, bar.right - TAB_WIDTH)),
      transition: "none",
    };
  };

  const ghostStyle = getGhostStyle();
  const draggedTab = dragState ? tabs.find((t) => t.id === dragState.tabId) : null;

  // ============================================================
  // 우클릭 컨텍스트 메뉴
  // ============================================================

  const handleContextMenu = (e: React.MouseEvent, tabId: string) => {
    e.preventDefault();
    setContextMenu({ x: e.clientX, y: e.clientY, tabId });
  };

  useEffect(() => {
    if (!contextMenu) return;
    const close = () => setContextMenu(null);
    window.addEventListener("click", close);
    window.addEventListener("scroll", close);
    return () => {
      window.removeEventListener("click", close);
      window.removeEventListener("scroll", close);
    };
  }, [contextMenu]);

  // ============================================================
  // 렌더링
  // ============================================================

  const renderTab = (tab: Tab, displayIndex: number) => {
    const isActive = tab.id === activeTabId;
    const animStyle = getTabAnimStyle(tab.id, displayIndex);
    const hiddenByGhost =
      !!dropGhost && displayIndex === dropGhost.targetIdx && tabs.length > dropGhost.tabCountAtCreation;

    return (
      <div
        key={tab.id}
        onPointerDown={(e) => handlePointerDown(e, tab.id, displayIndex)}
        onPointerMove={handlePointerMove}
        onPointerUp={handlePointerUp}
        onLostPointerCapture={handleLostPointerCapture}
        onContextMenu={(e) => handleContextMenu(e, tab.id)}
        className={cn(
          "group relative flex h-7 shrink-0 cursor-pointer items-center gap-0.5 rounded-t-md border border-b-0 px-3 select-none",
          isActive
            ? "text-primary z-10 -mb-px h-[30px] bg-primary/15 dark:bg-primary/20 border-primary/40 border-t-[3px] border-t-primary font-semibold"
            : "bg-transparent text-muted-foreground hover:bg-muted/50 hover:text-foreground border-transparent",
        )}
        style={{
          width: TAB_WIDTH,
          touchAction: "none",
          ...animStyle,
          ...(hiddenByGhost ? { opacity: 0 } : {}),
          ...(isActive ? {} : {}),
        }}
        title={tab.title}
      >
        <span className="min-w-0 flex-1 truncate text-[11px] font-medium">{tab.title}</span>

        <div className="flex shrink-0 items-center">
          {isActive && (
            <button
              onClick={(e) => {
                e.stopPropagation();
                refreshTab(tab.id);
              }}
              className="text-muted-foreground hover:bg-accent hover:text-foreground flex h-4 w-4 items-center justify-center rounded-sm transition-colors"
            >
              <RotateCw className="h-2.5 w-2.5" />
            </button>
          )}
          <button
            onClick={(e) => {
              e.stopPropagation();
              closeTab(tab.id);
            }}
            className={cn(
              "text-muted-foreground hover:bg-destructive/10 hover:text-destructive flex h-4 w-4 items-center justify-center rounded-sm transition-colors",
              !isActive && "opacity-0 group-hover:opacity-100",
            )}
          >
            <X className="h-2.5 w-2.5" />
          </button>
        </div>
      </div>
    );
  };

  if (tabs.length === 0) return null;

  return (
    <>
      <div
        ref={containerRef}
        className="border-border bg-background relative flex h-[33px] shrink-0 items-end gap-[2px] overflow-hidden px-1.5"
        onDragOver={handleBarDragOver}
        onDragLeave={handleBarDragLeave}
        onDrop={handleBarDrop}
      >
        <div className="border-border pointer-events-none absolute inset-x-0 bottom-0 z-0 border-b" />
        <div className="pointer-events-none absolute inset-0 z-5" />
        {displayVisible.map((tab, i) => renderTab(tab, i))}

        {hasOverflow && (
          <DropdownMenu>
            <DropdownMenuTrigger asChild>
              <button className="bg-muted/50 text-muted-foreground hover:bg-muted hover:text-foreground flex h-7 shrink-0 items-center gap-0.5 rounded-t-md border border-b-0 border-transparent px-2 text-[11px] font-medium transition-colors">
                +{displayOverflow.length}
                <ChevronDown className="h-2.5 w-2.5" />
              </button>
            </DropdownMenuTrigger>
            <DropdownMenuContent align="end" className="max-h-[300px] overflow-y-auto">
              {displayOverflow.map((tab) => (
                <DropdownMenuItem
                  key={tab.id}
                  onClick={() => switchTab(tab.id)}
                  className="flex items-center justify-between gap-2"
                >
                  <span className="min-w-0 flex-1 truncate text-xs">{tab.title}</span>
                  <button
                    onClick={(e) => {
                      e.stopPropagation();
                      closeTab(tab.id);
                    }}
                    className="hover:bg-destructive/10 hover:text-destructive flex h-4 w-4 shrink-0 items-center justify-center rounded-sm"
                  >
                    <X className="h-3 w-3" />
                  </button>
                </DropdownMenuItem>
              ))}
            </DropdownMenuContent>
          </DropdownMenu>
        )}
      </div>

      {/* 탭 드래그 고스트 (내부 재정렬) */}
      {ghostStyle && draggedTab && (
        <div
          style={ghostStyle}
          className="border-primary/50 bg-background rounded-t-md border border-b-0 px-3"
        >
          <div className="flex h-full items-center">
            <span className="truncate text-[11px] font-medium">{draggedTab.title}</span>
          </div>
        </div>
      )}

      {/* 사이드바 드롭 고스트 (드롭 지점 → 탭 슬롯 이동) */}
      {dropGhost &&
        (() => {
          const bar = containerRef.current?.getBoundingClientRect();
          if (!bar) return null;

          const targetX = bar.left + BAR_PAD_X + dropGhost.targetIdx * TAB_UNIT;
          const targetY = bar.bottom - 28;

          return (
            <div
              ref={dropGhostRef}
              style={{
                position: "fixed",
                left: targetX,
                top: targetY,
                width: TAB_WIDTH,
                height: 28,
                zIndex: 100,
                pointerEvents: "none",
              }}
              className="border-border bg-background rounded-t-md border border-b-0 px-3"
            >
              <div className="flex h-full items-center">
                <span className="truncate text-[11px] font-medium">{dropGhost.title}</span>
              </div>
            </div>
          );
        })()}

      {/* 우클릭 컨텍스트 메뉴 */}
      {contextMenu && (
        <div
          className="border-border bg-popover fixed z-50 min-w-[180px] rounded-md border p-1 shadow-md"
          style={{ left: contextMenu.x, top: contextMenu.y }}
        >
          <ContextMenuItem
            label="새로고침"
            onClick={() => {
              refreshTab(contextMenu.tabId);
              setContextMenu(null);
            }}
          />
          <div className="bg-border my-1 h-px" />
          <ContextMenuItem
            label="왼쪽 탭 닫기"
            onClick={() => {
              closeTabsToLeft(contextMenu.tabId);
              setContextMenu(null);
            }}
          />
          <ContextMenuItem
            label="오른쪽 탭 닫기"
            onClick={() => {
              closeTabsToRight(contextMenu.tabId);
              setContextMenu(null);
            }}
          />
          <ContextMenuItem
            label="다른 탭 모두 닫기"
            onClick={() => {
              closeOtherTabs(contextMenu.tabId);
              setContextMenu(null);
            }}
          />
          <div className="bg-border my-1 h-px" />
          <ContextMenuItem
            label="모든 탭 닫기"
            onClick={() => {
              closeAllTabs();
              setContextMenu(null);
            }}
            destructive
          />
        </div>
      )}
    </>
  );
}

function ContextMenuItem({
  label,
  onClick,
  destructive,
}: {
  label: string;
  onClick: () => void;
  destructive?: boolean;
}) {
  return (
    <button
      onClick={onClick}
      className={cn(
        "flex w-full items-center rounded-sm px-2 py-1.5 text-xs transition-colors",
        destructive ? "text-destructive hover:bg-destructive/10" : "text-foreground hover:bg-accent",
      )}
    >
      {label}
    </button>
  );
}
