"use client";

/**
 * INSERT 액션 노드 속성 편집 (개선 버전)
 */

import { useEffect, useState } from "react";
import { Plus, Trash2, Check, ChevronsUpDown, ArrowRight, Database, Globe, Link2, Sparkles } from "lucide-react";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { ScrollArea } from "@/components/ui/scroll-area";
import { cn } from "@/lib/utils";
import { useFlowEditorStore } from "@/lib/stores/flowEditorStore";
import { tableTypeApi } from "@/lib/api/screen";
import { getTestedExternalConnections, getExternalTables, getExternalColumns } from "@/lib/api/nodeExternalConnections";
import { getNumberingRules } from "@/lib/api/numberingRule";
import type { NumberingRuleConfig } from "@/types/numbering-rule";
import { getFlowProcedureParameters } from "@/lib/api/flow";
import type { InsertActionNodeData } from "@/types/node-editor";
import type { ExternalConnection, ExternalTable, ExternalColumn } from "@/lib/api/nodeExternalConnections";

interface InsertActionPropertiesProps {
  nodeId: string;
  data: InsertActionNodeData;
}

interface TableOption {
  tableName: string;
  displayName: string;
  description: string;
  label: string;
}

interface ColumnInfo {
  columnName: string;
  columnLabel?: string;
  dataType: string;
  isNullable: boolean;
  columnDefault?: string | null;
}

