/**
 * 노드 에디터 상태 관리 스토어
 */

import { create } from "zustand";
import { Connection, Edge, EdgeChange, Node, NodeChange, addEdge, applyNodeChanges, applyEdgeChanges } from "reactflow";
import type { FlowNode, FlowEdge, NodeType, ValidationResult } from "@/types/node-editor";
import { createNodeFlow, updateNodeFlow } from "../api/nodeFlows";

// 🔥 Debounce 유틸리티
function debounce<T extends (...args: any[]) => any>(func: T, wait: number): (...args: Parameters<T>) => void {
  let timeout: NodeJS.Timeout | null = null;
  return function (...args: Parameters<T>) {
    if (timeout) clearTimeout(timeout);
    timeout = setTimeout(() => func(...args), wait);
  };
}

// 🔥 외부 커넥션 캐시 타입
interface ExternalConnectionCache {
  data: any[];
  timestamp: number;
}

// 🔥 히스토리 스냅샷 타입
interface HistorySnapshot {
  nodes: FlowNode[];
  edges: FlowEdge[];
}

interface FlowEditorState {
  // 노드 및 엣지
  nodes: FlowNode[];
  edges: FlowEdge[];

  // 🔥 히스토리 관리
  history: HistorySnapshot[];
  historyIndex: number;
  maxHistorySize: number;
  isRestoringHistory: boolean; // 🔥 히스토리 복원 중 플래그

  // 선택 상태
  selectedNodes: string[];
  selectedEdges: string[];

  // 플로우 메타데이터
  flowId: number | null;
  flowName: string;
  flowDescription: string;

  // UI 상태
  isSaving: boolean;
  showValidationPanel: boolean;
  showPropertiesPanel: boolean;

  // 검증 결과
  validationResult: ValidationResult | null;

  // 🔥 외부 커넥션 캐시 (전역 캐싱)
  externalConnectionsCache: ExternalConnectionCache | null;

  // ========================================================================
  // 🔥 히스토리 관리 (Undo/Redo)
  // ========================================================================

  saveToHistory: () => void;
  undo: () => void;
  redo: () => void;
  canUndo: () => boolean;
  canRedo: () => boolean;

  // ========================================================================
  // 노드 관리
  // ========================================================================

  setNodes: (nodes: FlowNode[]) => void;
  onNodesChange: (changes: NodeChange[]) => void;
  onNodeDragStart: () => void; // 노드 드래그 시작 시 히스토리 저장 (변경 전 상태)
  addNode: (node: FlowNode) => void;
  updateNode: (id: string, data: Partial<FlowNode["data"]>) => void;
  removeNode: (id: string) => void;
  removeNodes: (ids: string[]) => void;

  // ========================================================================
  // 🔥 외부 커넥션 캐시 관리
  // ========================================================================

  setExternalConnectionsCache: (data: any[]) => void;
  clearExternalConnectionsCache: () => void;
  getExternalConnectionsCache: () => any[] | null;

  // ========================================================================
  // 엣지 관리
  // ========================================================================

  setEdges: (edges: FlowEdge[]) => void;
  onEdgesChange: (changes: EdgeChange[]) => void;
  onConnect: (connection: Connection) => void;
  removeEdge: (id: string) => void;
  removeEdges: (ids: string[]) => void;

  // ========================================================================
  // 선택 관리
  // ========================================================================

  selectNode: (id: string, multi?: boolean) => void;
  selectNodes: (ids: string[]) => void;
  selectEdge: (id: string, multi?: boolean) => void;
  clearSelection: () => void;

  // ========================================================================
  // 플로우 관리
  // ========================================================================

  loadFlow: (id: number, name: string, description: string, nodes: FlowNode[], edges: FlowEdge[]) => void;
  clearFlow: () => void;
  setFlowName: (name: string) => void;
  setFlowDescription: (description: string) => void;
  saveFlow: () => Promise<{ success: boolean; flowId?: number; message?: string }>;
  exportFlow: () => string;

  // ========================================================================
  // 검증
  // ========================================================================

  validateFlow: () => ValidationResult;
  setValidationResult: (result: ValidationResult | null) => void;

  // ========================================================================
  // UI 상태
  // ========================================================================

  setIsSaving: (value: boolean) => void;
  setShowValidationPanel: (value: boolean) => void;
  setShowPropertiesPanel: (value: boolean) => void;

