"use client";

import React, { useMemo, useState } from "react";
import { useAutoAnimate } from "@formkit/auto-animate/react";
import type { MenuItem } from "@/lib/api/menu";

export type DropPos = "before" | "after" | "into";

interface TreeNode {
  id: string;
  parentId: string;
  name: string;
  url: string;
  lev: number;
  status: string;
  raw: Record<string, any>;
  children: TreeNode[];
}

interface Props {
  menus: MenuItem[];
  selectedId: string;
  expandedIds: Set<string>;
  searchText: string;
  onSelect: (id: string) => void;
  onToggleExpand: (id: string) => void;
  onSearchChange: (s: string) => void;
  onAddTop: () => void;
  onMove: (sourceId: string, targetId: string, pos: DropPos) => void;
}

const buildTree = (menus: MenuItem[]): TreeNode[] => {
  const map = new Map<string, TreeNode>();
  const roots: TreeNode[] = [];

  for (const m of menus) {
    const id = String(m.objid ?? m.OBJID ?? "");
    if (!id) continue;
    map.set(id, {
      id,
      parentId: String(m.parent_obj_id ?? m.PARENT_OBJ_ID ?? "0"),
      name: m.menu_name_kor ?? m.MENU_NAME_KOR ?? "(no name)",
      url: m.menu_url ?? m.MENU_URL ?? "",
      lev: Number(m.lev ?? m.LEV ?? 1),
      status: (m.status ?? m.STATUS ?? "").toString().toLowerCase(),
      raw: m as any,
      children: [],
    });
  }

  map.forEach((node) => {
    if (node.parentId && node.parentId !== "0" && map.has(node.parentId)) {
      map.get(node.parentId)!.children.push(node);
    } else {
      roots.push(node);
    }
  });

  const sortRec = (nodes: TreeNode[]) => {
    nodes.sort((a, b) => (Number(a.raw.seq ?? a.raw.SEQ ?? 0) - Number(b.raw.seq ?? b.raw.SEQ ?? 0)));
    nodes.forEach((n) => sortRec(n.children));
  };
  sortRec(roots);

  return roots;
};

const filterTree = (nodes: TreeNode[], q: string): TreeNode[] => {
  if (!q) return nodes;
  const lower = q.toLowerCase();
  const rec = (node: TreeNode): TreeNode | null => {
    const matchSelf =
      node.name.toLowerCase().includes(lower) || node.url.toLowerCase().includes(lower);
    const filteredChildren = node.children.map(rec).filter(Boolean) as TreeNode[];
    if (matchSelf || filteredChildren.length) {
      return { ...node, children: filteredChildren };
    }
    return null;
  };
  return nodes.map(rec).filter(Boolean) as TreeNode[];
};

const StatusDot = ({ on }: { on: boolean }) => (
  <span className={`v5-mm-dot${on ? " on" : ""}`} />
);

interface RowProps {
  node: TreeNode;
  selectedId: string;
  expandedIds: Set<string>;
  draggingId: string | null;
  dropHint: { id: string; pos: DropPos } | null;
  onSelect: (id: string) => void;
  onToggleExpand: (id: string) => void;
  onDragStart: (id: string) => void;
  onDragEnd: () => void;
  onDragOver: (e: React.DragEvent, id: string, lev: number) => void;
  onDrop: (e: React.DragEvent, id: string) => void;
}

const NodeRow: React.FC<RowProps> = ({
  node,
  selectedId,
  expandedIds,
  draggingId,
  dropHint,
  onSelect,
  onToggleExpand,
  onDragStart,
  onDragEnd,
  onDragOver,
  onDrop,
}) => {
  const hasChildren = node.children.length > 0;
  const open = expandedIds.has(node.id);
  const sel = selectedId === node.id;
  const dragging = draggingId === node.id;
  const dropCls =
    dropHint && dropHint.id === node.id
      ? dropHint.pos === "before"
        ? "drop-before"
        : dropHint.pos === "after"
        ? "drop-after"
        : "drop-into"
      : "";
  const cls = [
    "v5-mm-node",
    node.lev === 1 ? "l1" : node.lev === 2 ? "l2" : "l3",
    hasChildren ? "" : "leaf",
    open ? "open" : "",
    sel ? "on" : "",
    dragging ? "dragging" : "",
    dropCls,
  ]
    .filter(Boolean)
    .join(" ");

  const isActive = node.status === "active";

  return (
    <>
      <div
        className={cls}
        onClick={() => onSelect(node.id)}
        draggable
        onDragStart={(e) => {
          e.stopPropagation();
          e.dataTransfer.effectAllowed = "move";
          e.dataTransfer.setData("text/plain", node.id);
          onDragStart(node.id);
        }}
        onDragEnd={onDragEnd}
        onDragOver={(e) => onDragOver(e, node.id, node.lev)}
        onDrop={(e) => onDrop(e, node.id)}
      >
        <span
          className="v5-mm-caret"
          onClick={(e) => {
            e.stopPropagation();
            if (hasChildren) onToggleExpand(node.id);
          }}
        >
          {hasChildren && (
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5">
              <path d="m9 5 7 7-7 7" />
            </svg>
          )}
        </span>
        {node.lev === 1 ? (
          <span className="v5-mm-node-ico">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
              <rect x="3" y="3" width="7" height="7" rx="1.5" />
              <rect x="14" y="3" width="7" height="7" rx="1.5" />
              <rect x="3" y="14" width="7" height="7" rx="1.5" />
              <rect x="14" y="14" width="7" height="7" rx="1.5" />
            </svg>
          </span>
        ) : (
          <StatusDot on={isActive} />
        )}
        <div className="v5-mm-node-body">
          <div className="v5-mm-node-name">{node.name}</div>
          {node.lev > 1 && node.url && <div className="v5-mm-node-meta">{node.url}</div>}
        </div>
        {node.lev === 1 && hasChildren && <span className="v5-mm-cnt">{node.children.length}</span>}
      </div>
      {open && hasChildren && (
        <div className="v5-mm-sub" style={{ display: "block" }}>
          {node.children.map((child) => (
            <NodeRow
              key={child.id}
              node={child}
              selectedId={selectedId}
              expandedIds={expandedIds}
              draggingId={draggingId}
              dropHint={dropHint}
              onSelect={onSelect}
              onToggleExpand={onToggleExpand}
              onDragStart={onDragStart}
              onDragEnd={onDragEnd}
              onDragOver={onDragOver}
              onDrop={onDrop}
            />
          ))}
        </div>
      )}
    </>
  );
};

