"use client";

import { useState, useEffect, useCallback, useMemo } from "react";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import {
  Plus,
  Search,
  Network,
  RefreshCw,
  Pencil,
  Copy,
  Trash2,
  LayoutGrid,
  List,
  Loader2,
} from "lucide-react";
import { toast } from "sonner";
import { showErrorToast } from "@/lib/utils/toastUtils";
import { apiClient } from "@/lib/api/client";
import { getNodePaletteItem } from "@/components/dataflow/node-editor/sidebar/nodePaletteConfig";

interface TopologyNode {
  id: string;
  type: string;
  x: number;
  y: number;
}

interface FlowSummary {
  nodeCount: number;
  edgeCount: number;
  nodeTypes: Record<string, number>;
  topology: {
    nodes: TopologyNode[];
    edges: [string, string][];
  } | null;
}

interface NodeFlow {
  flowId: number;
  flowName: string;
  flowDescription: string;
  createdAt: string;
  updatedAt: string;
  summary: FlowSummary;
}

interface DataFlowListProps {
  onLoadFlow: (flowId: number | null) => void;
}

const CATEGORY_COLORS: Record<string, { text: string; bg: string }> = {
  source: { text: "text-teal-700 dark:text-teal-400", bg: "bg-teal-100 dark:bg-teal-500/15" },
  transform: { text: "text-violet-700 dark:text-violet-400", bg: "bg-violet-100 dark:bg-violet-500/15" },
  action: { text: "text-emerald-700 dark:text-emerald-400", bg: "bg-emerald-100 dark:bg-emerald-500/15" },
  external: { text: "text-pink-700 dark:text-pink-400", bg: "bg-pink-100 dark:bg-pink-500/15" },
  utility: { text: "text-gray-700 dark:text-gray-400", bg: "bg-gray-100 dark:bg-gray-500/15" },
};

function getNodeCategoryColor(nodeType: string) {
  const item = getNodePaletteItem(nodeType);
  const cat = item?.category || "utility";
  return CATEGORY_COLORS[cat] || CATEGORY_COLORS.utility;
}

function getNodeLabel(nodeType: string) {
  const item = getNodePaletteItem(nodeType);
  return item?.label || nodeType;
}

function getNodeColor(nodeType: string): string {
  const item = getNodePaletteItem(nodeType);
  return item?.color || "#6B7280";
}

function relativeTime(dateStr: string): string {
  const now = Date.now();
  const d = new Date(dateStr).getTime();
  const diff = now - d;
  const min = Math.floor(diff / 60000);
  if (min < 1) return "방금 전";
  if (min < 60) return `${min}분 전`;
  const h = Math.floor(min / 60);
  if (h < 24) return `${h}시간 전`;
  const day = Math.floor(h / 24);
  if (day < 30) return `${day}일 전`;
  const month = Math.floor(day / 30);
  return `${month}개월 전`;
}

function MiniTopology({ topology }: { topology: FlowSummary["topology"] }) {
  if (!topology || topology.nodes.length === 0) {
    return (
      <div className="flex h-full items-center justify-center">
        <Network className="h-4 w-4 text-muted-foreground/30" />
      </div>
    );
  }

  const W = 280;
  const H = 60;
  const padX = 30;
  const padY = 12;
  const nodeMap = new Map(topology.nodes.map((n) => [n.id, n]));

  return (
    <svg viewBox={`0 0 ${W} ${H}`} fill="none" className="h-full w-full">
      {topology.edges.map(([src, tgt], i) => {
        const s = nodeMap.get(src);
        const t = nodeMap.get(tgt);
        if (!s || !t) return null;
        const sx = padX + s.x * (W - padX * 2);
        const sy = padY + s.y * (H - padY * 2);
        const tx = padX + t.x * (W - padX * 2);
        const ty = padY + t.y * (H - padY * 2);
        return (
          <line key={`e-${i}`} x1={sx} y1={sy} x2={tx} y2={ty} stroke="currentColor" strokeWidth="1" className="text-border" strokeOpacity="0.5" />
        );
      })}
      {topology.nodes.map((n) => {
        const cx = padX + n.x * (W - padX * 2);
        const cy = padY + n.y * (H - padY * 2);
        const color = getNodeColor(n.type);
        return (
          <g key={n.id}>
            <circle cx={cx} cy={cy} r="4" fill={`${color}30`} stroke={color} strokeWidth="1.2" />
            <circle cx={cx} cy={cy} r="1.5" fill={color} />
          </g>
        );
      })}
    </svg>
  );
}