  // ========================================================================
  // 유틸리티
  // ========================================================================

  getNodeById: (id: string) => FlowNode | undefined;
  getEdgeById: (id: string) => FlowEdge | undefined;
  getConnectedNodes: (nodeId: string) => { incoming: FlowNode[]; outgoing: FlowNode[] };
}

// 🔥 Debounced 히스토리 저장 함수 (스토어 외부에 생성)
let debouncedSaveToHistory: (() => void) | null = null;

export const useFlowEditorStore = create<FlowEditorState>((set, get) => {
  // 🔥 Debounced 히스토리 저장 함수 초기화
  if (!debouncedSaveToHistory) {
    debouncedSaveToHistory = debounce(() => {
      get().saveToHistory();
    }, 500); // 500ms 지연
  }

  return {
    // 초기 상태
    nodes: [],
    edges: [],
    history: [{ nodes: [], edges: [] }], // 초기 빈 상태를 히스토리에 저장
    historyIndex: 0,
    maxHistorySize: 50,
    isRestoringHistory: false, // 🔥 히스토리 복원 중 플래그 초기화
    selectedNodes: [],
    selectedEdges: [],
    flowId: null,
    flowName: "새 제어 플로우",
    flowDescription: "",
    isSaving: false,
    showValidationPanel: false,
    showPropertiesPanel: true,
    validationResult: null,
    externalConnectionsCache: null, // 🔥 캐시 초기화

    // ========================================================================
    // 🔥 히스토리 관리 (Undo/Redo)
    // ========================================================================

    saveToHistory: () => {
      const { nodes, edges, history, historyIndex, maxHistorySize } = get();

      // 현재 상태를 스냅샷으로 저장
      const snapshot: HistorySnapshot = {
        nodes: JSON.parse(JSON.stringify(nodes)),
        edges: JSON.parse(JSON.stringify(edges)),
      };

      // historyIndex 이후의 히스토리 제거 (새로운 변경이 발생했으므로)
      const newHistory = history.slice(0, historyIndex + 1);
      newHistory.push(snapshot);

      // 최대 크기 제한
      if (newHistory.length > maxHistorySize) {
        newHistory.shift();
      }

      console.log("📸 히스토리 저장:", {
        노드수: nodes.length,
        엣지수: edges.length,
        히스토리크기: newHistory.length,
        현재인덱스: newHistory.length - 1,
      });

      set({
        history: newHistory,
        historyIndex: newHistory.length - 1,
      });
    },

    undo: () => {
      const { history, historyIndex } = get();

      console.log("⏪ Undo 시도:", { historyIndex, historyLength: history.length });

      if (historyIndex > 0) {
        const newIndex = historyIndex - 1;
        const snapshot = history[newIndex];

        console.log("✅ Undo 실행:", {
          이전인덱스: historyIndex,
          새인덱스: newIndex,
          노드수: snapshot.nodes.length,
          엣지수: snapshot.edges.length,
        });

        // 🔥 히스토리 복원 중 플래그 설정
        set({ isRestoringHistory: true });

        // 노드와 엣지 복원
        set({
          nodes: JSON.parse(JSON.stringify(snapshot.nodes)),
          edges: JSON.parse(JSON.stringify(snapshot.edges)),
          historyIndex: newIndex,
        });

        // 🔥 다음 틱에서 플래그 해제 (ReactFlow 이벤트가 모두 처리된 후)
        setTimeout(() => {
          set({ isRestoringHistory: false });
        }, 0);
      } else {
        console.log("❌ Undo 불가: 히스토리가 없음");
      }
    },

    redo: () => {
      const { history, historyIndex } = get();

      console.log("⏩ Redo 시도:", { historyIndex, historyLength: history.length });

      if (historyIndex < history.length - 1) {
        const newIndex = historyIndex + 1;
        const snapshot = history[newIndex];

        console.log("✅ Redo 실행:", {
          이전인덱스: historyIndex,
          새인덱스: newIndex,
          노드수: snapshot.nodes.length,
          엣지수: snapshot.edges.length,
        });

        // 🔥 히스토리 복원 중 플래그 설정
        set({ isRestoringHistory: true });

        // 노드와 엣지 복원
        set({
          nodes: JSON.parse(JSON.stringify(snapshot.nodes)),
          edges: JSON.parse(JSON.stringify(snapshot.edges)),
          historyIndex: newIndex,
        });

        // 🔥 다음 틱에서 플래그 해제 (ReactFlow 이벤트가 모두 처리된 후)
        setTimeout(() => {
          set({ isRestoringHistory: false });
        }, 0);
      } else {
        console.log("❌ Redo 불가: 되돌릴 히스토리가 없음");
      }
    },

    canUndo: () => {
      const { historyIndex } = get();
      return historyIndex > 0;
    },

    canRedo: () => {
      const { history, historyIndex } = get();
      return historyIndex < history.length - 1;
    },

    // ========================================================================
    // 노드 관리
    // ========================================================================

    setNodes: (nodes) => set({ nodes }),

    onNodesChange: (changes) => {
      set({
        nodes: applyNodeChanges(changes, get().nodes) as FlowNode[],
      });
    },

    onNodeDragStart: () => {
      // 🔥 히스토리 복원 중이면 저장하지 않음
      if (get().isRestoringHistory) {
        console.log("⏭️ 히스토리 복원 중, 저장 스킵");
        return;
      }

      // 노드 드래그 시작 시 히스토리 저장 (변경 전 상태)
      get().saveToHistory();
      console.log("🎯 노드 이동 시작, 변경 전 상태 히스토리 저장");
    },

    addNode: (node) => {
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      if (!get().isRestoringHistory) {
        get().saveToHistory();
      }
      set((state) => ({
        nodes: [...state.nodes, node],
      }));
    },

    updateNode: (id, data) => {
      // 🔥 Debounced 히스토리 저장 (500ms 지연 - 타이핑 중에는 저장 안됨)
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      if (!get().isRestoringHistory && debouncedSaveToHistory) {
        debouncedSaveToHistory();
      }

      set((state) => ({
        nodes: state.nodes.map((node) =>
          node.id === id
            ? {
                ...node,
                data: { ...node.data, ...data },
              }
            : node,
        ),
      }));
    },

    removeNode: (id) => {
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      if (!get().isRestoringHistory) {
        get().saveToHistory();
      }
      set((state) => ({
        nodes: state.nodes.filter((node) => node.id !== id),
        edges: state.edges.filter((edge) => edge.source !== id && edge.target !== id),
      }));
    },

    removeNodes: (ids) => {
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      if (!get().isRestoringHistory) {
        get().saveToHistory();
      }
      set((state) => ({
        nodes: state.nodes.filter((node) => !ids.includes(node.id)),
        edges: state.edges.filter((edge) => !ids.includes(edge.source) && !ids.includes(edge.target)),
      }));
    },

    // ========================================================================
    // 엣지 관리
    // ========================================================================

    setEdges: (edges) => set({ edges }),

    onEdgesChange: (changes) => {
      // 엣지 삭제(remove) 타입이 있으면 히스토리 저장
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      const hasRemove = changes.some((change) => change.type === "remove");
      if (hasRemove && !get().isRestoringHistory) {
        get().saveToHistory();
        console.log("🔗 엣지 삭제, 변경 전 상태 히스토리 저장");
      }

      set({
        edges: applyEdgeChanges(changes, get().edges) as FlowEdge[],
      });
    },

    onConnect: (connection) => {
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      if (!get().isRestoringHistory) {
        get().saveToHistory();
      }

      // 연결 검증
      const validation = validateConnection(connection, get().nodes);
      if (!validation.valid) {
        console.warn("연결 검증 실패:", validation.error);
        return;
      }

      set((state) => ({
        edges: addEdge(
          {
            ...connection,
            type: "smoothstep",
            animated: false,
            data: {
              validation: { valid: true },
            },
          },
          state.edges,
        ) as FlowEdge[],
      }));
    },

    removeEdge: (id) => {
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      if (!get().isRestoringHistory) {
        get().saveToHistory();
      }
      set((state) => ({
        edges: state.edges.filter((edge) => edge.id !== id),
      }));
    },

    removeEdges: (ids) => {
      // 🔥 히스토리 복원 중이 아닐 때만 저장
      if (!get().isRestoringHistory) {
        get().saveToHistory();
      }
      set((state) => ({
        edges: state.edges.filter((edge) => !ids.includes(edge.id)),
      }));
    },

    // ========================================================================
    // 선택 관리
    // ========================================================================

    selectNode: (id, multi = false) => {
      set((state) => ({
        selectedNodes: multi ? [...state.selectedNodes, id] : [id],
      }));
    },

    selectNodes: (ids) => {
      set({
        selectedNodes: ids,
        showPropertiesPanel: ids.length > 0, // 노드가 선택되면 속성창 자동으로 열기
      });
    },

    selectEdge: (id, multi = false) => {
      set((state) => ({
        selectedEdges: multi ? [...state.selectedEdges, id] : [id],
      }));
    },

    clearSelection: () => {
      set({ selectedNodes: [], selectedEdges: [] });
    },

    // ========================================================================
    // 플로우 관리
    // ========================================================================

    loadFlow: (id, name, description, nodes, edges) => {
      console.log("📂 플로우 로드:", { id, name, 노드수: nodes.length, 엣지수: edges.length });
      set({
        flowId: id,
        flowName: name,
        flowDescription: description,
        nodes,
        edges,
        selectedNodes: [],
        selectedEdges: [],
        // 로드된 상태를 히스토리의 첫 번째 스냅샷으로 저장
        history: [{ nodes: JSON.parse(JSON.stringify(nodes)), edges: JSON.parse(JSON.stringify(edges)) }],
        historyIndex: 0,
      });
    },

    clearFlow: () => {
      console.log("🔄 플로우 초기화");
      set({
        flowId: null,
        flowName: "새 제어 플로우",
        flowDescription: "",
        nodes: [],
        edges: [],
        selectedNodes: [],
        selectedEdges: [],
        validationResult: null,
        history: [{ nodes: [], edges: [] }], // 초기 빈 상태를 히스토리에 저장
        historyIndex: 0,
      });
    },

    setFlowName: (name) => set({ flowName: name }),
    setFlowDescription: (description) => set({ flowDescription: description }),

    saveFlow: async () => {
      const { flowId, flowName, flowDescription, nodes, edges } = get();

      if (!flowName || flowName.trim() === "") {
        return { success: false, message: "플로우 이름을 입력해주세요." };
      }

      // 🔥 검증 (순환 참조 및 기타 에러 체크)
      const validation = get().validateFlow();

      // 🔥 검증 실패 시 상세 메시지와 함께 저장 차단
      if (!validation.valid) {
        const errorMessages = validation.errors
          .filter((err) => err.severity === "error")
          .map((err) => err.message)
          .join(", ");

        // 🔥 검증 패널 표시하여 사용자가 오류를 확인할 수 있도록
        set({ validationResult: validation, showValidationPanel: true });

        return {
          success: false,
          message: `플로우를 저장할 수 없습니다: ${errorMessages}`,
        };
      }

      set({ isSaving: true });

      try {
        // 플로우 데이터 직렬화
        const flowData = {
          nodes: nodes.map((node) => ({
            id: node.id,
            type: node.type,
            position: node.position,
            data: node.data,
          })),
          edges: edges.map((edge) => ({
            id: edge.id,
            source: edge.source,
            target: edge.target,
            sourceHandle: edge.sourceHandle,
            targetHandle: edge.targetHandle,
          })),
        };

        const result = flowId
          ? await updateNodeFlow({
              flowId,
              flowName,
              flowDescription,
              flowData: JSON.stringify(flowData),
            })
          : await createNodeFlow({
              flowName,
              flowDescription,
              flowData: JSON.stringify(flowData),
            });

        set({ flowId: result.flowId });
        return { success: true, flowId: result.flowId, message: "저장 완료!" };
      } catch (error) {
        console.error("플로우 저장 오류:", error);
        return { success: false, message: error instanceof Error ? error.message : "저장 중 오류 발생" };
      } finally {
        set({ isSaving: false });
      }
    },

    exportFlow: () => {
      const { flowName, flowDescription, nodes, edges } = get();
      const flowData = {
        flowName,
        flowDescription,
        nodes,
        edges,
        version: "1.0",
        exportedAt: new Date().toISOString(),
      };
      return JSON.stringify(flowData, null, 2);
    },

    // ========================================================================
    // 검증
    // ========================================================================

    validateFlow: () => {
      const { nodes, edges } = get();
      const result = performFlowValidation(nodes, edges);
      set({ validationResult: result });
      return result;
    },

    setValidationResult: (result) => set({ validationResult: result }),

    // ========================================================================
    // UI 상태
    // ========================================================================

    setIsSaving: (value) => set({ isSaving: value }),
    setShowValidationPanel: (value) => set({ showValidationPanel: value }),
    setShowPropertiesPanel: (value) => set({ showPropertiesPanel: value }),

    // ========================================================================
    // 유틸리티
    // ========================================================================

    getNodeById: (id) => {
      return get().nodes.find((node) => node.id === id);
    },

    getEdgeById: (id) => {
      return get().edges.find((edge) => edge.id === id);
    },

    getConnectedNodes: (nodeId) => {
      const { nodes, edges } = get();

      const incoming = edges
        .filter((edge) => edge.target === nodeId)
        .map((edge) => nodes.find((node) => node.id === edge.source))
        .filter((node): node is FlowNode => node !== undefined);

      const outgoing = edges
        .filter((edge) => edge.source === nodeId)
        .map((edge) => nodes.find((node) => node.id === edge.target))
        .filter((node): node is FlowNode => node !== undefined);

      return { incoming, outgoing };
    },

    // ========================================================================
    // 🔥 외부 커넥션 캐시 관리
    // ========================================================================

    setExternalConnectionsCache: (data) => {
      set({
        externalConnectionsCache: {
          data,
          timestamp: Date.now(),
        },
      });
    },

    clearExternalConnectionsCache: () => {
      set({ externalConnectionsCache: null });
    },

    getExternalConnectionsCache: () => {
      const cache = get().externalConnectionsCache;
      if (!cache) return null;

      // 🔥 5분 후 캐시 만료
      const CACHE_DURATION = 5 * 60 * 1000; // 5분
      const isExpired = Date.now() - cache.timestamp > CACHE_DURATION;

      if (isExpired) {
        set({ externalConnectionsCache: null });
        return null;
      }

      return cache.data;
    },
  }; // 🔥 return 블록 종료
}); // 🔥 create 함수 종료

