"use client";

import React, { useState, useEffect, useCallback } from "react";
import {
  ReactFlow,
  Controls,
  Background,
  BackgroundVariant,
  Node,
  Edge,
  useNodesState,
  useEdgesState,
  MarkerType,
} from "@xyflow/react";
import "@xyflow/react/dist/style.css";

import { ScreenDefinition } from "@/types/screen";
import { ScreenNode, TableNode, ScreenNodeData, TableNodeData } from "./ScreenNode";
import {
  getFieldJoins,
  getDataFlows,
  getTableRelations,
  getMultipleScreenLayoutSummary,
  ScreenLayoutSummary,
} from "@/lib/api/screenGroup";
import { getTableColumns, ColumnTypeInfo } from "@/lib/api/tableManagement";

// 노드 타입 등록
const nodeTypes = {
  screenNode: ScreenNode,
  tableNode: TableNode,
};

// 레이아웃 상수
const SCREEN_Y = 50; // 화면 노드 Y 위치 (상단)
const TABLE_Y = 400; // 테이블 노드 Y 위치 (하단)
const NODE_WIDTH = 260; // 노드 너비 (조금 넓게)
const NODE_GAP = 40; // 노드 간격

interface ScreenRelationFlowProps {
  screen: ScreenDefinition | null;
}

// 노드 타입 (Record<string, unknown> 확장)
type ScreenNodeType = Node<ScreenNodeData & Record<string, unknown>>;
type TableNodeType = Node<TableNodeData & Record<string, unknown>>;
type AllNodeType = ScreenNodeType | TableNodeType;