function FlowCard({
  flow,
  onOpen,
  onCopy,
  onDelete,
}: {
  flow: NodeFlow;
  onOpen: () => void;
  onCopy: () => void;
  onDelete: () => void;
}) {
  const chips = useMemo(() => {
    const entries = Object.entries(flow.summary?.nodeTypes || {});
    return entries.slice(0, 4).map(([type, count]) => {
      const colors = getNodeCategoryColor(type);
      const label = getNodeLabel(type);
      return { type, count, label, colors };
    });
  }, [flow.summary?.nodeTypes]);

  return (
    <div
      className="group relative cursor-pointer rounded-lg border bg-card transition-all hover:shadow-md hover:border-primary/30"
      onClick={onOpen}
    >
      {/* 미니 토폴로지 */}
      <div className="h-[60px] overflow-hidden border-b bg-muted/30 px-2 py-1">
        <MiniTopology topology={flow.summary?.topology} />
      </div>

      {/* 바디 */}
      <div className="px-3 pb-2 pt-2.5">
        <h3 className="mb-0.5 truncate text-xs font-semibold">{flow.flowName}</h3>
        <p className="mb-2 line-clamp-1 text-[10px] text-muted-foreground">
          {flow.flowDescription || "설명 없음"}
        </p>

        {/* 노드 타입 칩 */}
        {chips.length > 0 && (
          <div className="flex flex-wrap gap-1">
            {chips.map(({ type, count, label, colors }) => (
              <span
                key={type}
                className={`inline-flex items-center gap-0.5 rounded px-1.5 py-0.5 text-[9px] font-semibold ${colors.text} ${colors.bg}`}
              >
                {label} {count}
              </span>
            ))}
          </div>
        )}
      </div>

      {/* 푸터 */}
      <div className="flex items-center justify-between border-t px-3 py-1.5">
        <span className="text-[10px] text-muted-foreground">{relativeTime(flow.updatedAt)}</span>
        <div className="flex gap-0.5">
          <button
            className="flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground"
            title="편집"
            onClick={(e) => { e.stopPropagation(); onOpen(); }}
          >
            <Pencil className="h-3 w-3" />
          </button>
          <button
            className="flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground"
            title="복사"
            onClick={(e) => { e.stopPropagation(); onCopy(); }}
          >
            <Copy className="h-3 w-3" />
          </button>
          <button
            className="flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive"
            title="삭제"
            onClick={(e) => { e.stopPropagation(); onDelete(); }}
          >
            <Trash2 className="h-3 w-3" />
          </button>
        </div>
      </div>
    </div>
  );
}