// ============================================================================
// 헬퍼 함수들
// ============================================================================

/**
 * 연결 검증
 */
function validateConnection(connection: Connection, nodes: FlowNode[]): { valid: boolean; error?: string } {
  const sourceNode = nodes.find((n) => n.id === connection.source);
  const targetNode = nodes.find((n) => n.id === connection.target);

  if (!sourceNode || !targetNode) {
    return { valid: false, error: "노드를 찾을 수 없습니다" };
  }

  // 소스 노드가 출력을 가져야 함
  if (isSourceOnlyNode(sourceNode.type)) {
    // OK
  } else if (isActionNode(targetNode.type)) {
    // 액션 노드는 입력만 받을 수 있음
  } else {
    // 기타 경우는 허용
  }

  // 자기 자신에게 연결 방지
  if (connection.source === connection.target) {
    return { valid: false, error: "자기 자신에게 연결할 수 없습니다" };
  }

  return { valid: true };
}

/**
 * 플로우 검증
 */
function performFlowValidation(nodes: FlowNode[], edges: FlowEdge[]): ValidationResult {
  const errors: ValidationResult["errors"] = [];

  // 1. 노드가 하나도 없으면 경고
  if (nodes.length === 0) {
    errors.push({
      message: "노드가 없습니다. 최소 하나의 노드를 추가하세요.",
      severity: "warning",
    });
  }

  // 2. 소스 노드 확인
  const sourceNodes = nodes.filter((n) => isSourceNode(n.type));
  if (sourceNodes.length === 0 && nodes.length > 0) {
    errors.push({
      message: "데이터 소스 노드가 필요합니다.",
      severity: "error",
    });
  }

  // 3. 액션 노드 확인
  const actionNodes = nodes.filter((n) => isActionNode(n.type));
  if (actionNodes.length === 0 && nodes.length > 0) {
    errors.push({
      message: "최소 하나의 액션 노드가 필요합니다.",
      severity: "error",
    });
  }

  // 4. 고아 노드 확인 (연결되지 않은 노드) - Comment와 Log는 제외
  nodes.forEach((node) => {
    // Comment와 Log는 독립적으로 존재 가능
    if (node.type === "comment" || node.type === "log") {
      return;
    }

    const hasIncoming = edges.some((e) => e.target === node.id);
    const hasOutgoing = edges.some((e) => e.source === node.id);

    if (!hasIncoming && !hasOutgoing && !isSourceNode(node.type)) {
      errors.push({
        nodeId: node.id,
        message: `노드 "${node.data.displayName || node.id}"가 연결되어 있지 않습니다.`,
        severity: "warning",
      });
    }
  });

  // 5. 액션 노드가 입력을 받는지 확인
  actionNodes.forEach((node) => {
    const hasInput = edges.some((e) => e.target === node.id);
    if (!hasInput) {
      errors.push({
        nodeId: node.id,
        message: `액션 노드 "${node.data.displayName || node.id}"에 입력 데이터가 없습니다.`,
        severity: "error",
      });
    }
  });

  // 6. 순환 참조 검증
  const cycles = detectCycles(nodes, edges);
  cycles.forEach((cycle) => {
    errors.push({
      message: `순환 참조가 감지되었습니다: ${cycle.join(" → ")}`,
      severity: "error",
    });
  });

  // 7. 노드별 필수 속성 검증
  nodes.forEach((node) => {
    const nodeErrors = validateNodeProperties(node);
    errors.push(...nodeErrors);
  });

  return {
    valid: errors.filter((e) => e.severity === "error").length === 0,
    errors,
  };
}