export function InsertActionProperties({ nodeId, data }: InsertActionPropertiesProps) {
  const { updateNode, nodes, edges, getExternalConnectionsCache } = useFlowEditorStore();

  // 🔥 타겟 타입 상태
  const [targetType, setTargetType] = useState<"internal" | "external" | "api">(data.targetType || "internal");

  const [displayName, setDisplayName] = useState(data.displayName || data.targetTable);
  const [targetTable, setTargetTable] = useState(data.targetTable);
  const [fieldMappings, setFieldMappings] = useState(data.fieldMappings || []);

  // 내부 DB 테이블 관련 상태
  const [tables, setTables] = useState<TableOption[]>([]);
  const [tablesLoading, setTablesLoading] = useState(false);
  const [tablesOpen, setTablesOpen] = useState(false);

  // 컬럼 관련 상태
  const [targetColumns, setTargetColumns] = useState<ColumnInfo[]>([]);
  const [columnsLoading, setColumnsLoading] = useState(false);

  // 소스 필드 목록 (연결된 입력 노드에서 가져오기)
  const [sourceFields, setSourceFields] = useState<Array<{ name: string; label?: string }>>([]);
  // REST API 소스 노드 연결 여부
  const [hasRestAPISource, setHasRestAPISource] = useState(false);

  // Combobox 열림 상태 관리 (필드 매핑)
  const [mappingSourceFieldsOpenState, setMappingSourceFieldsOpenState] = useState<boolean[]>([]);
  const [mappingTargetFieldsOpenState, setMappingTargetFieldsOpenState] = useState<boolean[]>([]);

  // 🔥 외부 DB 관련 상태
  const [externalConnections, setExternalConnections] = useState<ExternalConnection[]>([]);
  const [externalConnectionsLoading, setExternalConnectionsLoading] = useState(false);
  const [selectedExternalConnectionId, setSelectedExternalConnectionId] = useState<number | undefined>(
    data.externalConnectionId,
  );
  const [externalTables, setExternalTables] = useState<ExternalTable[]>([]);
  const [externalTablesLoading, setExternalTablesLoading] = useState(false);
  const [externalTargetTable, setExternalTargetTable] = useState(data.externalTargetTable);
  const [externalColumns, setExternalColumns] = useState<ExternalColumn[]>([]);
  const [externalColumnsLoading, setExternalColumnsLoading] = useState(false);

  // 🔥 REST API 관련 상태
  const [apiEndpoint, setApiEndpoint] = useState(data.apiEndpoint || "");
  const [apiMethod, setApiMethod] = useState<"POST" | "PUT" | "PATCH">(data.apiMethod || "POST");
  const [apiAuthType, setApiAuthType] = useState<"none" | "basic" | "bearer" | "apikey">(data.apiAuthType || "none");
  const [apiAuthConfig, setApiAuthConfig] = useState(data.apiAuthConfig || {});
  const [apiHeaders, setApiHeaders] = useState<Record<string, string>>(data.apiHeaders || {});
  const [apiBodyTemplate, setApiBodyTemplate] = useState(data.apiBodyTemplate || "");

  // 🔥 채번 규칙 관련 상태
  const [numberingRules, setNumberingRules] = useState<NumberingRuleConfig[]>([]);
  const [numberingRulesLoading, setNumberingRulesLoading] = useState(false);
  const [mappingNumberingRulesOpenState, setMappingNumberingRulesOpenState] = useState<boolean[]>([]);

  // 데이터 변경 시 로컬 상태 업데이트
  useEffect(() => {
    setDisplayName(data.displayName || data.targetTable);
    setTargetTable(data.targetTable);
    setFieldMappings(data.fieldMappings || []);
  }, [data]);

  // 내부 DB 테이블 목록 로딩
  useEffect(() => {
    if (targetType === "internal") {
      loadTables();
    }
  }, [targetType]);

  // 타겟 테이블 변경 시 컬럼 로딩 (내부 DB)
  useEffect(() => {
    if (targetType === "internal" && targetTable) {
      loadColumns(targetTable);
    }
  }, [targetType, targetTable]);

  // 🔥 외부 커넥션 로드 (캐시 우선)
  useEffect(() => {
    if (targetType === "external") {
      loadExternalConnections();
    }
  }, [targetType]);

  // 🔥 외부 커넥션 변경 시 테이블 로드
  useEffect(() => {
    if (targetType === "external" && selectedExternalConnectionId) {
      loadExternalTables(selectedExternalConnectionId);
    }
  }, [targetType, selectedExternalConnectionId]);

  // fieldMappings 변경 시 Combobox 열림 상태 초기화
  useEffect(() => {
    setMappingSourceFieldsOpenState(new Array(fieldMappings.length).fill(false));
    setMappingTargetFieldsOpenState(new Array(fieldMappings.length).fill(false));
    setMappingNumberingRulesOpenState(new Array(fieldMappings.length).fill(false));
  }, [fieldMappings.length]);

  // 🔥 채번 규칙 로딩 (자동 생성 사용 시)
  useEffect(() => {
    const loadNumberingRules = async () => {
      setNumberingRulesLoading(true);
      try {
        const response = await getNumberingRules();
        if (response.success && response.data) {
          setNumberingRules(response.data);
          console.log(`✅ 채번 규칙 ${response.data.length}개 로딩 완료`);
        } else {
          console.error("❌ 채번 규칙 로딩 실패:", response.error);
          setNumberingRules([]);
        }
      } catch (error) {
        console.error("❌ 채번 규칙 로딩 오류:", error);
        setNumberingRules([]);
      } finally {
        setNumberingRulesLoading(false);
      }
    };

    loadNumberingRules();
  }, []);

  // 🔥 외부 테이블 변경 시 컬럼 로드
  useEffect(() => {
    if (targetType === "external" && selectedExternalConnectionId && externalTargetTable) {
      loadExternalColumns(selectedExternalConnectionId, externalTargetTable);
    }
  }, [targetType, selectedExternalConnectionId, externalTargetTable]);

  // 연결된 소스 노드에서 필드 가져오기 (재귀적으로 모든 상위 노드 탐색)
  useEffect(() => {
    // 프로시저 노드 정보를 수집하여 비동기 파라미터 조회에 사용
    const procedureNodes: Array<{
      procedureName: string;
      dbSource: "internal" | "external";
      connectionId?: number;
      schema?: string;
      sourcePath: string[];
    }> = [];

    const getAllSourceFields = (
      targetNodeId: string,
      visitedNodes = new Set<string>(),
      sourcePath: string[] = [],
    ): { fields: Array<{ name: string; label?: string; sourcePath?: string[] }>; hasRestAPI: boolean } => {
      if (visitedNodes.has(targetNodeId)) {
        console.log(`⚠️ 순환 참조 감지: ${targetNodeId} (이미 방문함)`);
        return { fields: [], hasRestAPI: false };
      }
      visitedNodes.add(targetNodeId);

      const inputEdges = edges.filter((edge) => edge.target === targetNodeId);
      const sourceNodeIds = inputEdges.map((edge) => edge.source);
      const sourceNodes = nodes.filter((node) => sourceNodeIds.includes(node.id));

      // 🔥 다중 소스 감지
      if (sourceNodes.length > 1) {
        console.log(`⚠️ 다중 소스 감지: ${sourceNodes.length}개 노드 연결됨`);
        console.log("   소스 노드들:", sourceNodes.map((n) => `${n.id}(${n.type})`).join(", "));
      }

      const fields: Array<{ name: string; label?: string; sourcePath?: string[] }> = [];
      let foundRestAPI = false;

      sourceNodes.forEach((node) => {
        console.log(`🔍 노드 ${node.id} 타입: ${node.type}`);

        // 🔥 현재 노드를 경로에 추가
        const currentPath = [...sourcePath, `${node.id}(${node.type})`];

        // 1️⃣ 데이터 변환 노드: 변환된 필드 + 상위 노드의 원본 필드
        if (node.type === "dataTransform") {
          console.log("✅ 데이터 변환 노드 발견");

          // 상위 노드의 원본 필드 먼저 수집
          const upperResult = getAllSourceFields(node.id, visitedNodes, currentPath);
          const upperFields = upperResult.fields;
          foundRestAPI = foundRestAPI || upperResult.hasRestAPI;
          console.log(`   📤 상위 노드에서 ${upperFields.length}개 필드 가져옴`);

          // 변환된 필드 추가 (in-place 변환 고려)
          if ((node.data as any).transformations && Array.isArray((node.data as any).transformations)) {
            console.log(`   📊 ${(node.data as any).transformations.length}개 변환 발견`);
            const inPlaceFields = new Set<string>();

            (node.data as any).transformations.forEach((transform: any) => {
              const targetField = transform.targetField || transform.sourceField;
              const isInPlace = !transform.targetField || transform.targetField === transform.sourceField;

              console.log(`   🔹 변환: ${transform.sourceField} → ${targetField} ${isInPlace ? "(in-place)" : ""}`);

              if (isInPlace) {
                inPlaceFields.add(transform.sourceField);
              } else if (targetField) {
                fields.push({
                  name: targetField,
                  label: transform.targetFieldLabel || targetField,
                  sourcePath: currentPath,
                });
              }
            });

            // 상위 필드 추가
            upperFields.forEach((field) => {
              if (!inPlaceFields.has(field.name)) {
                fields.push(field);
              } else {
                fields.push(field);
              }
            });
          } else {
            fields.push(...upperFields);
          }
        }
        // 2️⃣ REST API 소스 노드
        else if (node.type === "restAPISource") {
          console.log("✅ REST API 소스 노드 발견");
          foundRestAPI = true;
          const responseFields = (node.data as any).responseFields;

          if (responseFields && Array.isArray(responseFields)) {
            console.log(`✅ REST API 노드에서 ${responseFields.length}개 필드 발견`);
            responseFields.forEach((field: any) => {
              const fieldName = field.name || field.fieldName;
              const fieldLabel = field.label || field.displayName;
              if (fieldName) {
                fields.push({
                  name: fieldName,
                  label: fieldLabel,
                  sourcePath: currentPath,
                });
              }
            });
          } else {
            console.log("⚠️ REST API 노드에 responseFields 없음");
          }
        }
        // 3️⃣ 수식 변환(FormulaTransform) 노드: 상위 필드 + 변환 출력 필드
        else if (node.type === "formulaTransform") {
          console.log("✅ 수식 변환 노드 발견");

          // 상위 노드의 필드 가져오기
          const upperResult = getAllSourceFields(node.id, visitedNodes, currentPath);
          fields.push(...upperResult.fields);
          foundRestAPI = foundRestAPI || upperResult.hasRestAPI;

          // 수식 변환 출력 필드 추가
          const nodeData = node.data as any;
          if (nodeData.transformations && Array.isArray(nodeData.transformations)) {
            console.log(`   📊 ${nodeData.transformations.length}개 수식 변환 발견`);
            nodeData.transformations.forEach((trans: any) => {
              if (trans.outputField) {
                fields.push({
                  name: trans.outputField,
                  label: trans.outputFieldLabel || trans.outputField,
                  sourcePath: currentPath,
                });
              }
            });
          }
        }
        // 4️⃣ 집계(Aggregate) 노드: 그룹 필드 + 집계 결과 필드
        else if (node.type === "aggregate") {
          console.log("✅ 집계 노드 발견");
          const nodeData = node.data as any;

          // 그룹 기준 필드 추가 (field 또는 fieldName 둘 다 지원)
          if (nodeData.groupByFields && Array.isArray(nodeData.groupByFields)) {
            console.log(`   📊 ${nodeData.groupByFields.length}개 그룹 필드 발견`);
            nodeData.groupByFields.forEach((groupField: any) => {
              const fieldName = groupField.field || groupField.fieldName;
              if (fieldName) {
                fields.push({
                  name: fieldName,
                  label: groupField.fieldLabel || fieldName,
                  sourcePath: currentPath,
                });
              }
            });
          }

          // 집계 결과 필드 추가 (aggregations 또는 aggregateFunctions 둘 다 지원)
          const aggregations = nodeData.aggregations || nodeData.aggregateFunctions || [];
          if (Array.isArray(aggregations)) {
            console.log(`   📊 ${aggregations.length}개 집계 함수 발견`);
            aggregations.forEach((aggFunc: any) => {
              // outputField 또는 targetField 둘 다 지원
              const outputFieldName = aggFunc.outputField || aggFunc.targetField;
              // function 또는 aggregateType 둘 다 지원
              const funcType = aggFunc.function || aggFunc.aggregateType;
              if (outputFieldName) {
                fields.push({
                  name: outputFieldName,
                  label:
                    aggFunc.outputFieldLabel ||
                    aggFunc.targetFieldLabel ||
                    `${funcType}(${aggFunc.sourceFieldLabel || aggFunc.sourceField})`,
                  sourcePath: currentPath,
                });
              }
            });
          }

          // 집계 노드는 상위 노드의 필드를 그대로 통과시키지 않음 (집계된 결과만 전달)
        }
        // 4️⃣ 테이블/외부DB 소스 노드
        else if (node.type === "tableSource" || node.type === "externalDBSource") {
          const nodeFields = (node.data as any).fields || (node.data as any).outputFields;
          const displayName = (node.data as any).displayName || (node.data as any).tableName || node.id;

          if (nodeFields && Array.isArray(nodeFields)) {
            console.log(`✅ ${node.type}[${displayName}] 노드에서 ${nodeFields.length}개 필드 발견`);
            nodeFields.forEach((field: any) => {
              const fieldName = field.name || field.fieldName || field.column_name;
              const fieldLabel = field.label || field.displayName || field.label_ko;
              if (fieldName) {
                // 🔥 다중 소스인 경우 필드명에 소스 표시
                const displayLabel =
                  sourceNodes.length > 1 ? `${fieldLabel || fieldName} [${displayName}]` : fieldLabel || fieldName;

                fields.push({
                  name: fieldName,
                  label: displayLabel,
                  sourcePath: currentPath,
                });
              }
            });
          } else {
            console.log(`⚠️ ${node.type} 노드에 필드 정의 없음 → 상위 노드 탐색`);
            // 필드가 없으면 상위 노드로 계속 탐색
            const upperResult = getAllSourceFields(node.id, visitedNodes, currentPath);
            fields.push(...upperResult.fields);
            foundRestAPI = foundRestAPI || upperResult.hasRestAPI;
          }
        }
        // 5️⃣ 프로시저 호출 노드: 상위 필드 + OUT 파라미터(반환 필드) 추가
        else if (node.type === "procedureCallAction") {
          console.log("✅ 프로시저 호출 노드 발견");
          const upperResult = getAllSourceFields(node.id, visitedNodes, currentPath);
          fields.push(...upperResult.fields);
          foundRestAPI = foundRestAPI || upperResult.hasRestAPI;

          const nodeData = node.data as any;
          const procParams = nodeData.parameters;
          let hasOutParams = false;

          if (Array.isArray(procParams)) {
            for (const p of procParams) {
              if (p.mode === "OUT" || p.mode === "INOUT") {
                hasOutParams = true;
                fields.push({
                  name: p.name,
                  label: `${p.name} (프로시저 반환)`,
                  sourcePath: currentPath,
                });
              }
            }
          }

          // OUT 파라미터가 저장되어 있지 않으면 API로 동적 조회 예약
          if (!hasOutParams && nodeData.procedureName) {
            procedureNodes.push({
              procedureName: nodeData.procedureName,
              dbSource: nodeData.dbSource || "internal",
              connectionId: nodeData.connectionId,
              schema: nodeData.procedureSchema || "public",
              sourcePath: currentPath,
            });
          }

          fields.push({
            name: "_procedureReturn",
            label: "프로시저 반환값",
            sourcePath: currentPath,
          });
        }
        // 6️⃣ 통과 노드 (조건, 기타 모든 노드): 상위 노드로 계속 탐색
        else {
          console.log(`✅ 통과 노드 (${node.type}) → 상위 노드로 계속 탐색`);
          const upperResult = getAllSourceFields(node.id, visitedNodes, currentPath);
          fields.push(...upperResult.fields);
          foundRestAPI = foundRestAPI || upperResult.hasRestAPI;
          console.log(`   📤 상위 노드에서 ${upperResult.fields.length}개 필드 가져옴`);
        }
      });

      return { fields, hasRestAPI: foundRestAPI };
    };

    console.log("🔍 INSERT 노드 ID:", nodeId);
    const result = getAllSourceFields(nodeId);

    console.log("📊 필드 수집 완료:");
    console.log(`   - 총 필드 수: ${result.fields.length}개`);
    console.log(`   - REST API 포함: ${result.hasRestAPI}`);

    const applyFields = (allFields: typeof result.fields) => {
      const fieldMap = new Map<string, (typeof result.fields)[number]>();
      const duplicateFields = new Set<string>();

      allFields.forEach((field) => {
        const key = `${field.name}`;
        if (fieldMap.has(key)) {
          duplicateFields.add(field.name);
        }
        fieldMap.set(key, field);
      });

      if (duplicateFields.size > 0) {
        console.warn(`⚠️ 중복 필드명 감지: ${Array.from(duplicateFields).join(", ")}`);
      }

      const uniqueFields = Array.from(fieldMap.values());
      setSourceFields(uniqueFields);
      setHasRestAPISource(result.hasRestAPI);
      console.log("✅ 최종 소스 필드 목록:", uniqueFields);
    };

    // 프로시저 노드에 OUT 파라미터가 저장되지 않은 경우, API로 동적 조회
    if (procedureNodes.length > 0) {
      console.log(`🔄 프로시저 ${procedureNodes.length}개의 반환 필드를 API로 조회`);
      applyFields(result.fields);

      Promise.all(
        procedureNodes.map(async (pn) => {
          try {
            const res = await getFlowProcedureParameters(
              pn.procedureName,
              pn.dbSource,
              pn.connectionId,
              pn.schema
            );
            if (res.success && res.data) {
              return res.data
                .filter((p: any) => p.mode === "OUT" || p.mode === "INOUT")
                .map((p: any) => ({
                  name: p.name,
                  label: `${p.name} (프로시저 반환)`,
                  sourcePath: pn.sourcePath,
                }));
            }
          } catch (e) {
            console.error("프로시저 파라미터 조회 실패:", e);
          }
          return [];
        })
      ).then((extraFieldArrays) => {
        const extraFields = extraFieldArrays.flat();
        if (extraFields.length > 0) {
          console.log(`✅ 프로시저 반환 필드 ${extraFields.length}개 추가 발견`);
          applyFields([...result.fields, ...extraFields]);
        }
      });
    } else {
      applyFields(result.fields);
    }
  }, [nodeId, nodes, edges]);

  /**
   * 테이블 목록 로드
   */
  const loadTables = async () => {
    try {
      setTablesLoading(true);
      const tableList = await tableTypeApi.getTables();

      const options: TableOption[] = tableList.map((table) => {
        const label = (table as any).tableLabel || table.displayName || table.tableName || "알 수 없는 테이블";

        return {
          tableName: table.tableName,
          displayName: table.displayName || table.tableName,
          description: table.description || "",
          label,
        };
      });

      setTables(options);
      console.log(`✅ 테이블 ${options.length}개 로딩 완료`);
    } catch (error) {
      console.error("❌ 테이블 목록 로딩 실패:", error);
      setTables([]);
    } finally {
      setTablesLoading(false);
    }
  };

  /**
   * 타겟 테이블의 컬럼 목록 로드
   */
  const loadColumns = async (tableName: string) => {
    try {
      setColumnsLoading(true);
      console.log(`🔍 컬럼 조회 중: ${tableName}`);

      const columns = await tableTypeApi.getColumns(tableName);

      const columnInfo: ColumnInfo[] = columns.map((col: any) => {
        // is_nullable 파싱: "YES", true, 1 등을 true로, "NO", false, 0 등을 false로 변환
        const isNullableValue = col.is_nullable ?? col.isNullable;
        let isNullable = true; // 기본값: nullable

        if (typeof isNullableValue === "boolean") {
          isNullable = isNullableValue;
        } else if (typeof isNullableValue === "string") {
          isNullable = isNullableValue.toUpperCase() === "YES" || isNullableValue.toUpperCase() === "TRUE";
        } else if (typeof isNullableValue === "number") {
          isNullable = isNullableValue !== 0;
        }

        return {
          columnName: col.column_name || col.columnName,
          columnLabel: col.label_ko || col.columnLabel,
          dataType: col.data_type || col.dataType || "unknown",
          isNullable,
          columnDefault: col.column_default ?? col.columnDefault ?? null,
        };
      });

      setTargetColumns(columnInfo);
      console.log(`✅ 컬럼 ${columnInfo.length}개 로딩 완료`);
    } catch (error) {
      console.error("❌ 컬럼 목록 로딩 실패:", error);
      setTargetColumns([]);
    } finally {
      setColumnsLoading(false);
    }
  };

  // 🔥 외부 커넥션 로드 (캐시 우선)
  const loadExternalConnections = async () => {
    try {
      // 캐시 확인
      const cachedData = getExternalConnectionsCache();
      if (cachedData) {
        console.log("✅ 캐시된 외부 커넥션 사용:", cachedData.length);
        setExternalConnections(cachedData);
        return;
      }

      setExternalConnectionsLoading(true);
      console.log("🔍 외부 커넥션 조회 중...");

      const connections = await getTestedExternalConnections();
      setExternalConnections(connections);
      console.log(`✅ 외부 커넥션 ${connections.length}개 로딩 완료`);
    } catch (error) {
      console.error("❌ 외부 커넥션 로딩 실패:", error);
      setExternalConnections([]);
    } finally {
      setExternalConnectionsLoading(false);
    }
  };

  // 🔥 외부 테이블 로드
  const loadExternalTables = async (connectionId: number) => {
    try {
      setExternalTablesLoading(true);
      console.log(`🔍 외부 테이블 조회 중: connection ${connectionId}`);

      const tables = await getExternalTables(connectionId);
      setExternalTables(tables);
      console.log(`✅ 외부 테이블 ${tables.length}개 로딩 완료`);
    } catch (error) {
      console.error("❌ 외부 테이블 로딩 실패:", error);
      setExternalTables([]);
    } finally {
      setExternalTablesLoading(false);
    }
  };

  // 🔥 외부 컬럼 로드
  const loadExternalColumns = async (connectionId: number, tableName: string) => {
    try {
      setExternalColumnsLoading(true);
      console.log(`🔍 외부 컬럼 조회 중: ${tableName}`);

      const columns = await getExternalColumns(connectionId, tableName);
      setExternalColumns(columns);
      console.log(`✅ 외부 컬럼 ${columns.length}개 로딩 완료`);
    } catch (error) {
      console.error("❌ 외부 컬럼 로딩 실패:", error);
      setExternalColumns([]);
    } finally {
      setExternalColumnsLoading(false);
    }
  };

  /**
   * 테이블 선택 핸들러
   */
  const handleTableSelect = (selectedTableName: string) => {
    const selectedTable = tables.find((t) => t.tableName === selectedTableName);
    if (selectedTable) {
      setTargetTable(selectedTable.tableName);
      if (!displayName || displayName === targetTable) {
        setDisplayName(selectedTable.label);
      }

      // 즉시 노드 업데이트
      updateNode(nodeId, {
        displayName: selectedTable.label,
        targetTable: selectedTable.tableName,
        fieldMappings,
      });

      setTablesOpen(false);
    }
  };

  const handleAddMapping = () => {
    const newMappings = [
      ...fieldMappings,
      {
        sourceField: null,
        targetField: "",
        staticValue: undefined,
        valueType: "source" as const, // 🔥 기본값: 소스 필드
      },
    ];
    setFieldMappings(newMappings);
    updateNode(nodeId, { fieldMappings: newMappings });

    // Combobox 열림 상태 배열 초기화
    setMappingSourceFieldsOpenState(new Array(newMappings.length).fill(false));
    setMappingTargetFieldsOpenState(new Array(newMappings.length).fill(false));
    setMappingNumberingRulesOpenState(new Array(newMappings.length).fill(false));
  };

  const handleRemoveMapping = (index: number) => {
    const newMappings = fieldMappings.filter((_, i) => i !== index);
    setFieldMappings(newMappings);
    updateNode(nodeId, { fieldMappings: newMappings });

    // Combobox 열림 상태 배열도 업데이트
    setMappingSourceFieldsOpenState(new Array(newMappings.length).fill(false));
    setMappingTargetFieldsOpenState(new Array(newMappings.length).fill(false));
    setMappingNumberingRulesOpenState(new Array(newMappings.length).fill(false));
  };

  const handleMappingChange = (index: number, field: string, value: any) => {
    const newMappings = [...fieldMappings];

    // 필드 변경 시 라벨도 함께 저장
    if (field === "sourceField") {
      const sourceField = sourceFields.find((f) => f.name === value);
      newMappings[index] = {
        ...newMappings[index],
        sourceField: value,
        sourceFieldLabel: sourceField?.label,
      };
    } else if (field === "targetField") {
      const targetColumn = (() => {
        if (targetType === "internal") {
          return targetColumns.find((col) => col.column_name === value);
        } else if (targetType === "external") {
          return externalColumns.find((col) => col.column_name === value);
        }
        return null;
      })();

      newMappings[index] = {
        ...newMappings[index],
        targetField: value,
        targetFieldLabel: targetColumn?.label_ko || targetColumn?.column_label || targetColumn?.displayName || value,
      };
    } else if (field === "valueType") {
      // 🔥 값 생성 유형 변경 시 관련 필드 초기화
      newMappings[index] = {
        ...newMappings[index],
        valueType: value,
        // 유형 변경 시 다른 유형의 값 초기화
        ...(value !== "source" && { sourceField: null, sourceFieldLabel: undefined }),
        ...(value !== "static" && { staticValue: undefined }),
        ...(value !== "autoGenerate" && { numberingRuleId: undefined, numberingRuleName: undefined }),
      };
    } else if (field === "numberingRuleId") {
      // 🔥 채번 규칙 선택 시 이름도 함께 저장
      const selectedRule = numberingRules.find((r) => r.ruleId === value);
      newMappings[index] = {
        ...newMappings[index],
        numberingRuleId: value,
        numberingRuleName: selectedRule?.ruleName,
      };
    } else {
      newMappings[index] = {
        ...newMappings[index],
        [field]: value,
      };
    }

    setFieldMappings(newMappings);
    updateNode(nodeId, { fieldMappings: newMappings });
  };

  // 즉시 반영 핸들러들
  const handleDisplayNameChange = (newDisplayName: string) => {
    setDisplayName(newDisplayName);
    updateNode(nodeId, { displayName: newDisplayName });
  };

  const handleFieldMappingsChange = (newMappings: any[]) => {
    setFieldMappings(newMappings);
    updateNode(nodeId, { fieldMappings: newMappings });
  };

  const selectedTableLabel = tables.find((t) => t.tableName === targetTable)?.label || targetTable;

  // 🔥 타겟 타입 변경 핸들러
  const handleTargetTypeChange = (newType: "internal" | "external" | "api") => {
    setTargetType(newType);

    // 타입 변경 시 관련 필드 초기화
    const updates: any = {
      targetType: newType,
      displayName,
    };

    // 이전 타입의 데이터 유지
    if (newType === "internal") {
      updates.targetTable = targetTable;
      updates.targetTableLabel = data.targetTableLabel;
    } else if (newType === "external") {
      updates.externalConnectionId = data.externalConnectionId;
      updates.externalTargetTable = data.externalTargetTable;
    } else if (newType === "api") {
      updates.apiEndpoint = data.apiEndpoint;
      updates.apiMethod = data.apiMethod || "POST";
    }

    updates.fieldMappings = fieldMappings;

    updateNode(nodeId, updates);
  };

  return (
    <div>
      <div className="space-y-4 p-4 pb-8">
        {/* 🔥 타겟 타입 선택 */}
        <div>
          <Label className="mb-2 block text-xs font-medium">타겟 선택</Label>
          <div className="grid grid-cols-3 gap-2">
            <button
              type="button"
              onClick={() => handleTargetTypeChange("internal")}
              className={cn(
                "relative flex flex-col items-center gap-2 rounded-lg border-2 p-3 transition-all",
                targetType === "internal" ? "border-primary bg-primary/10" : "border-border hover:border-input",
              )}
            >
              <Database className={cn("h-5 w-5", targetType === "internal" ? "text-primary" : "text-muted-foreground/70")} />
              <span
                className={cn("text-xs font-medium", targetType === "internal" ? "text-primary" : "text-muted-foreground")}
              >
                내부 DB
              </span>
              {targetType === "internal" && <Check className="absolute top-2 right-2 h-4 w-4 text-primary" />}
            </button>

            <button
              type="button"
              onClick={() => handleTargetTypeChange("external")}
              className={cn(
                "relative flex flex-col items-center gap-2 rounded-lg border-2 p-3 transition-all",
                targetType === "external" ? "border-emerald-500 bg-emerald-50" : "border-border hover:border-input",
              )}
            >
              <Globe className={cn("h-5 w-5", targetType === "external" ? "text-emerald-600" : "text-muted-foreground/70")} />
              <span
                className={cn("text-xs font-medium", targetType === "external" ? "text-emerald-700" : "text-muted-foreground")}
              >
                외부 DB
              </span>
              {targetType === "external" && <Check className="absolute top-2 right-2 h-4 w-4 text-emerald-600" />}
            </button>

            <button
              type="button"
              onClick={() => handleTargetTypeChange("api")}
              className={cn(
                "relative flex flex-col items-center gap-2 rounded-lg border-2 p-3 transition-all",
                targetType === "api" ? "border-purple-500 bg-purple-50" : "border-border hover:border-input",
              )}
            >
              <Link2 className={cn("h-5 w-5", targetType === "api" ? "text-purple-600" : "text-muted-foreground/70")} />
              <span className={cn("text-xs font-medium", targetType === "api" ? "text-purple-700" : "text-muted-foreground")}>
                REST API
              </span>
              {targetType === "api" && <Check className="absolute top-2 right-2 h-4 w-4 text-purple-600" />}
            </button>
          </div>
        </div>

        {/* 기본 정보 */}
        <div>
          <h3 className="mb-3 text-sm font-semibold">기본 정보</h3>

          <div className="space-y-3">
            <div>
              <Label htmlFor="displayName" className="text-xs">
                표시 이름
              </Label>
              <Input
                id="displayName"
                value={displayName}
                onChange={(e) => setDisplayName(e.target.value)}
                className="mt-1"
                placeholder="노드 표시 이름"
              />
            </div>

            {/* 🔥 타겟 타입에 따른 조건부 렌더링 */}
            {targetType === "internal" && (
              <>
                {/* 타겟 테이블 Combobox */}
                <div>
                  <Label className="text-xs">타겟 테이블</Label>
                  <Popover open={tablesOpen} onOpenChange={setTablesOpen}>
                    <PopoverTrigger asChild>
                      <Button
                        variant="outline"
                        role="combobox"
                        aria-expanded={tablesOpen}
                        className="mt-1 w-full justify-between"
                        disabled={tablesLoading}
                      >
                        {tablesLoading ? (
                          <span className="text-muted-foreground">로딩 중...</span>
                        ) : targetTable ? (
                          <span className="truncate">{selectedTableLabel}</span>
                        ) : (
                          <span className="text-muted-foreground">테이블을 선택하세요</span>
                        )}
                        <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                      </Button>
                    </PopoverTrigger>
                    <PopoverContent className="w-[320px] p-0" align="start">
                      <Command>
                        <CommandInput placeholder="테이블 검색..." className="h-9" />
                        <CommandList>
                          <CommandEmpty>검색 결과가 없습니다.</CommandEmpty>
                          <CommandGroup>
                            <ScrollArea className="h-[300px]">
                              {tables.map((table) => (
                                <CommandItem
                                  key={table.tableName}
                                  value={`${table.label} ${table.tableName} ${table.description}`}
                                  onSelect={() => handleTableSelect(table.tableName)}
                                  className="cursor-pointer"
                                >
                                  <Check
                                    className={cn(
                                      "mr-2 h-4 w-4",
                                      targetTable === table.tableName ? "opacity-100" : "opacity-0",
                                    )}
                                  />
                                  <div className="flex flex-col">
                                    <span className="font-medium">{table.label}</span>
                                    {table.label !== table.tableName && (
                                      <span className="text-muted-foreground text-xs">{table.tableName}</span>
                                    )}
                                    {table.description && (
                                      <span className="text-muted-foreground text-xs">{table.description}</span>
                                    )}
                                  </div>
                                </CommandItem>
                              ))}
                            </ScrollArea>
                          </CommandGroup>
                        </CommandList>
                      </Command>
                    </PopoverContent>
                  </Popover>
                  {targetTable && selectedTableLabel !== targetTable && (
                    <p className="text-muted-foreground mt-1 text-xs">
                      실제 테이블명: <code className="rounded bg-muted px-1 py-0.5">{targetTable}</code>
                    </p>
                  )}
                </div>
              </>
            )}

            {/* 🔥 외부 DB 타입 UI */}
            {targetType === "external" && (
              <>
                {/* 외부 커넥션 선택 */}
                <div>
                  <Label className="text-xs">외부 DB 커넥션</Label>
                  <Select
                    value={selectedExternalConnectionId?.toString()}
                    onValueChange={(value) => {
                      const connectionId = parseInt(value);
                      setSelectedExternalConnectionId(connectionId);
                      setExternalTargetTable(undefined); // 테이블 초기화

                      const selectedConnection = externalConnections.find((c) => c.id === connectionId);
                      updateNode(nodeId, {
                        targetType,
                        displayName,
                        externalConnectionId: connectionId,
                        externalConnectionName: selectedConnection?.connection_name,
                        externalDbType: selectedConnection?.db_type,
                        externalTargetTable: undefined,
                        fieldMappings,
                      });
                    }}
                    disabled={externalConnectionsLoading}
                  >
                    <SelectTrigger className="mt-1">
                      <SelectValue placeholder="외부 커넥션을 선택하세요" />
                    </SelectTrigger>
                    <SelectContent>
                      {externalConnections.map((conn) => (
                        <SelectItem key={conn.id} value={conn.id.toString()}>
                          <div className="flex items-center gap-2">
                            <span>{conn.db_type.toUpperCase()}</span>
                            <span>-</span>
                            <span>{conn.connection_name}</span>
                          </div>
                        </SelectItem>
                      ))}
                    </SelectContent>
                  </Select>
                  {externalConnectionsLoading && <p className="text-muted-foreground mt-1 text-xs">로딩 중...</p>}
                  {externalConnections.length === 0 && !externalConnectionsLoading && (
                    <p className="mt-1 text-xs text-amber-600">⚠️ 테스트에 성공한 외부 커넥션이 없습니다.</p>
                  )}
                </div>

                {/* 외부 테이블 선택 */}
                {selectedExternalConnectionId && (
                  <div>
                    <Label className="text-xs">외부 테이블</Label>
                    <Select
                      value={externalTargetTable}
                      onValueChange={(value) => {
                        setExternalTargetTable(value);
                        updateNode(nodeId, {
                          targetType,
                          displayName,
                          externalConnectionId: selectedExternalConnectionId,
                          externalTargetTable: value,
                          fieldMappings,
                        });
                      }}
                      disabled={externalTablesLoading}
                    >
                      <SelectTrigger className="mt-1">
                        <SelectValue placeholder="테이블을 선택하세요" />
                      </SelectTrigger>
                      <SelectContent>
                        {externalTables.map((table) => (
                          <SelectItem key={table.table_name} value={table.table_name}>
                            {table.table_name}
                            {table.table_schema && table.table_schema !== "public" && (
                              <span className="text-muted-foreground ml-2 text-xs">({table.table_schema})</span>
                            )}
                          </SelectItem>
                        ))}
                      </SelectContent>
                    </Select>
                    {externalTablesLoading && <p className="text-muted-foreground mt-1 text-xs">로딩 중...</p>}
                  </div>
                )}

                {/* 외부 컬럼 정보 표시 */}
                {selectedExternalConnectionId && externalTargetTable && externalColumns.length > 0 && (
                  <div className="rounded-lg border bg-muted p-3">
                    <p className="text-xs font-medium text-foreground">타겟 컬럼 ({externalColumns.length}개)</p>
                    <div className="mt-2 max-h-[150px] space-y-1 overflow-y-auto">
                      {externalColumns.map((col) => (
                        <div key={col.column_name} className="flex items-center justify-between text-xs">
                          <span className="font-mono text-foreground">{col.column_name}</span>
                          <span className="text-muted-foreground">{col.data_type}</span>
                        </div>
                      ))}
                    </div>
                  </div>
                )}
              </>
            )}

            {/* 🔥 REST API 타입 UI (추후 구현) */}
            {targetType === "api" && (
              <div className="space-y-4">
                {/* API 엔드포인트 */}
                <div>
                  <Label className="mb-1.5 block text-xs font-medium">API 엔드포인트</Label>
                  <Input
                    placeholder="https://api.example.com/v1/users"
                    value={apiEndpoint}
                    onChange={(e) => {
                      setApiEndpoint(e.target.value);
                      updateNode(nodeId, { apiEndpoint: e.target.value });
                    }}
                    className="h-8 text-xs"
                  />
                </div>

                {/* HTTP 메서드 */}
                <div>
                  <Label className="mb-1.5 block text-xs font-medium">HTTP 메서드</Label>
                  <Select
                    value={apiMethod}
                    onValueChange={(value: "POST" | "PUT" | "PATCH") => {
                      setApiMethod(value);
                      updateNode(nodeId, { apiMethod: value });
                    }}
                  >
                    <SelectTrigger className="h-8 text-xs">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="POST">POST</SelectItem>
                      <SelectItem value="PUT">PUT</SelectItem>
                      <SelectItem value="PATCH">PATCH</SelectItem>
                    </SelectContent>
                  </Select>
                </div>

                {/* 인증 타입 */}
                <div>
                  <Label className="mb-1.5 block text-xs font-medium">인증 방식</Label>
                  <Select
                    value={apiAuthType}
                    onValueChange={(value: "none" | "basic" | "bearer" | "apikey") => {
                      setApiAuthType(value);
                      updateNode(nodeId, { apiAuthType: value });
                    }}
                  >
                    <SelectTrigger className="h-8 text-xs">
                      <SelectValue />
                    </SelectTrigger>
                    <SelectContent>
                      <SelectItem value="none">인증 없음</SelectItem>
                      <SelectItem value="bearer">Bearer Token</SelectItem>
                      <SelectItem value="basic">Basic Auth</SelectItem>
                      <SelectItem value="apikey">API Key</SelectItem>
                    </SelectContent>
                  </Select>
                </div>

                {/* 인증 설정 */}
                {apiAuthType !== "none" && (
                  <div className="space-y-2 rounded border bg-muted p-3">
                    <Label className="block text-xs font-medium">인증 정보</Label>

                    {apiAuthType === "bearer" && (
                      <Input
                        placeholder="Bearer Token"
                        value={(apiAuthConfig as any)?.token || ""}
                        onChange={(e) => {
                          const newConfig = { token: e.target.value };
                          setApiAuthConfig(newConfig);
                          updateNode(nodeId, { apiAuthConfig: newConfig });
                        }}
                        className="h-8 text-xs"
                      />
                    )}

                    {apiAuthType === "basic" && (
                      <div className="space-y-2">
                        <Input
                          placeholder="사용자명"
                          value={(apiAuthConfig as any)?.username || ""}
                          onChange={(e) => {
                            const newConfig = { ...(apiAuthConfig as any), username: e.target.value };
                            setApiAuthConfig(newConfig);
                            updateNode(nodeId, { apiAuthConfig: newConfig });
                          }}
                          className="h-8 text-xs"
                        />
                        <Input
                          type="password"
                          placeholder="비밀번호"
                          value={(apiAuthConfig as any)?.password || ""}
                          onChange={(e) => {
                            const newConfig = { ...(apiAuthConfig as any), password: e.target.value };
                            setApiAuthConfig(newConfig);
                            updateNode(nodeId, { apiAuthConfig: newConfig });
                          }}
                          className="h-8 text-xs"
                        />
                      </div>
                    )}

                    {apiAuthType === "apikey" && (
                      <div className="space-y-2">
                        <Input
                          placeholder="헤더 이름 (예: X-API-Key)"
                          value={(apiAuthConfig as any)?.headerName || ""}
                          onChange={(e) => {
                            const newConfig = { ...(apiAuthConfig as any), headerName: e.target.value };
                            setApiAuthConfig(newConfig);
                            updateNode(nodeId, { apiAuthConfig: newConfig });
                          }}
                          className="h-8 text-xs"
                        />
                        <Input
                          placeholder="API Key"
                          value={(apiAuthConfig as any)?.apiKey || ""}
                          onChange={(e) => {
                            const newConfig = { ...(apiAuthConfig as any), apiKey: e.target.value };
                            setApiAuthConfig(newConfig);
                            updateNode(nodeId, { apiAuthConfig: newConfig });
                          }}
                          className="h-8 text-xs"
                        />
                      </div>
                    )}
                  </div>
                )}

                {/* 커스텀 헤더 */}
                <div>
                  <Label className="mb-1.5 block text-xs font-medium">커스텀 헤더 (선택사항)</Label>
                  <div className="space-y-2 rounded border bg-muted p-3">
                    {Object.entries(apiHeaders).map(([key, value], index) => (
                      <div key={index} className="flex gap-2">
                        <Input
                          placeholder="헤더 이름"
                          value={key}
                          onChange={(e) => {
                            const newHeaders = { ...apiHeaders };
                            delete newHeaders[key];
                            newHeaders[e.target.value] = value;
                            setApiHeaders(newHeaders);
                            updateNode(nodeId, { apiHeaders: newHeaders });
                          }}
                          className="h-7 flex-1 text-xs"
                        />
                        <Input
                          placeholder="헤더 값"
                          value={value}
                          onChange={(e) => {
                            const newHeaders = { ...apiHeaders, [key]: e.target.value };
                            setApiHeaders(newHeaders);
                            updateNode(nodeId, { apiHeaders: newHeaders });
                          }}
                          className="h-7 flex-1 text-xs"
                        />
                        <Button
                          size="sm"
                          variant="ghost"
                          onClick={() => {
                            const newHeaders = { ...apiHeaders };
                            delete newHeaders[key];
                            setApiHeaders(newHeaders);
                            updateNode(nodeId, { apiHeaders: newHeaders });
                          }}
                          className="h-7 w-7 p-0"
                        >
                          <Trash2 className="h-3 w-3" />
                        </Button>
                      </div>
                    ))}
                    <Button
                      size="sm"
                      variant="outline"
                      onClick={() => {
                        const newHeaders = { ...apiHeaders, "": "" };
                        setApiHeaders(newHeaders);
                        updateNode(nodeId, { apiHeaders: newHeaders });
                      }}
                      className="h-7 w-full text-xs"
                    >
                      <Plus className="mr-1 h-3 w-3" />
                      헤더 추가
                    </Button>
                  </div>
                </div>

                {/* 요청 바디 설정 */}
                <div>
                  <Label className="mb-1.5 block text-xs font-medium">
                    요청 바디 템플릿
                    <span className="ml-1 text-muted-foreground">{"{{fieldName}}"}으로 소스 필드 참조</span>
                  </Label>
                  <textarea
                    placeholder={'{\n  "name": "{{name}}",\n  "email": "{{email}}",\n  "age": "{{age}}"\n}'}
                    value={apiBodyTemplate}
                    onChange={(e) => {
                      setApiBodyTemplate(e.target.value);
                      updateNode(nodeId, { apiBodyTemplate: e.target.value });
                    }}
                    className="w-full rounded border p-2 font-mono text-xs"
                    rows={8}
                  />
                  <p className="mt-1 text-xs text-muted-foreground">
                    소스 데이터의 필드명을 {"{{필드명}}"} 형태로 참조할 수 있습니다.
                  </p>
                </div>
              </div>
            )}
          </div>
        </div>

        {/* 필드 매핑 (REST API 타입에서는 숨김) */}
        {targetType !== "api" && (
          <div>
            <div className="mb-2 flex items-center justify-between">
              <h3 className="text-sm font-semibold">필드 매핑</h3>
              <Button size="sm" variant="outline" onClick={handleAddMapping} className="h-7">
                <Plus className="mr-1 h-3 w-3" />
                추가
              </Button>
            </div>

            {/* 🔥 로딩 상태 (타입별) */}
            {(columnsLoading || externalColumnsLoading) && (
              <div className="rounded border p-3 text-center text-xs text-muted-foreground">컬럼 목록을 불러오는 중...</div>
            )}

            {/* 🔥 테이블 미선택 경고 (타입별) */}
            {targetType === "internal" && !targetTable && !columnsLoading && (
              <div className="rounded border border-dashed bg-amber-50 p-3 text-center text-xs text-yellow-700">
                ⚠️ 먼저 타겟 테이블을 선택하세요
              </div>
            )}

            {targetType === "external" && !externalTargetTable && !externalColumnsLoading && (
              <div className="rounded border border-dashed bg-amber-50 p-3 text-center text-xs text-yellow-700">
                ⚠️ 먼저 외부 커넥션과 테이블을 선택하세요
              </div>
            )}

            {/* 🔥 컬럼 로드 실패 (타입별) */}
            {targetType === "internal" && targetTable && !columnsLoading && targetColumns.length === 0 && (
              <div className="rounded border border-dashed bg-destructive/10 p-3 text-center text-xs text-destructive">
                ❌ 컬럼 정보를 불러올 수 없습니다
              </div>
            )}

            {targetType === "external" &&
              externalTargetTable &&
              !externalColumnsLoading &&
              externalColumns.length === 0 && (
                <div className="rounded border border-dashed bg-destructive/10 p-3 text-center text-xs text-destructive">
                  ❌ 외부 DB 컬럼 정보를 불러올 수 없습니다
                </div>
              )}

            {/* 🔥 필드 매핑 UI (타입별 컬럼 사용) */}
            {((targetType === "internal" && targetTable && targetColumns.length > 0) ||
              (targetType === "external" && externalTargetTable && externalColumns.length > 0)) && (
              <>
                {fieldMappings.length > 0 ? (
                  <div className="space-y-3">
                    {fieldMappings.map((mapping, index) => (
                      <div key={index} className="rounded border bg-muted p-3">
                        <div className="mb-2 flex items-center justify-between">
                          <span className="text-xs font-medium text-foreground">매핑 #{index + 1}</span>
                          <Button
                            size="sm"
                            variant="ghost"
                            onClick={() => handleRemoveMapping(index)}
                            className="h-6 w-6 p-0 text-destructive hover:text-destructive"
                          >
                            <Trash2 className="h-3 w-3" />
                          </Button>
                        </div>

                        <div className="space-y-2">
                          {/* 🔥 값 생성 유형 선택 */}
                          <div>
                            <Label className="text-xs text-muted-foreground">값 생성 방식</Label>
                            <div className="mt-1 grid grid-cols-3 gap-1">
                              <button
                                type="button"
                                onClick={() => handleMappingChange(index, "valueType", "source")}
                                className={cn(
                                  "rounded border px-2 py-1 text-xs transition-all",
                                  (mapping.valueType === "source" || !mapping.valueType)
                                    ? "border-primary bg-primary/10 text-primary"
                                    : "border-border hover:border-input",
                                )}
                              >
                                소스 필드
                              </button>
                              <button
                                type="button"
                                onClick={() => handleMappingChange(index, "valueType", "static")}
                                className={cn(
                                  "rounded border px-2 py-1 text-xs transition-all",
                                  mapping.valueType === "static"
                                    ? "border-orange-500 bg-amber-50 text-orange-700"
                                    : "border-border hover:border-input",
                                )}
                              >
                                고정값
                              </button>
                              <button
                                type="button"
                                onClick={() => handleMappingChange(index, "valueType", "autoGenerate")}
                                className={cn(
                                  "rounded border px-2 py-1 text-xs transition-all flex items-center justify-center gap-1",
                                  mapping.valueType === "autoGenerate"
                                    ? "border-purple-500 bg-purple-50 text-purple-700"
                                    : "border-border hover:border-input",
                                )}
                              >
                                <Sparkles className="h-3 w-3" />
                                자동생성
                              </button>
                            </div>
                          </div>

                          {/* 🔥 소스 필드 입력/선택 (valueType === "source" 일 때만) */}
                          {(mapping.valueType === "source" || !mapping.valueType) && (
                            <div>
                              <Label className="text-xs text-muted-foreground">
                                소스 필드
                                {hasRestAPISource && <span className="ml-1 text-teal-600">(REST API - 직접 입력)</span>}
                              </Label>
                              {hasRestAPISource ? (
                                // REST API 소스인 경우: 직접 입력
                                <Input
                                  value={mapping.sourceField || ""}
                                  onChange={(e) => handleMappingChange(index, "sourceField", e.target.value || null)}
                                  placeholder="필드명 입력 (예: userId, userName)"
                                  className="mt-1 h-8 text-xs"
                                />
                              ) : (
                                // 일반 소스인 경우: Combobox 선택
                                <Popover
                                  open={mappingSourceFieldsOpenState[index]}
                                  onOpenChange={(open) => {
                                    const newState = [...mappingSourceFieldsOpenState];
                                    newState[index] = open;
                                    setMappingSourceFieldsOpenState(newState);
                                  }}
                                >
                                  <PopoverTrigger asChild>
                                    <Button
                                      variant="outline"
                                      role="combobox"
                                      aria-expanded={mappingSourceFieldsOpenState[index]}
                                      className="mt-1 h-8 w-full justify-between text-xs sm:h-10 sm:text-sm"
                                    >
                                      {mapping.sourceField
                                        ? (() => {
                                            const field = sourceFields.find((f) => f.name === mapping.sourceField);
                                            return (
                                              <div className="flex items-center justify-between gap-2 overflow-hidden">
                                                <span className="truncate font-medium">
                                                  {field?.label || mapping.sourceField}
                                                </span>
                                                {field?.label && field.label !== field.name && (
                                                  <span className="text-muted-foreground font-mono text-xs">
                                                    {field.name}
                                                  </span>
                                                )}
                                              </div>
                                            );
                                          })()
                                        : "소스 필드 선택"}
                                      <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                                    </Button>
                                  </PopoverTrigger>
                                  <PopoverContent
                                    className="p-0"
                                    style={{ width: "var(--radix-popover-trigger-width)" }}
                                    align="start"
                                  >
                                    <Command>
                                      <CommandInput placeholder="소스 필드 검색..." className="text-xs sm:text-sm" />
                                      <CommandList>
                                        <CommandEmpty className="text-xs sm:text-sm">
                                          필드를 찾을 수 없습니다.
                                        </CommandEmpty>
                                        <CommandGroup>
                                          {sourceFields.map((field) => (
                                            <CommandItem
                                              key={field.name}
                                              value={field.name}
                                              onSelect={(currentValue) => {
                                                handleMappingChange(index, "sourceField", currentValue || null);
                                                const newState = [...mappingSourceFieldsOpenState];
                                                newState[index] = false;
                                                setMappingSourceFieldsOpenState(newState);
                                              }}
                                              className="text-xs sm:text-sm"
                                            >
                                              <Check
                                                className={cn(
                                                  "mr-2 h-4 w-4",
                                                  mapping.sourceField === field.name ? "opacity-100" : "opacity-0",
                                                )}
                                              />
                                              <div className="flex flex-col">
                                                <span className="font-medium">{field.label || field.name}</span>
                                                {field.label && field.label !== field.name && (
                                                  <span className="text-muted-foreground font-mono text-[10px]">
                                                    {field.name}
                                                  </span>
                                                )}
                                              </div>
                                            </CommandItem>
                                          ))}
                                        </CommandGroup>
                                      </CommandList>
                                    </Command>
                                  </PopoverContent>
                                </Popover>
                              )}
                              {hasRestAPISource && (
                                <p className="mt-1 text-xs text-muted-foreground">API 응답 JSON의 필드명을 입력하세요</p>
                              )}
                            </div>
                          )}

                          {/* 🔥 고정값 입력 (valueType === "static" 일 때) */}
                          {mapping.valueType === "static" && (
                            <div>
                              <Label className="text-xs text-muted-foreground">고정값</Label>
                              <Input
                                value={mapping.staticValue || ""}
                                onChange={(e) => handleMappingChange(index, "staticValue", e.target.value || undefined)}
                                placeholder="고정값 입력"
                                className="mt-1 h-8 text-xs"
                              />
                            </div>
                          )}

                          {/* 🔥 채번 규칙 선택 (valueType === "autoGenerate" 일 때) */}
                          {mapping.valueType === "autoGenerate" && (
                            <div>
                              <Label className="text-xs text-muted-foreground">
                                채번 규칙
                                {numberingRulesLoading && <span className="ml-1 text-muted-foreground/70">(로딩 중...)</span>}
                              </Label>
                              <Popover
                                open={mappingNumberingRulesOpenState[index]}
                                onOpenChange={(open) => {
                                  const newState = [...mappingNumberingRulesOpenState];
                                  newState[index] = open;
                                  setMappingNumberingRulesOpenState(newState);
                                }}
                              >
                                <PopoverTrigger asChild>
                                  <Button
                                    variant="outline"
                                    role="combobox"
                                    aria-expanded={mappingNumberingRulesOpenState[index]}
                                    className="mt-1 h-8 w-full justify-between text-xs sm:h-10 sm:text-sm"
                                    disabled={numberingRulesLoading || numberingRules.length === 0}
                                  >
                                    {mapping.numberingRuleId
                                      ? (() => {
                                          const rule = numberingRules.find((r) => r.ruleId === mapping.numberingRuleId);
                                          return (
                                            <div className="flex items-center gap-2 overflow-hidden">
                                              <Sparkles className="h-3 w-3 text-purple-500" />
                                              <span className="truncate font-medium">
                                                {rule?.ruleName || mapping.numberingRuleName || mapping.numberingRuleId}
                                              </span>
                                            </div>
                                          );
                                        })()
                                      : "채번 규칙 선택"}
                                    <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                                  </Button>
                                </PopoverTrigger>
                                <PopoverContent
                                  className="p-0"
                                  style={{ width: "var(--radix-popover-trigger-width)" }}
                                  align="start"
                                >
                                  <Command>
                                    <CommandInput placeholder="채번 규칙 검색..." className="text-xs sm:text-sm" />
                                    <CommandList>
                                      <CommandEmpty className="text-xs sm:text-sm">
                                        채번 규칙을 찾을 수 없습니다.
                                      </CommandEmpty>
                                      <CommandGroup>
                                        {numberingRules.map((rule) => (
                                          <CommandItem
                                            key={rule.ruleId}
                                            value={rule.ruleId}
                                            onSelect={(currentValue) => {
                                              handleMappingChange(index, "numberingRuleId", currentValue);
                                              const newState = [...mappingNumberingRulesOpenState];
                                              newState[index] = false;
                                              setMappingNumberingRulesOpenState(newState);
                                            }}
                                            className="text-xs sm:text-sm"
                                          >
                                            <Check
                                              className={cn(
                                                "mr-2 h-4 w-4",
                                                mapping.numberingRuleId === rule.ruleId ? "opacity-100" : "opacity-0",
                                              )}
                                            />
                                            <div className="flex flex-col">
                                              <span className="font-medium">{rule.ruleName}</span>
                                              <span className="text-muted-foreground font-mono text-[10px]">
                                                {rule.ruleId}
                                                {rule.tableName && ` - ${rule.tableName}`}
                                              </span>
                                            </div>
                                          </CommandItem>
                                        ))}
                                      </CommandGroup>
                                    </CommandList>
                                  </Command>
                                </PopoverContent>
                              </Popover>
                              {numberingRules.length === 0 && !numberingRulesLoading && (
                                <p className="mt-1 text-xs text-amber-600">
                                  등록된 채번 규칙이 없습니다. 시스템 관리에서 먼저 채번 규칙을 생성하세요.
                                </p>
                              )}
                            </div>
                          )}

                          <div className="flex items-center justify-center py-1">
                            <ArrowRight className="h-4 w-4 text-emerald-600" />
                          </div>

                          {/* 타겟 필드 Combobox (🔥 타입별 컬럼 사용) */}
                          <div>
                            <Label className="text-xs text-muted-foreground">타겟 필드</Label>
                            <Popover
                              open={mappingTargetFieldsOpenState[index]}
                              onOpenChange={(open) => {
                                const newState = [...mappingTargetFieldsOpenState];
                                newState[index] = open;
                                setMappingTargetFieldsOpenState(newState);
                              }}
                            >
                              <PopoverTrigger asChild>
                                <Button
                                  variant="outline"
                                  role="combobox"
                                  aria-expanded={mappingTargetFieldsOpenState[index]}
                                  className="mt-1 h-8 w-full justify-between text-xs sm:h-10 sm:text-sm"
                                >
                                  {mapping.targetField
                                    ? (() => {
                                        if (targetType === "internal") {
                                          const col = targetColumns.find((c) => c.columnName === mapping.targetField);
                                          return (
                                            <div className="flex items-center justify-between gap-2 overflow-hidden">
                                              <span className="truncate font-mono">
                                                {col?.columnLabel || mapping.targetField}
                                              </span>
                                              <span className="text-muted-foreground text-xs">
                                                {col?.dataType}
                                                {col && !col.isNullable && <span className="text-destructive">*</span>}
                                              </span>
                                            </div>
                                          );
                                        } else {
                                          const col = externalColumns.find(
                                            (c) => c.column_name === mapping.targetField,
                                          );
                                          return (
                                            <div className="flex items-center justify-between gap-2 overflow-hidden">
                                              <span className="truncate font-mono">
                                                {col?.column_name || mapping.targetField}
                                              </span>
                                              <span className="text-muted-foreground text-xs">{col?.data_type}</span>
                                            </div>
                                          );
                                        }
                                      })()
                                    : "타겟 필드 선택"}
                                  <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
                                </Button>
                              </PopoverTrigger>
                              <PopoverContent
                                className="p-0"
                                style={{ width: "var(--radix-popover-trigger-width)" }}
                                align="start"
                              >
                                <Command>
                                  <CommandInput placeholder="타겟 필드 검색..." className="text-xs sm:text-sm" />
                                  <CommandList>
                                    <CommandEmpty className="text-xs sm:text-sm">필드를 찾을 수 없습니다.</CommandEmpty>
                                    <CommandGroup>
                                      {/* 🔥 내부 DB 컬럼 */}
                                      {targetType === "internal" &&
                                        targetColumns.map((col) => (
                                          <CommandItem
                                            key={col.columnName}
                                            value={col.columnName}
                                            onSelect={(currentValue) => {
                                              handleMappingChange(index, "targetField", currentValue);
                                              const newState = [...mappingTargetFieldsOpenState];
                                              newState[index] = false;
                                              setMappingTargetFieldsOpenState(newState);
                                            }}
                                            className="text-xs sm:text-sm"
                                          >
                                            <Check
                                              className={cn(
                                                "mr-2 h-4 w-4",
                                                mapping.targetField === col.columnName ? "opacity-100" : "opacity-0",
                                              )}
                                            />
                                            <div className="flex flex-col">
                                              <span className="font-mono font-medium">
                                                {col.columnLabel || col.columnName}
                                              </span>
                                              <span className="text-muted-foreground text-[10px]">
                                                {col.dataType}
                                                {col.columnDefault ? (
                                                  <span className="text-primary"> 🔵기본값</span>
                                                ) : (
                                                  !col.isNullable && <span className="text-destructive"> *필수</span>
                                                )}
                                              </span>
                                            </div>
                                          </CommandItem>
                                        ))}

                                      {/* 🔥 외부 DB 컬럼 */}
                                      {targetType === "external" &&
                                        externalColumns.map((col) => (
                                          <CommandItem
                                            key={col.column_name}
                                            value={col.column_name}
                                            onSelect={(currentValue) => {
                                              handleMappingChange(index, "targetField", currentValue);
                                              const newState = [...mappingTargetFieldsOpenState];
                                              newState[index] = false;
                                              setMappingTargetFieldsOpenState(newState);
                                            }}
                                            className="text-xs sm:text-sm"
                                          >
                                            <Check
                                              className={cn(
                                                "mr-2 h-4 w-4",
                                                mapping.targetField === col.column_name ? "opacity-100" : "opacity-0",
                                              )}
                                            />
                                            <div className="flex flex-col">
                                              <span className="font-mono font-medium">{col.column_name}</span>
                                              <span className="text-muted-foreground text-[10px]">{col.data_type}</span>
                                            </div>
                                          </CommandItem>
                                        ))}
                                    </CommandGroup>
                                  </CommandList>
                                </Command>
                              </PopoverContent>
                            </Popover>
                          </div>
                        </div>
                      </div>
                    ))}
                  </div>
                ) : (
                  <div className="rounded border border-dashed p-4 text-center text-xs text-muted-foreground/70">
                    필드 매핑이 없습니다. "추가" 버튼을 클릭하세요.
                  </div>
                )}
              </>
            )}
          </div>
        )}

        {/* 안내 */}
        <div className="rounded bg-emerald-50 p-3 text-xs text-emerald-700">
          <p>테이블과 필드는 실제 데이터베이스에서 조회됩니다.</p>
          <p className="mt-1">값 생성 방식: 소스 필드(입력값 연결) / 고정값(직접 입력) / 자동생성(채번 규칙)</p>
        </div>
      </div>
    </div>
  );
}
