"use client";

import React, { useState, useCallback, useEffect, useRef } from "react";
import toast from "react-hot-toast";
import {
  ReactFlow,
  Node,
  Edge,
  Controls,
  Background,
  MiniMap,
  useNodesState,
  useEdgesState,
  addEdge,
  Connection,
} from "@xyflow/react";
import "@xyflow/react/dist/style.css";
import { ScreenNode } from "./ScreenNode";
import { CustomEdge } from "./CustomEdge";
import { ScreenSelector } from "./ScreenSelector";
import { ConnectionSetupModal } from "./ConnectionSetupModal";
import { DataFlowAPI, ScreenDefinition, ColumnInfo, ScreenWithFields } from "@/lib/api/dataflow";

// 노드 및 엣지 타입 정의
const nodeTypes = {
  screenNode: ScreenNode,
};

const edgeTypes = {
  customEdge: CustomEdge,
};

interface DataFlowDesignerProps {
  companyCode: string;
  onSave?: (relationships: any[]) => void;
}

export const DataFlowDesigner: React.FC<DataFlowDesignerProps> = ({ companyCode, onSave }) => {
  const [nodes, setNodes, onNodesChange] = useNodesState([]);
  const [edges, setEdges, onEdgesChange] = useEdgesState([]);
  const [selectedFields, setSelectedFields] = useState<{
    [screenId: string]: string[];
  }>({});
  const [selectionOrder, setSelectionOrder] = useState<string[]>([]);
  const [loadingScreens, setLoadingScreens] = useState<Set<number>>(new Set());
  const [pendingConnection, setPendingConnection] = useState<{
    fromNode: { id: string; screenName: string; tableName: string };
    toNode: { id: string; screenName: string; tableName: string };
    fromField?: string;
    toField?: string;
    selectedFieldsData?: {
      [screenId: string]: {
        screenName: string;
        fields: string[];
      };
    };
  } | null>(null);
  const [isOverNodeScrollArea, setIsOverNodeScrollArea] = useState(false);
  const toastShownRef = useRef(false);

  // 빈 onConnect 함수 (드래그 연결 비활성화)
  const onConnect = useCallback(() => {
    // 드래그로 연결하는 것을 방지
    return;
  }, []);

  // 필드 클릭 처리 (토글 방식, 최대 2개 화면만 허용)
  const handleFieldClick = useCallback((screenId: string, fieldName: string) => {
    setSelectedFields((prev) => {
      const currentFields = prev[screenId] || [];
      const isSelected = currentFields.includes(fieldName);
      const selectedScreens = Object.keys(prev).filter((id) => prev[id] && prev[id].length > 0);

      if (isSelected) {
        // 선택 해제
        const newFields = currentFields.filter((field) => field !== fieldName);
        if (newFields.length === 0) {
          const { [screenId]: _, ...rest } = prev;
          // 선택 순서에서도 제거 (다음 렌더링에서)
          setTimeout(() => {
            setSelectionOrder((order) => order.filter((id) => id !== screenId));
          }, 0);
          return rest;
        }
        return { ...prev, [screenId]: newFields };
      } else {
        // 선택 추가 - 새로운 화면이고 이미 2개 화면이 선택되어 있으면 거부
        if (!prev[screenId] && selectedScreens.length >= 2) {
          // 토스트 중복 방지를 위한 ref 사용
          if (!toastShownRef.current) {
            toastShownRef.current = true;
            setTimeout(() => {
              toast.error("최대 2개의 화면에서만 필드를 선택할 수 있습니다.", {
                duration: 3000,
                position: "top-center",
              });
              // 3초 후 플래그 리셋
              setTimeout(() => {
                toastShownRef.current = false;
              }, 3000);
            }, 0);
          }
          return prev;
        }

        // 새로운 화면이면 선택 순서에 추가, 기존 화면이면 맨 뒤로 이동 (다음 렌더링에서)
        setTimeout(() => {
          setSelectionOrder((order) => {
            // 기존에 있던 화면이면 제거 후 맨 뒤에 추가 (순서 갱신)
            const filteredOrder = order.filter((id) => id !== screenId);
            return [...filteredOrder, screenId];
          });
        }, 0);

        return { ...prev, [screenId]: [...currentFields, fieldName] };
      }
    });
  }, []);

  // 선택된 필드가 변경될 때마다 기존 노드들 업데이트 및 selectionOrder 정리
  useEffect(() => {
    setNodes((prevNodes) =>
      prevNodes.map((node) => ({
        ...node,
        data: {
          ...node.data,
          selectedFields: selectedFields[node.data.screen.screenId] || [],
        },
      })),
    );

    // selectionOrder에서 선택되지 않은 화면들 제거
    const activeScreens = Object.keys(selectedFields).filter(
      (screenId) => selectedFields[screenId] && selectedFields[screenId].length > 0,
    );
    setSelectionOrder((prev) => prev.filter((screenId) => activeScreens.includes(screenId)));
  }, [selectedFields, setNodes]);

  // 연결 가능한 상태인지 확인
  const canCreateConnection = () => {
    const selectedScreens = Object.keys(selectedFields).filter(
      (screenId) => selectedFields[screenId] && selectedFields[screenId].length > 0,
    );

    // 최소 2개의 서로 다른 테이블에서 필드가 선택되어야 함
    return selectedScreens.length >= 2;
  };

  // 필드 연결 설정 모달 열기
  const openConnectionModal = () => {
    const selectedScreens = Object.keys(selectedFields).filter(
      (screenId) => selectedFields[screenId] && selectedFields[screenId].length > 0,
    );

    if (selectedScreens.length < 2) return;

    // 선택 순서에 따라 첫 번째와 두 번째 화면 설정
    const orderedScreens = selectionOrder.filter((id) => selectedScreens.includes(id));
    const firstScreenId = orderedScreens[0];
    const secondScreenId = orderedScreens[1];
    const firstNode = nodes.find((node) => node.data.screen.screenId === firstScreenId);
    const secondNode = nodes.find((node) => node.data.screen.screenId === secondScreenId);

    if (!firstNode || !secondNode) return;

    setPendingConnection({
      fromNode: {
        id: firstNode.id,
        screenName: firstNode.data.screen.screenName,
        tableName: firstNode.data.screen.tableName,
      },
      toNode: {
        id: secondNode.id,
        screenName: secondNode.data.screen.screenName,
        tableName: secondNode.data.screen.tableName,
      },
      // 선택된 모든 필드 정보를 선택 순서대로 전달
      selectedFieldsData: (() => {
        const orderedData: { [key: string]: { screenName: string; fields: string[] } } = {};
        // selectionOrder 순서대로 데이터 구성 (첫 번째 선택이 먼저)
        orderedScreens.forEach((screenId) => {
          const node = nodes.find((n) => n.data.screen.screenId === screenId);
          if (node && selectedFields[screenId]) {
            orderedData[screenId] = {
              screenName: node.data.screen.screenName,
              fields: selectedFields[screenId],
            };
          }
        });
        return orderedData;
      })(),
      // 명시적인 순서 정보 전달
      orderedScreenIds: orderedScreens,
    });
  };

  // 실제 화면 노드 추가
  const addScreenNode = useCallback(
    async (screen: ScreenDefinition) => {
      try {
        setLoadingScreens((prev) => new Set(prev).add(screen.screenId));

        // 테이블 컬럼 정보 조회
        const columns = await DataFlowAPI.getTableColumns(screen.tableName);

        const newNode: Node = {
          id: `screen-${screen.screenId}`,
          type: "screenNode",
          position: { x: Math.random() * 300, y: Math.random() * 200 },
          data: {
            screen: {
              screenId: screen.screenId.toString(),
              screenName: screen.screenName,
              screenCode: screen.screenCode,
              tableName: screen.tableName,
              fields: columns.map((col) => ({
                name: col.columnName || "unknown",
                type: col.dataType || col.dbType || "UNKNOWN",
                description:
                  col.columnLabel || col.displayName || col.description || col.columnName || "No description",
              })),
            },
            onFieldClick: handleFieldClick,
            onScrollAreaEnter: () => setIsOverNodeScrollArea(true),
            onScrollAreaLeave: () => setIsOverNodeScrollArea(false),
            selectedFields: selectedFields[screen.screenId] || [],
          },
        };

        setNodes((nds) => nds.concat(newNode));
      } catch (error) {
        console.error("화면 노드 추가 실패:", error);
        alert("화면 정보를 불러오는데 실패했습니다.");
      } finally {
        setLoadingScreens((prev) => {
          const newSet = new Set(prev);
          newSet.delete(screen.screenId);
          return newSet;
        });
      }
    },
    [handleFieldClick, setNodes],
  );

  // 샘플 화면 노드 추가 (개발용)
  const addSampleNode = useCallback(() => {
    const newNode: Node = {
      id: `sample-${Date.now()}`,
      type: "screenNode",
      position: { x: Math.random() * 300, y: Math.random() * 200 },
      data: {
        screen: {
          screenId: `sample-${Date.now()}`,
          screenName: `샘플 화면 ${nodes.length + 1}`,
          screenCode: `SAMPLE${nodes.length + 1}`,
          tableName: `sample_table_${nodes.length + 1}`,
          fields: [
            { name: "id", type: "INTEGER", description: "고유 식별자" },
            { name: "name", type: "VARCHAR(100)", description: "이름" },
            { name: "code", type: "VARCHAR(50)", description: "코드" },
            { name: "created_date", type: "TIMESTAMP", description: "생성일시" },
          ],
        },
        onFieldClick: handleFieldClick,
      },
    };

    setNodes((nds) => nds.concat(newNode));
  }, [nodes.length, handleFieldClick, setNodes]);

  // 노드 전체 삭제
  const clearNodes = useCallback(() => {
    setNodes([]);
    setEdges([]);
  }, [setNodes, setEdges]);

  // 현재 추가된 화면 ID 목록 가져오기
  const getSelectedScreenIds = useCallback(() => {
    return nodes
      .filter((node) => node.id.startsWith("screen-"))
      .map((node) => parseInt(node.id.replace("screen-", "")))
      .filter((id) => !isNaN(id));
  }, [nodes]);

  // 연결 설정 확인
  const handleConfirmConnection = useCallback(
    (config: any) => {
      if (!pendingConnection) return;

      const newEdge = {
        id: `edge-${Date.now()}`,
        source: pendingConnection.fromNode.id,
        target: pendingConnection.toNode.id,
        type: "customEdge",
        data: {
          relationshipType: config.relationshipType,
          connectionType: config.connectionType,
          label: config.relationshipName,
        },
      };

      setEdges((eds) => [...eds, newEdge]);
      setPendingConnection(null);

      // TODO: 백엔드 API 호출하여 관계 저장
      console.log("연결 설정:", config);
    },
    [pendingConnection, setEdges],
  );

  // 연결 설정 취소
  const handleCancelConnection = useCallback(() => {
    setPendingConnection(null);
  }, []);

  return (
    <div className="data-flow-designer h-screen bg-gray-100">
      <div className="flex h-full">
        {/* 사이드바 */}
        <div className="w-80 border-r border-gray-200 bg-white shadow-lg">
          <div className="p-6">
            <h2 className="mb-6 text-xl font-bold text-gray-800">데이터 흐름 관리</h2>

            {/* 회사 정보 */}
            <div className="mb-6 rounded-lg bg-blue-50 p-4">
              <div className="text-sm font-medium text-blue-600">회사 코드</div>
              <div className="text-lg font-bold text-blue-800">{companyCode}</div>
            </div>

            {/* 화면 선택기 */}
            <ScreenSelector
              companyCode={companyCode}
              onScreenAdd={addScreenNode}
              selectedScreens={getSelectedScreenIds()}
            />

            {/* 컨트롤 버튼들 */}
            <div className="space-y-3">
              <button
                onClick={addSampleNode}
                className="w-full rounded-lg bg-gray-500 p-3 font-medium text-white transition-colors hover:bg-gray-600"
              >
                + 샘플 화면 추가 (개발용)
              </button>

              <button
                onClick={clearNodes}
                className="w-full rounded-lg bg-red-500 p-3 font-medium text-white transition-colors hover:bg-red-600"
              >
                전체 삭제
              </button>

              <button
                onClick={() => onSave && onSave([])}
                className="w-full rounded-lg bg-green-500 p-3 font-medium text-white transition-colors hover:bg-green-600"
              >
                저장
              </button>
            </div>

            {/* 통계 정보 */}
            <div className="mt-6 rounded-lg bg-gray-50 p-4">
              <div className="mb-2 text-sm font-semibold text-gray-700">통계</div>
              <div className="space-y-1 text-sm text-gray-600">
                <div className="flex justify-between">
                  <span>화면 노드:</span>
                  <span className="font-medium">{nodes.length}개</span>
                </div>
                <div className="flex justify-between">
                  <span>연결:</span>
                  <span className="font-medium">{edges.length}개</span>
                </div>
              </div>
            </div>

            {/* 선택된 필드 정보 */}
            {Object.keys(selectedFields).length > 0 && (
              <div className="mt-6 space-y-4">
                <div className="rounded-lg border border-blue-200 bg-blue-50 p-4">
                  <div className="mb-3 text-sm font-semibold text-blue-800">선택된 필드</div>
                  <div className="space-y-3">
                    {[...new Set(selectionOrder)]
                      .filter((screenId) => selectedFields[screenId] && selectedFields[screenId].length > 0)
                      .map((screenId, index, filteredOrder) => {
                        const fields = selectedFields[screenId];
                        const node = nodes.find((n) => n.data.screen.screenId === screenId);
                        const screenName = node?.data.screen.screenName || screenId;

                        return (
                          <div key={`selected-${screenId}-${index}`}>
                            <div className="w-full min-w-0 rounded-lg border border-blue-300 bg-white p-3">
                              <div className="mb-2 flex flex-wrap items-center gap-2">
                                <div className="flex-shrink-0 rounded bg-blue-600 px-2 py-1 text-xs font-medium text-white">
                                  {screenName}
                                </div>
                                <div className="flex-shrink-0 text-xs text-gray-500">ID: {screenId}</div>
                              </div>
                              <div className="flex w-full min-w-0 flex-wrap gap-1">
                                {fields.map((field, fieldIndex) => (
                                  <div
                                    key={`${screenId}-${field}-${fieldIndex}`}
                                    className="max-w-full truncate rounded-full border border-blue-200 bg-blue-100 px-2 py-1 text-xs text-blue-800"
                                    title={field}
                                  >
                                    {field}
                                  </div>
                                ))}
                              </div>
                            </div>
                            {/* 첫 번째 화면 다음에 화살표 표시 */}
                            {index === 0 && filteredOrder.length > 1 && (
                              <div className="flex justify-center py-2">
                                <div className="text-gray-400">↓</div>
                              </div>
                            )}
                          </div>
                        );
                      })}
                  </div>
                  <div className="mt-3 flex gap-2">
                    <button
                      onClick={openConnectionModal}
                      disabled={!canCreateConnection()}
                      className={`rounded px-3 py-1 text-xs font-medium transition-colors ${
                        canCreateConnection()
                          ? "bg-blue-600 text-white hover:bg-blue-700"
                          : "cursor-not-allowed bg-gray-300 text-gray-500"
                      }`}
                    >
                      필드 연결 설정
                    </button>
                    <button
                      onClick={() => {
                        setSelectedFields({});
                        setSelectionOrder([]);
                      }}
                      className="rounded bg-gray-200 px-3 py-1 text-xs font-medium text-gray-600 hover:bg-gray-300"
                    >
                      선택 초기화
                    </button>
                  </div>
                </div>
              </div>
            )}
          </div>
        </div>

        {/* React Flow 캔버스 */}
        <div className="relative flex-1">
          <ReactFlow
            nodes={nodes}
            edges={edges}
            onNodesChange={onNodesChange}
            onEdgesChange={onEdgesChange}
            onConnect={onConnect}
            nodeTypes={nodeTypes}
            edgeTypes={edgeTypes}
            fitView
            attributionPosition="bottom-left"
            panOnScroll={false}
            zoomOnScroll={true}
            zoomOnPinch={true}
            panOnDrag={true}
          >
            <Controls />
            <MiniMap
              nodeColor={(node) => {
                switch (node.type) {
                  case "screenNode":
                    return "#3B82F6";
                  default:
                    return "#6B7280";
                }
              }}
            />
            <Background variant="dots" gap={20} size={1} color="#E5E7EB" />
          </ReactFlow>

          {/* 안내 메시지 */}
          {nodes.length === 0 && (
            <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
              <div className="text-center text-gray-500">
                <div className="mb-2 text-2xl">📊</div>
                <div className="mb-1 text-lg font-medium">데이터 흐름 설계를 시작하세요</div>
                <div className="text-sm">왼쪽 사이드바에서 화면을 선택하여 추가하세요</div>
              </div>
            </div>
          )}
        </div>
      </div>

      {/* 연결 설정 모달 */}
      <ConnectionSetupModal
        isOpen={!!pendingConnection}
        connection={pendingConnection}
        onConfirm={handleConfirmConnection}
        onCancel={handleCancelConnection}
      />
    </div>
  );
};