/**
 * 소스 노드 여부 확인
 */
function isSourceNode(type: NodeType): boolean {
  return type === "tableSource" || type === "externalDBSource" || type === "restAPISource";
}

/**
 * 소스 전용 노드 여부 확인
 */
function isSourceOnlyNode(type: NodeType): boolean {
  return isSourceNode(type);
}

/**
 * 액션 노드 여부 확인
 */
function isActionNode(type: NodeType): boolean {
  return (
    type === "insertAction" ||
    type === "updateAction" ||
    type === "deleteAction" ||
    type === "upsertAction" ||
    type === "emailAction" ||       // 이메일 발송 액션
    type === "scriptAction" ||      // 스크립트 실행 액션
    type === "httpRequestAction"    // HTTP 요청 액션
  );
}

/**
 * 순환 참조 검증 (DFS 사용)
 */
function detectCycles(nodes: FlowNode[], edges: FlowEdge[]): string[][] {
  const cycles: string[][] = [];
  const visited = new Set<string>();
  const recursionStack = new Set<string>();

  // 인접 리스트 생성
  const adjacencyList = new Map<string, string[]>();
  nodes.forEach((node) => adjacencyList.set(node.id, []));
  edges.forEach((edge) => {
    const targets = adjacencyList.get(edge.source) || [];
    targets.push(edge.target);
    adjacencyList.set(edge.source, targets);
  });

  function dfs(nodeId: string, path: string[]): boolean {
    visited.add(nodeId);
    recursionStack.add(nodeId);
    path.push(nodeId);

    const neighbors = adjacencyList.get(nodeId) || [];
    for (const neighbor of neighbors) {
      if (!visited.has(neighbor)) {
        if (dfs(neighbor, [...path])) {
          return true;
        }
      } else if (recursionStack.has(neighbor)) {
        // 순환 발견
        const cycleStart = path.indexOf(neighbor);
        const cycle = path.slice(cycleStart).concat(neighbor);
        const nodeNames = cycle.map((id) => {
          const node = nodes.find((n) => n.id === id);
          return node?.data.displayName || id;
        });
        cycles.push(nodeNames);
        return true;
      }
    }

    recursionStack.delete(nodeId);
    return false;
  }

  // 모든 노드에서 DFS 시작
  nodes.forEach((node) => {
    if (!visited.has(node.id)) {
      dfs(node.id, []);
    }
  });

  return cycles;
}