export function ScreenRelationFlow({ screen }: ScreenRelationFlowProps) {
  const [nodes, setNodes, onNodesChange] = useNodesState<AllNodeType>([]);
  const [edges, setEdges, onEdgesChange] = useEdgesState<Edge>([]);
  const [loading, setLoading] = useState(false);
  const [tableColumns, setTableColumns] = useState<Record<string, ColumnTypeInfo[]>>({});

  // 테이블 컬럼 정보 로드
  const loadTableColumns = useCallback(
    async (tableName: string): Promise<ColumnTypeInfo[]> => {
      if (!tableName) return [];
      if (tableColumns[tableName]) return tableColumns[tableName];

      try {
        const response = await getTableColumns(tableName);
        if (response.success && response.data && response.data.columns) {
          const columns = response.data.columns;
          setTableColumns((prev) => ({ ...prev, [tableName]: columns }));
          return columns;
        }
      } catch (error) {
        console.error(`테이블 ${tableName} 컬럼 로드 실패:`, error);
      }
      return [];
    },
    [tableColumns]
  );

  // 데이터 로드 및 노드/엣지 생성
  useEffect(() => {
    if (!screen) {
      setNodes([]);
      setEdges([]);
      return;
    }

    const loadRelations = async () => {
      setLoading(true);

      try {
        // 관계 데이터 로드
        const [joinsRes, flowsRes, relationsRes] = await Promise.all([
          getFieldJoins(screen.screenId).catch(() => ({ success: false, data: [] })),
          getDataFlows().catch(() => ({ success: false, data: [] })),
          getTableRelations({ screen_id: screen.screenId }).catch(() => ({ success: false, data: [] })),
        ]);

        const joins = joinsRes.success ? joinsRes.data || [] : [];
        const flows = flowsRes.success ? flowsRes.data || [] : [];
        const relations = relationsRes.success ? relationsRes.data || [] : [];

        // ========== 화면 목록 수집 ==========
        const screenList: ScreenDefinition[] = [screen];

        // 데이터 흐름에서 연결된 화면들 추가
        flows.forEach((flow: any) => {
          if (flow.source_screen_id === screen.screenId && flow.target_screen_id) {
            const exists = screenList.some((s) => s.screenId === flow.target_screen_id);
            if (!exists) {
              screenList.push({
                screenId: flow.target_screen_id,
                screenName: flow.target_screen_name || `화면 ${flow.target_screen_id}`,
                screenCode: "",
                tableName: "",
                companyCode: screen.companyCode,
                isActive: "Y",
                createdDate: new Date(),
                updatedDate: new Date(),
              } as ScreenDefinition);
            }
          }
        });

        // 화면 레이아웃 요약 정보 로드
        const screenIds = screenList.map((s) => s.screenId);
        let layoutSummaries: Record<number, ScreenLayoutSummary> = {};
        try {
          const layoutRes = await getMultipleScreenLayoutSummary(screenIds);
          if (layoutRes.success && layoutRes.data) {
            // API 응답이 Record 형태 (screenId -> summary)
            layoutSummaries = layoutRes.data as Record<number, ScreenLayoutSummary>;
          }
        } catch (e) {
          console.error("레이아웃 요약 로드 실패:", e);
        }

        // ========== 상단: 화면 노드들 ==========
        const screenNodes: ScreenNodeType[] = [];
        const screenStartX = 50;

        screenList.forEach((scr, idx) => {
          const isMain = scr.screenId === screen.screenId;
          const summary = layoutSummaries[scr.screenId];

          screenNodes.push({
            id: `screen-${scr.screenId}`,
            type: "screenNode",
            position: { x: screenStartX + idx * (NODE_WIDTH + NODE_GAP), y: SCREEN_Y },
            data: {
              label: scr.screenName,
              subLabel: isMain ? "메인 화면" : "연결 화면",
              type: "screen",
              isMain,
              tableName: scr.tableName,
              layoutSummary: summary,
            },
          });
        });

        // ========== 하단: 테이블 노드들 ==========
        const tableNodes: TableNodeType[] = [];
        const tableSet = new Set<string>();

        // 메인 화면의 테이블 추가
        if (screen.tableName) {
          tableSet.add(screen.tableName);
        }

        // 조인된 테이블들 추가
        joins.forEach((join: any) => {
          if (join.save_table) tableSet.add(join.save_table);
          if (join.join_table) tableSet.add(join.join_table);
        });

        // 테이블 관계에서 추가
        relations.forEach((rel: any) => {
          if (rel.table_name) tableSet.add(rel.table_name);
        });

        // 테이블 노드 배치 (하단, 가로 배치)
        const tableList = Array.from(tableSet);
        const tableStartX = 50;

        for (let idx = 0; idx < tableList.length; idx++) {
          const tableName = tableList[idx];
          const isMainTable = tableName === screen.tableName;

          // 컬럼 정보 로드
          let columns: ColumnTypeInfo[] = [];
          try {
            columns = await loadTableColumns(tableName);
          } catch (e) {
            // ignore
          }

          // 컬럼 정보를 PK/FK 표시와 함께 변환
          const formattedColumns = columns.slice(0, 8).map((col) => ({
            name: col.displayName || col.columnName || "",
            type: col.dataType || "",
            isPrimaryKey: col.isPrimaryKey || col.columnName === "id",
            isForeignKey: !!col.referenceTable || (col.columnName?.includes("_id") && col.columnName !== "id"),
          }));

          tableNodes.push({
            id: `table-${tableName}`,
            type: "tableNode",
            position: { x: tableStartX + idx * (NODE_WIDTH + NODE_GAP), y: TABLE_Y },
            data: {
              label: tableName,
              subLabel: isMainTable ? "메인 테이블" : "조인 테이블",
              isMain: isMainTable,
              columns: formattedColumns,
            },
          });
        }

        // ========== 엣지: 연결선 생성 ==========
        const newEdges: Edge[] = [];

        // 메인 화면 → 메인 테이블 연결 (양방향 CRUD)
        if (screen.tableName) {
          newEdges.push({
            id: `edge-main`,
            source: `screen-${screen.screenId}`,
            target: `table-${screen.tableName}`,
            sourceHandle: "bottom",
            targetHandle: "top",
            type: "smoothstep",
            animated: true,
            style: { stroke: "#3b82f6", strokeWidth: 2 },
          });
        }

        // 조인 관계 엣지 (테이블 간 - 1:N 관계 표시)
        joins.forEach((join: any, idx: number) => {
          if (join.save_table && join.join_table && join.save_table !== join.join_table) {
            newEdges.push({
              id: `edge-join-${idx}`,
              source: `table-${join.save_table}`,
              target: `table-${join.join_table}`,
              sourceHandle: "right",
              targetHandle: "left",
              type: "smoothstep",
              label: "1:N 관계",
              labelStyle: { fontSize: 10, fill: "#6366f1", fontWeight: 500 },
              labelBgStyle: { fill: "white", stroke: "#e2e8f0", strokeWidth: 1 },
              labelBgPadding: [4, 2] as [number, number],
              markerEnd: { type: MarkerType.ArrowClosed, color: "#6366f1" },
              style: { stroke: "#6366f1", strokeWidth: 1.5, strokeDasharray: "5,5" },
            });
          }
        });

        // 테이블 관계 엣지 (추가 관계)
        relations.forEach((rel: any, idx: number) => {
          if (rel.table_name && rel.table_name !== screen.tableName) {
            // 화면 → 연결 테이블
            const edgeExists = newEdges.some(
              (e) => e.source === `screen-${screen.screenId}` && e.target === `table-${rel.table_name}`
            );
            if (!edgeExists) {
              newEdges.push({
                id: `edge-rel-${idx}`,
                source: `screen-${screen.screenId}`,
                target: `table-${rel.table_name}`,
                sourceHandle: "bottom",
                targetHandle: "top",
                type: "smoothstep",
                label: rel.relation_type === "join" ? "조인" : rel.crud_operations || "",
                labelStyle: { fontSize: 9, fill: "#10b981" },
                labelBgStyle: { fill: "white", stroke: "#e2e8f0", strokeWidth: 1 },
                labelBgPadding: [3, 2] as [number, number],
                style: { stroke: "#10b981", strokeWidth: 1.5 },
              });
            }
          }
        });

        // 데이터 흐름 엣지 (화면 간)
        flows
          .filter((flow: any) => flow.source_screen_id === screen.screenId)
          .forEach((flow: any, idx: number) => {
            if (flow.target_screen_id) {
              newEdges.push({
                id: `edge-flow-${idx}`,
                source: `screen-${screen.screenId}`,
                target: `screen-${flow.target_screen_id}`,
                sourceHandle: "right",
                targetHandle: "left",
                type: "smoothstep",
                animated: true,
                label: flow.flow_label || flow.flow_type || "이동",
                labelStyle: { fontSize: 10, fill: "#8b5cf6", fontWeight: 500 },
                labelBgStyle: { fill: "white", stroke: "#e2e8f0", strokeWidth: 1 },
                labelBgPadding: [4, 2] as [number, number],
                markerEnd: { type: MarkerType.ArrowClosed, color: "#8b5cf6" },
                style: { stroke: "#8b5cf6", strokeWidth: 2 },
              });
            }
          });

        // 최종 노드 배열 합치기
        const allNodes: AllNodeType[] = [...screenNodes, ...tableNodes];

        // 테이블이 없으면 안내 노드 추가
        if (tableNodes.length === 0) {
          allNodes.push({
            id: "hint-table",
            type: "tableNode",
            position: { x: 50, y: TABLE_Y },
            data: {
              label: "연결된 테이블 없음",
              subLabel: "화면에 테이블을 설정하세요",
              isMain: false,
              columns: [],
            },
          });
        }

        setNodes(allNodes);
        setEdges(newEdges);
      } catch (error) {
        console.error("관계 데이터 로드 실패:", error);
      } finally {
        setLoading(false);
      }
    };

    loadRelations();
  }, [screen, setNodes, setEdges, loadTableColumns]);

  if (!screen) {
    return (
      <div className="flex h-full items-center justify-center text-muted-foreground">
        <div className="text-center">
          <p className="text-sm">화면을 선택하면</p>
          <p className="text-sm">데이터 관계가 시각화됩니다</p>
        </div>
      </div>
    );
  }

  if (loading) {
    return (
      <div className="flex h-full items-center justify-center">
        <div className="text-sm text-muted-foreground">로딩 중...</div>
      </div>
    );
  }

  return (
    <div className="h-full w-full">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        onNodesChange={onNodesChange}
        onEdgesChange={onEdgesChange}
        nodeTypes={nodeTypes}
        fitView
        fitViewOptions={{ padding: 0.2 }}
        minZoom={0.3}
        maxZoom={1.5}
        proOptions={{ hideAttribution: true }}
      >
        <Background variant={BackgroundVariant.Dots} gap={20} size={1} color="#e2e8f0" />
        <Controls position="bottom-right" />
      </ReactFlow>
    </div>
  );
}