export default function DataFlowList({ onLoadFlow }: DataFlowListProps) {
  const [flows, setFlows] = useState<NodeFlow[]>([]);
  const [loading, setLoading] = useState(true);
  const [searchTerm, setSearchTerm] = useState("");
  const [viewMode, setViewMode] = useState<"grid" | "list">("grid");
  const [showDeleteModal, setShowDeleteModal] = useState(false);
  const [selectedFlow, setSelectedFlow] = useState<NodeFlow | null>(null);

  const loadFlows = useCallback(async () => {
    try {
      setLoading(true);
      const response = await apiClient.get("/dataflow/node-flows");
      if (response.data.success) {
        setFlows(response.data.data);
      } else {
        throw new Error(response.data.message || "플로우 목록 조회 실패");
      }
    } catch (error) {
      console.error("플로우 목록 조회 실패", error);
      showErrorToast("플로우 목록을 불러오는 데 실패했어요", error, {
        guidance: "네트워크 연결을 확인해 주세요.",
      });
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => { loadFlows(); }, [loadFlows]);

  const handleDelete = (flow: NodeFlow) => { setSelectedFlow(flow); setShowDeleteModal(true); };

  const handleCopy = async (flow: NodeFlow) => {
    try {
      setLoading(true);
      const response = await apiClient.get(`/dataflow/node-flows/${flow.flowId}`);
      if (!response.data.success) throw new Error(response.data.message || "플로우 조회 실패");
      const copyResponse = await apiClient.post("/dataflow/node-flows", {
        flowName: `${flow.flowName} (복사본)`,
        flowDescription: flow.flowDescription,
        flowData: response.data.data.flowData,
      });
      if (copyResponse.data.success) {
        toast.success("플로우를 복사했어요");
        await loadFlows();
      } else {
        throw new Error(copyResponse.data.message || "플로우 복사 실패");
      }
    } catch (error) {
      console.error("플로우 복사 실패:", error);
      showErrorToast("플로우 복사에 실패했어요", error, { guidance: "잠시 후 다시 시도해 주세요." });
    } finally {
      setLoading(false);
    }
  };

  const handleConfirmDelete = async () => {
    if (!selectedFlow) return;
    try {
      setLoading(true);
      const response = await apiClient.delete(`/dataflow/node-flows/${selectedFlow.flowId}`);
      if (response.data.success) {
        toast.success(`"${selectedFlow.flowName}" 플로우를 삭제했어요`);
        await loadFlows();
      } else {
        throw new Error(response.data.message || "플로우 삭제 실패");
      }
    } catch (error) {
      console.error("플로우 삭제 실패:", error);
      showErrorToast("플로우 삭제에 실패했어요", error, { guidance: "잠시 후 다시 시도해 주세요." });
    } finally {
      setLoading(false);
      setShowDeleteModal(false);
      setSelectedFlow(null);
    }
  };

  const filteredFlows = useMemo(
    () =>
      flows.filter(
        (f) =>
          f.flowName.toLowerCase().includes(searchTerm.toLowerCase()) ||
          (f.flowDescription || "").toLowerCase().includes(searchTerm.toLowerCase()),
      ),
    [flows, searchTerm],
  );

  const stats = useMemo(() => {
    let totalNodes = 0;
    let totalEdges = 0;
    flows.forEach((f) => {
      totalNodes += f.summary?.nodeCount || 0;
      totalEdges += f.summary?.edgeCount || 0;
    });
    return { total: flows.length, totalNodes, totalEdges };
  }, [flows]);

  if (loading && flows.length === 0) {
    return (
      <div className="flex h-48 items-center justify-center">
        <Loader2 className="h-5 w-5 animate-spin text-muted-foreground" />
      </div>
    );
  }

  return (
    <div className="h-full overflow-y-auto">
      <div className="space-y-4 p-4 sm:p-5">
        {/* 헤더 */}
        <div className="flex items-center justify-between border-b pb-3">
          <div>
            <h1 className="text-lg font-bold tracking-tight">제어 관리</h1>
            <p className="mt-0.5 text-xs text-muted-foreground">노드 기반 데이터 플로우를 시각적으로 설계하고 관리해요</p>
          </div>
          <div className="flex gap-1.5">
            <Button variant="outline" size="sm" onClick={loadFlows} disabled={loading} className="h-8 gap-1 text-xs">
              <RefreshCw className={`h-3.5 w-3.5 ${loading ? "animate-spin" : ""}`} />
              새로고침
            </Button>
            <Button size="sm" onClick={() => onLoadFlow(null)} className="h-8 gap-1 text-xs">
              <Plus className="h-3.5 w-3.5" />
              새 플로우
            </Button>
          </div>
        </div>

        {/* 통계 + 검색 + 뷰 토글 */}
        <div className="flex flex-wrap items-center justify-between gap-2">
          <div className="flex items-center gap-4">
            <div className="flex items-center gap-3 text-[11px] text-muted-foreground">
              <span>전체 <strong className="font-semibold text-foreground">{stats.total}</strong></span>
              <span>노드 <strong className="font-semibold text-foreground">{stats.totalNodes}</strong></span>
              <span>연결 <strong className="font-semibold text-foreground">{stats.totalEdges}</strong></span>
            </div>
          </div>
          <div className="flex items-center gap-2">
            <div className="relative w-52">
              <Search className="absolute left-2.5 top-1/2 h-3.5 w-3.5 -translate-y-1/2 text-muted-foreground" />
              <Input
                placeholder="플로우 검색..."
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)}
                className="h-8 pl-8 text-xs"
              />
            </div>
            <div className="flex rounded-md border p-0.5">
              <button
                className={`flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium transition-colors ${
                  viewMode === "grid" ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"
                }`}
                onClick={() => setViewMode("grid")}
              >
                <LayoutGrid className="h-3 w-3" />
                그리드
              </button>
              <button
                className={`flex items-center gap-1 rounded px-2 py-1 text-[10px] font-medium transition-colors ${
                  viewMode === "list" ? "bg-primary/10 text-primary" : "text-muted-foreground hover:text-foreground"
                }`}
                onClick={() => setViewMode("list")}
              >
                <List className="h-3 w-3" />
                리스트
              </button>
            </div>
          </div>
        </div>

        {/* 컨텐츠 */}
        {filteredFlows.length === 0 ? (
          <div className="flex flex-col items-center justify-center rounded-lg border border-dashed py-16">
            <Network className="mb-3 h-6 w-6 text-muted-foreground" />
            <p className="text-sm font-medium">{searchTerm ? "검색 결과가 없어요" : "아직 플로우가 없어요"}</p>
            <p className="mt-1 text-xs text-muted-foreground">
              {searchTerm ? "다른 키워드로 검색해 보세요" : "노드를 연결해서 데이터 파이프라인을 만들어 보세요"}
            </p>
            {!searchTerm && (
              <Button size="sm" onClick={() => onLoadFlow(null)} className="mt-4 h-8 gap-1 text-xs">
                <Plus className="h-3.5 w-3.5" />
                첫 번째 플로우 만들기
              </Button>
            )}
          </div>
        ) : viewMode === "grid" ? (
          <div className="grid grid-cols-1 gap-3 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4">
            {filteredFlows.map((flow) => (
              <FlowCard
                key={flow.flowId}
                flow={flow}
                onOpen={() => onLoadFlow(flow.flowId)}
                onCopy={() => handleCopy(flow)}
                onDelete={() => handleDelete(flow)}
              />
            ))}
            {/* 새 플로우 카드 */}
            <div
              className="flex cursor-pointer flex-col items-center justify-center rounded-lg border border-dashed py-10 transition-all hover:border-primary/40 hover:bg-primary/5"
              onClick={() => onLoadFlow(null)}
            >
              <div className="mb-2 flex h-8 w-8 items-center justify-center rounded-lg bg-muted">
                <Plus className="h-4 w-4 text-muted-foreground" />
              </div>
              <span className="text-xs font-medium text-muted-foreground">새 플로우</span>
            </div>
          </div>
        ) : (
          /* 리스트 뷰 */
          <div className="space-y-1.5">
            {filteredFlows.map((flow) => (
              <div
                key={flow.flowId}
                className="group flex cursor-pointer items-center gap-3 rounded-lg border bg-card px-3 py-2.5 transition-all hover:shadow-sm hover:border-primary/30"
                onClick={() => onLoadFlow(flow.flowId)}
              >
                <div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-md bg-muted">
                  <Network className="h-4 w-4 text-muted-foreground" />
                </div>
                <div className="min-w-0 flex-1">
                  <h3 className="truncate text-xs font-semibold">{flow.flowName}</h3>
                  <p className="truncate text-[10px] text-muted-foreground">{flow.flowDescription || "설명 없음"}</p>
                </div>
                <div className="hidden items-center gap-1 lg:flex">
                  {Object.entries(flow.summary?.nodeTypes || {}).slice(0, 3).map(([type, count]) => {
                    const colors = getNodeCategoryColor(type);
                    return (
                      <span key={type} className={`inline-flex items-center gap-0.5 rounded px-1.5 py-0.5 text-[9px] font-semibold ${colors.text} ${colors.bg}`}>
                        {getNodeLabel(type)} {count}
                      </span>
                    );
                  })}
                </div>
                <span className="hidden text-[10px] text-muted-foreground sm:block">{relativeTime(flow.updatedAt)}</span>
                <div className="flex gap-0.5" onClick={(e) => e.stopPropagation()}>
                  <button className="flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground" title="복사" onClick={() => handleCopy(flow)}>
                    <Copy className="h-3 w-3" />
                  </button>
                  <button className="flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:bg-destructive/10 hover:text-destructive" title="삭제" onClick={() => handleDelete(flow)}>
                    <Trash2 className="h-3 w-3" />
                  </button>
                </div>
              </div>
            ))}
          </div>
        )}

        {/* 삭제 확인 모달 */}
        <Dialog open={showDeleteModal} onOpenChange={setShowDeleteModal}>
          <DialogContent className="max-w-[95vw] sm:max-w-[420px]">
            <DialogHeader>
              <DialogTitle className="text-sm">플로우 삭제</DialogTitle>
              <DialogDescription className="text-xs">
                &ldquo;{selectedFlow?.flowName}&rdquo; 플로우가 완전히 삭제됩니다. 이 작업은 되돌릴 수 없습니다.
              </DialogDescription>
            </DialogHeader>
            <DialogFooter className="gap-2 sm:gap-0">
              <Button variant="outline" size="sm" onClick={() => setShowDeleteModal(false)} className="h-8 text-xs">취소</Button>
              <Button variant="destructive" size="sm" onClick={handleConfirmDelete} disabled={loading} className="h-8 text-xs">
                {loading ? "삭제 중..." : "삭제"}
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>
      </div>
    </div>
  );
}