export function MenuTreePanel({
  menus,
  selectedId,
  expandedIds,
  searchText,
  onSelect,
  onToggleExpand,
  onSearchChange,
  onAddTop,
  onMove,
}: Props) {
  const tree = useMemo(() => buildTree(menus), [menus]);
  const filtered = useMemo(() => filterTree(tree, searchText), [tree, searchText]);

  const total = menus.length;
  const rootCount = tree.length;

  const [draggingId, setDraggingId] = useState<string | null>(null);
  const [dropHint, setDropHint] = useState<{ id: string; pos: DropPos } | null>(null);
  const [treeRef] = useAutoAnimate<HTMLDivElement>({ duration: 280, easing: "cubic-bezier(.16,1,.3,1)" });

  const handleDragStart = (id: string) => setDraggingId(id);
  const handleDragEnd = () => {
    setDraggingId(null);
    setDropHint(null);
  };
  const handleDragOver = (e: React.DragEvent, id: string, lev: number) => {
    e.preventDefault();
    e.stopPropagation();
    if (!draggingId || draggingId === id) return;
    e.dataTransfer.dropEffect = "move";
    const rect = (e.currentTarget as HTMLElement).getBoundingClientRect();
    const y = e.clientY - rect.top;
    const h = rect.height;
    // L1: 카드형 — before/after 50/50 (자식 승격이 용이)
    // L2/L3: 3-zone — 상단 33% before / 중앙 34% into (하위로 넣기) / 하단 33% after
    let pos: DropPos;
    if (lev === 1) {
      pos = y < h * 0.5 ? "before" : "after";
    } else {
      if (y < h * 0.33) pos = "before";
      else if (y > h * 0.67) pos = "after";
      else pos = "into";
    }
    setDropHint((prev) => (prev && prev.id === id && prev.pos === pos ? prev : { id, pos }));
  };
  const handleDrop = (e: React.DragEvent, id: string) => {
    e.preventDefault();
    e.stopPropagation();
    const sourceId = draggingId || e.dataTransfer.getData("text/plain");
    const pos = dropHint?.pos || "after";
    if (sourceId && sourceId !== id) {
      onMove(sourceId, id, pos);
    }
    setDraggingId(null);
    setDropHint(null);
  };

  return (
    <section className="v5-mm-col v5-mm-col-tree">
      <div className="v5-mm-col-hd">
        <div>
          <div className="v5-mm-step">
            <span className="num">02</span>Tree
          </div>
          <h3>메뉴 트리</h3>
          <p>
            {rootCount}개 · {total}개 항목
          </p>
        </div>
        <button className="v5-mm-hd-add" title="최상위 메뉴 추가" onClick={onAddTop}>
          <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2">
            <path d="M12 5v14M5 12h14" />
          </svg>
        </button>
      </div>

      <div className="v5-mm-tree-srch">
        <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
          <circle cx="11" cy="11" r="7" />
          <path d="m21 21-4.3-4.3" />
        </svg>
        <input
          placeholder="트리 검색…"
          value={searchText}
          onChange={(e) => onSearchChange(e.target.value)}
        />
      </div>

      <div
        className="v5-mm-tree"
        ref={treeRef}
        onDragOver={(e) => {
          if (!draggingId) return;
          // 자식 노드가 이벤트 처리 중이면(dropHint 이미 있음) 무시
          if (dropHint) return;
          e.preventDefault();
          e.dataTransfer.dropEffect = "move";
        }}
        onDrop={(e) => {
          if (!draggingId) return;
          if (dropHint) return; // 자식 노드가 처리
          e.preventDefault();
          // 마지막 L1의 after로 이동
          const lastL1 = [...filtered].reverse()[0];
          if (lastL1 && draggingId !== lastL1.id) {
            onMove(draggingId, lastL1.id, "after");
          }
          setDraggingId(null);
          setDropHint(null);
        }}
      >
        {filtered.length === 0 ? (
          <div className="v5-mm-empty">
            <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.5">
              <circle cx="11" cy="11" r="7" />
              <path d="m21 21-4.3-4.3" />
            </svg>
            <div>검색 결과가 없습니다</div>
          </div>
        ) : (
          filtered.map((node) => (
            <NodeRow
              key={node.id}
              node={node}
              selectedId={selectedId}
              expandedIds={expandedIds}
              draggingId={draggingId}
              dropHint={dropHint}
              onSelect={onSelect}
              onToggleExpand={onToggleExpand}
              onDragStart={handleDragStart}
              onDragEnd={handleDragEnd}
              onDragOver={handleDragOver}
              onDrop={handleDrop}
            />
          ))
        )}
      </div>
    </section>
  );
}