/**
 * 노드별 필수 속성 검증
 */
function validateNodeProperties(node: FlowNode): ValidationResult["errors"] {
  const errors: ValidationResult["errors"] = [];

  switch (node.type) {
    case "tableSource":
      if (!node.data.tableName || node.data.tableName.trim() === "") {
        errors.push({
          nodeId: node.id,
          message: `테이블 소스 노드 "${node.data.displayName || node.id}": 테이블명이 필요합니다.`,
          severity: "error",
        });
      }
      break;

    case "externalDBSource":
      if (!node.data.connectionName || node.data.connectionName.trim() === "") {
        errors.push({
          nodeId: node.id,
          message: `외부 DB 소스 노드 "${node.data.displayName || node.id}": 연결 이름이 필요합니다.`,
          severity: "error",
        });
      }
      if (!node.data.tableName || node.data.tableName.trim() === "") {
        errors.push({
          nodeId: node.id,
          message: `외부 DB 소스 노드 "${node.data.displayName || node.id}": 테이블명이 필요합니다.`,
          severity: "error",
        });
      }
      break;

    case "restAPISource":
      if (!node.data.url || node.data.url.trim() === "") {
        errors.push({
          nodeId: node.id,
          message: `REST API 소스 노드 "${node.data.displayName || node.id}": URL이 필요합니다.`,
          severity: "error",
        });
      }
      if (!node.data.method) {
        errors.push({
          nodeId: node.id,
          message: `REST API 소스 노드 "${node.data.displayName || node.id}": HTTP 메서드가 필요합니다.`,
          severity: "error",
        });
      }
      break;

    case "insertAction":
    case "updateAction":
    case "deleteAction":
      if (!node.data.targetTable || node.data.targetTable.trim() === "") {
        errors.push({
          nodeId: node.id,
          message: `${getActionTypeName(node.type)} 노드 "${node.data.displayName || node.id}": 타겟 테이블이 필요합니다.`,
          severity: "error",
        });
      }
      if (node.type === "insertAction" || node.type === "updateAction") {
        if (!node.data.fieldMappings || node.data.fieldMappings.length === 0) {
          errors.push({
            nodeId: node.id,
            message: `${getActionTypeName(node.type)} 노드 "${node.data.displayName || node.id}": 최소 하나의 필드 매핑이 필요합니다.`,
            severity: "error",
          });
        }
      }
      if (node.type === "updateAction" || node.type === "deleteAction") {
        if (!node.data.whereConditions || node.data.whereConditions.length === 0) {
          errors.push({
            nodeId: node.id,
            message: `${getActionTypeName(node.type)} 노드 "${node.data.displayName || node.id}": WHERE 조건이 필요합니다.`,
            severity: "error",
          });
        }
      }
      break;

    case "upsertAction":
      if (!node.data.targetTable || node.data.targetTable.trim() === "") {
        errors.push({
          nodeId: node.id,
          message: `UPSERT 액션 노드 "${node.data.displayName || node.id}": 타겟 테이블이 필요합니다.`,
          severity: "error",
        });
      }
      if (!node.data.conflictKeys || node.data.conflictKeys.length === 0) {
        errors.push({
          nodeId: node.id,
          message: `UPSERT 액션 노드 "${node.data.displayName || node.id}": 충돌 키(ON CONFLICT)가 필요합니다.`,
          severity: "error",
        });
      }
      if (!node.data.fieldMappings || node.data.fieldMappings.length === 0) {
        errors.push({
          nodeId: node.id,
          message: `UPSERT 액션 노드 "${node.data.displayName || node.id}": 최소 하나의 필드 매핑이 필요합니다.`,
          severity: "error",
        });
      }
      break;

    case "condition":
      if (!node.data.conditions || node.data.conditions.length === 0) {
        errors.push({
          nodeId: node.id,
          message: `조건 노드 "${node.data.displayName || node.id}": 최소 하나의 조건이 필요합니다.`,
          severity: "error",
        });
      }
      break;

    case "fieldMapping":
      if (!node.data.mappings || node.data.mappings.length === 0) {
        errors.push({
          nodeId: node.id,
          message: `필드 매핑 노드 "${node.data.displayName || node.id}": 최소 하나의 매핑이 필요합니다.`,
          severity: "warning",
        });
      }
      break;

    case "dataTransform":
      if (!node.data.transformations || node.data.transformations.length === 0) {
        errors.push({
          nodeId: node.id,
          message: `데이터 변환 노드 "${node.data.displayName || node.id}": 최소 하나의 변환 규칙이 필요합니다.`,
          severity: "warning",
        });
      }
      break;

    case "log":
      if (!node.data.message || node.data.message.trim() === "") {
        errors.push({
          nodeId: node.id,
          message: `로그 노드 "${node.data.displayName || node.id}": 로그 메시지가 필요합니다.`,
          severity: "warning",
        });
      }
      break;

    case "comment":
      // Comment 노드는 내용이 없어도 괜찮음
      break;
  }

  return errors;
}

/**
 * 액션 타입 이름 반환
 */
function getActionTypeName(type: string): string {
  const names: Record<string, string> = {
    insertAction: "INSERT",
    updateAction: "UPDATE",
    deleteAction: "DELETE",
    upsertAction: "UPSERT",
  };
  return names[type] || type;
}
