"use client";

import React, { useState, useRef, useEffect } from "react";
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter,
} from "@/components/ui/dialog";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from "@/components/ui/select";
import { toast } from "sonner";
import {
  Upload,
  FileSpreadsheet,
  AlertCircle,
  CheckCircle2,
  ArrowRight,
  Zap,
  Copy,
} from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { importFromExcel, getExcelSheetNames } from "@/lib/utils/excelExport";
import { DynamicFormApi } from "@/lib/api/dynamicForm";
import { getTableSchema, TableColumn } from "@/lib/api/tableSchema";
import { cn } from "@/lib/utils";
import { findMappingByColumns, saveMappingTemplate } from "@/lib/api/excelMapping";
import { EditableSpreadsheet } from "./EditableSpreadsheet";

// 마스터-디테일 엑셀 업로드 설정 (버튼 설정에서 설정)
export interface MasterDetailExcelConfig {
  // 테이블 정보
  masterTable?: string;
  detailTable?: string;
  masterKeyColumn?: string;
  detailFkColumn?: string;
  // 채번
  numberingRuleId?: string;
  // 업로드 전 사용자가 선택할 마스터 테이블 필드
  masterSelectFields?: Array<{
    columnName: string;
    columnLabel: string;
    required: boolean;
    inputType: "entity" | "date" | "text" | "select";
    referenceTable?: string;
    referenceColumn?: string;
    displayColumn?: string;
  }>;
  // 엑셀에서 매핑할 디테일 테이블 필드
  detailExcelFields?: Array<{
    columnName: string;
    columnLabel: string;
    required: boolean;
  }>;
  masterDefaults?: Record<string, any>;
  detailDefaults?: Record<string, any>;
}

export interface ExcelUploadModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  tableName: string;
  uploadMode?: "insert" | "update" | "upsert";
  keyColumn?: string;
  onSuccess?: () => void;
  userId?: string;
  // 마스터-디테일 지원
  screenId?: number;
  isMasterDetail?: boolean;
  masterDetailRelation?: {
    masterTable: string;
    detailTable: string;
    masterKeyColumn: string;
    detailFkColumn: string;
    masterColumns: Array<{ name: string; label: string; inputType: string; isFromMaster: boolean }>;
    detailColumns: Array<{ name: string; label: string; inputType: string; isFromMaster: boolean }>;
  };
  // 마스터-디테일 엑셀 업로드 설정
  masterDetailExcelConfig?: MasterDetailExcelConfig;
  // 업로드 후 제어 실행 설정
  afterUploadFlows?: Array<{ flowId: string; order: number }>;
}

interface ColumnMapping {
  excelColumn: string;
  systemColumn: string | null;
  // 중복 체크 설정 (해당 컬럼을 중복 체크 키로 사용할지)
  checkDuplicate?: boolean;
}

export const ExcelUploadModal: React.FC<ExcelUploadModalProps> = ({
  open,
  onOpenChange,
  tableName,
  uploadMode = "insert",
  keyColumn,
  onSuccess,
  userId = "guest",
  screenId,
  isMasterDetail = false,
  masterDetailRelation,
  masterDetailExcelConfig,
  // 업로드 후 제어 실행 설정
  afterUploadFlows,
}) => {
  const [currentStep, setCurrentStep] = useState(1);

  // 1단계: 파일 선택 & 미리보기
  const [file, setFile] = useState<File | null>(null);
  const [sheetNames, setSheetNames] = useState<string[]>([]);
  const [selectedSheet, setSelectedSheet] = useState<string>("");
  const [isDragOver, setIsDragOver] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [detectedRange, setDetectedRange] = useState<string>("");
  const [allData, setAllData] = useState<Record<string, any>[]>([]);
  const [displayData, setDisplayData] = useState<Record<string, any>[]>([]);

  // 2단계: 컬럼 매핑 + 매핑 템플릿 자동 적용
  const [isAutoMappingLoaded, setIsAutoMappingLoaded] = useState(false);
  const [excelColumns, setExcelColumns] = useState<string[]>([]);
  const [systemColumns, setSystemColumns] = useState<TableColumn[]>([]);
  const [columnMappings, setColumnMappings] = useState<ColumnMapping[]>([]);
  
  // 중복 처리 방법 (전역 설정)
  const [duplicateAction, setDuplicateAction] = useState<"overwrite" | "skip">("skip");

  // 3단계: 확인
  const [isUploading, setIsUploading] = useState(false);

  // 🆕 마스터-디테일 모드: 마스터 필드 입력값
  const [masterFieldValues, setMasterFieldValues] = useState<Record<string, any>>({});
  const [entitySearchData, setEntitySearchData] = useState<Record<string, any[]>>({});
  const [entitySearchLoading, setEntitySearchLoading] = useState<Record<string, boolean>>({});
  const [entityDisplayColumns, setEntityDisplayColumns] = useState<Record<string, string>>({});

  // 🆕 엔티티 참조 데이터 로드
  useEffect(() => {
    console.log("🔍 엔티티 데이터 로드 체크:", {
      masterSelectFields: masterDetailExcelConfig?.masterSelectFields,
      open,
      isMasterDetail,
    });

    if (!masterDetailExcelConfig?.masterSelectFields) return;

    const loadEntityData = async () => {
      const { apiClient } = await import("@/lib/api/client");
      const { DynamicFormApi } = await import("@/lib/api/dynamicForm");

      for (const field of masterDetailExcelConfig.masterSelectFields!) {
        console.log("🔍 필드 처리:", field);
        
        if (field.inputType === "entity") {
          setEntitySearchLoading((prev) => ({ ...prev, [field.columnName]: true }));
          try {
            let refTable = field.referenceTable;
            console.log("🔍 초기 refTable:", refTable);

            let displayCol = field.displayColumn;

            // referenceTable 또는 displayColumn이 없으면 DB에서 동적으로 조회
            if ((!refTable || !displayCol) && masterDetailExcelConfig.masterTable) {
              console.log("🔍 DB에서 referenceTable/displayColumn 조회 시도:", masterDetailExcelConfig.masterTable);
              const colResponse = await apiClient.get(
                `/table-management/tables/${masterDetailExcelConfig.masterTable}/columns`
              );
              console.log("🔍 컬럼 조회 응답:", colResponse.data);
              
              if (colResponse.data?.success && colResponse.data?.data?.columns) {
                const colInfo = colResponse.data.data.columns.find(
                  (c: any) => (c.columnName || c.column_name) === field.columnName
                );
                console.log("🔍 찾은 컬럼 정보:", colInfo);
                if (colInfo) {
                  if (!refTable) {
                    refTable = colInfo.referenceTable || colInfo.reference_table;
                    console.log("🔍 DB에서 가져온 refTable:", refTable);
                  }
                  if (!displayCol) {
                    displayCol = colInfo.displayColumn || colInfo.display_column;
                    console.log("🔍 DB에서 가져온 displayColumn:", displayCol);
                  }
                }
              }
            }

            // displayColumn 저장 (Select 렌더링 시 사용)
            if (displayCol) {
              setEntityDisplayColumns((prev) => ({ ...prev, [field.columnName]: displayCol }));
            }

            if (refTable) {
              console.log("🔍 엔티티 데이터 조회:", refTable);
              const response = await DynamicFormApi.getTableData(refTable, {
                page: 1,
                pageSize: 1000,
              });
              console.log("🔍 엔티티 데이터 응답:", response);
              // getTableData는 { success, data: [...] } 형식으로 반환
              const rows = response.data?.rows || response.data;
              if (response.success && rows && Array.isArray(rows)) {
                setEntitySearchData((prev) => ({
                  ...prev,
                  [field.columnName]: rows,
                }));
                console.log("✅ 엔티티 데이터 로드 성공:", field.columnName, rows.length, "개");
              }
            } else {
              console.warn("❌ 엔티티 필드의 referenceTable을 찾을 수 없음:", field.columnName);
            }
          } catch (error) {
            console.error("❌ 엔티티 데이터 로드 실패:", field.columnName, error);
          } finally {
            setEntitySearchLoading((prev) => ({ ...prev, [field.columnName]: false }));
          }
        }
      }
    };

    if (open && isMasterDetail && masterDetailExcelConfig?.masterSelectFields?.length > 0) {
      loadEntityData();
    }
  }, [open, isMasterDetail, masterDetailExcelConfig]);

  // 마스터-디테일 모드에서 마스터 필드 입력 여부 확인
  const isSimpleMasterDetailMode = isMasterDetail && masterDetailExcelConfig;
  const hasMasterSelectFields = isSimpleMasterDetailMode && 
    (masterDetailExcelConfig?.masterSelectFields?.length ?? 0) > 0;

  // 마스터 필드가 모두 입력되었는지 확인
  const isMasterFieldsValid = () => {
    if (!hasMasterSelectFields) return true;
    return masterDetailExcelConfig!.masterSelectFields!.every((field) => {
      if (!field.required) return true;
      const value = masterFieldValues[field.columnName];
      return value !== undefined && value !== null && value !== "";
    });
  };

  // 파일 선택 핸들러
  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const selectedFile = e.target.files?.[0];
    if (!selectedFile) return;
    await processFile(selectedFile);
  };

  // 파일 처리 공통 함수 (파일 선택 및 드래그 앤 드롭에서 공유)
  const processFile = async (selectedFile: File) => {
    const fileExtension = selectedFile.name.split(".").pop()?.toLowerCase();
    if (!["xlsx", "xls", "csv"].includes(fileExtension || "")) {
      toast.error("엑셀 파일만 업로드 가능합니다. (.xlsx, .xls, .csv)");
      return;
    }

    setFile(selectedFile);

    try {
      const sheets = await getExcelSheetNames(selectedFile);
      setSheetNames(sheets);
      setSelectedSheet(sheets[0] || "");

      const data = await importFromExcel(selectedFile, sheets[0]);
      setAllData(data);
      setDisplayData(data);

      if (data.length > 0) {
        const columns = Object.keys(data[0]);
        const lastCol = String.fromCharCode(64 + columns.length);
        setDetectedRange(`A1:${lastCol}${data.length + 1}`);
        setExcelColumns(columns);
      }

      toast.success(`파일이 선택되었습니다: ${selectedFile.name}`);
    } catch (error) {
      console.error("파일 읽기 오류:", error);
      toast.error("파일을 읽는 중 오류가 발생했습니다.");
      setFile(null);
    }
  };

  // 드래그 앤 드롭 핸들러
  const handleDragOver = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragOver(true);
  };

  const handleDragLeave = (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragOver(false);
  };

  const handleDrop = async (e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragOver(false);

    const droppedFile = e.dataTransfer.files?.[0];
    if (droppedFile) {
      await processFile(droppedFile);
    }
  };

  // 시트 변경 핸들러
  const handleSheetChange = async (sheetName: string) => {
    setSelectedSheet(sheetName);
    if (!file) return;

    try {
      const data = await importFromExcel(file, sheetName);
      setAllData(data);
      setDisplayData(data);

      if (data.length > 0) {
        const columns = Object.keys(data[0]);
        const lastCol = String.fromCharCode(64 + columns.length);
        setDetectedRange(`A1:${lastCol}${data.length + 1}`);
        setExcelColumns(columns);
      }
    } catch (error) {
      console.error("시트 읽기 오류:", error);
      toast.error("시트를 읽는 중 오류가 발생했습니다.");
    }
  };

  // 테이블 스키마 가져오기 (2단계 진입 시)
  useEffect(() => {
    if (currentStep === 2 && tableName) {
      loadTableSchema();
    }
  }, [currentStep, tableName]);

  // 테이블 생성 시 자동 생성되는 시스템 컬럼 (매핑에서 제외)
  const AUTO_GENERATED_COLUMNS = [
    "id",
    "created_date",
    "updated_date",
    "writer",
    "company_code",
  ];

  const loadTableSchema = async () => {
    try {
      console.log("🔍 테이블 스키마 로드 시작:", { tableName, isMasterDetail, isSimpleMasterDetailMode });

      let allColumns: TableColumn[] = [];

      // 🆕 마스터-디테일 간단 모드: 디테일 테이블 컬럼만 로드 (마스터 필드는 UI에서 선택)
      if (isSimpleMasterDetailMode && masterDetailRelation) {
        const { detailTable, detailFkColumn } = masterDetailRelation;
        
        console.log("📊 마스터-디테일 간단 모드 스키마 로드 (디테일만):", { detailTable });

        // 디테일 테이블 스키마만 로드 (마스터 정보는 UI에서 선택)
        const detailResponse = await getTableSchema(detailTable);
        if (detailResponse.success && detailResponse.data) {
          // 설정된 detailExcelFields가 있으면 해당 필드만, 없으면 전체
          const configuredFields = masterDetailExcelConfig?.detailExcelFields;
          
          const detailCols = detailResponse.data.columns
            .filter((col) => {
              // 자동 생성 컬럼, FK 컬럼 제외
              if (AUTO_GENERATED_COLUMNS.includes(col.name.toLowerCase())) return false;
              if (col.name === detailFkColumn) return false;
              
              // 설정된 필드가 있으면 해당 필드만
              if (configuredFields && configuredFields.length > 0) {
                return configuredFields.some((f) => f.columnName === col.name);
              }
              return true;
            })
            .map((col) => {
              // 설정에서 라벨 찾기
              const configField = configuredFields?.find((f) => f.columnName === col.name);
              return {
                ...col,
                label: configField?.columnLabel || col.label || col.name,
                originalName: col.name,
                sourceTable: detailTable,
              };
            });
          allColumns = detailCols;
        }

        console.log("✅ 마스터-디테일 간단 모드 컬럼 로드 완료:", allColumns.length);
      }
      // 🆕 마스터-디테일 기존 모드: 두 테이블의 컬럼 합치기
      else if (isMasterDetail && masterDetailRelation) {
        const { masterTable, detailTable, detailFkColumn } = masterDetailRelation;
        
        console.log("📊 마스터-디테일 스키마 로드:", { masterTable, detailTable });

        // 마스터 테이블 스키마
        const masterResponse = await getTableSchema(masterTable);
        if (masterResponse.success && masterResponse.data) {
          const masterCols = masterResponse.data.columns
            .filter((col) => !AUTO_GENERATED_COLUMNS.includes(col.name.toLowerCase()))
            .map((col) => ({
              ...col,
              // 유니크 키를 위해 테이블명 접두사 추가
              name: `${masterTable}.${col.name}`,
              label: `[마스터] ${col.label || col.name}`,
              originalName: col.name,
              sourceTable: masterTable,
            }));
          allColumns = [...allColumns, ...masterCols];
        }

        // 디테일 테이블 스키마 (FK 컬럼 제외)
        const detailResponse = await getTableSchema(detailTable);
        if (detailResponse.success && detailResponse.data) {
          const detailCols = detailResponse.data.columns
            .filter((col) => 
              !AUTO_GENERATED_COLUMNS.includes(col.name.toLowerCase()) &&
              col.name !== detailFkColumn // FK 컬럼 제외
            )
            .map((col) => ({
              ...col,
              // 유니크 키를 위해 테이블명 접두사 추가
              name: `${detailTable}.${col.name}`,
              label: `[디테일] ${col.label || col.name}`,
              originalName: col.name,
              sourceTable: detailTable,
            }));
          allColumns = [...allColumns, ...detailCols];
        }

        console.log("✅ 마스터-디테일 컬럼 로드 완료:", allColumns.length);
      } else {
        // 기존 단일 테이블 모드
        const response = await getTableSchema(tableName);

        console.log("📊 테이블 스키마 응답:", response);

        if (response.success && response.data) {
          // 자동 생성 컬럼 제외
          allColumns = response.data.columns.filter(
            (col) => !AUTO_GENERATED_COLUMNS.includes(col.name.toLowerCase())
          );
        } else {
          console.error("❌ 테이블 스키마 로드 실패:", response);
          return;
        }
      }

      // 채번 정보 병합: table_type_columns에서 inputType 가져오기
      try {
        const { getTableColumns } = await import("@/lib/api/tableManagement");
        const targetTables = isMasterDetail && masterDetailRelation
          ? [masterDetailRelation.masterTable, masterDetailRelation.detailTable]
          : [tableName];

        // 테이블별 채번 컬럼 수집
        const numberingColSet = new Set<string>();
        for (const tbl of targetTables) {
          const typeResponse = await getTableColumns(tbl);
          if (typeResponse.success && typeResponse.data?.columns) {
            for (const tc of typeResponse.data.columns) {
              if (tc.inputType === "numbering") {
                try {
                  const settings = typeof tc.detailSettings === "string"
                    ? JSON.parse(tc.detailSettings) : tc.detailSettings;
                  if (settings?.numberingRuleId) {
                    numberingColSet.add(tc.columnName);
                  }
                } catch { /* 파싱 실패 무시 */ }
              }
            }
          }
        }

        // systemColumns에 isNumbering 플래그 추가
        if (numberingColSet.size > 0) {
          allColumns = allColumns.map((col) => {
            const rawName = (col as any).originalName || col.name;
            const colName = rawName.includes(".") ? rawName.split(".")[1] : rawName;
            if (numberingColSet.has(colName)) {
              return { ...col, isNumbering: true } as any;
            }
            return col;
          });
          console.log("✅ 채번 컬럼 감지:", Array.from(numberingColSet));
        }
      } catch (error) {
        console.warn("채번 정보 로드 실패 (무시):", error);
      }

      console.log("✅ 시스템 컬럼 로드 완료 (자동 생성 컬럼 제외):", allColumns);
      setSystemColumns(allColumns);

      // 기존 매핑 템플릿 조회
      console.log("🔍 매핑 템플릿 조회 중...", { tableName, excelColumns });
      const mappingResponse = await findMappingByColumns(tableName, excelColumns);

      if (mappingResponse.success && mappingResponse.data) {
        // 저장된 매핑 템플릿이 있으면 자동 적용
        console.log("✅ 기존 매핑 템플릿 발견:", mappingResponse.data);
        const savedMappings = mappingResponse.data.columnMappings;

        const appliedMappings: ColumnMapping[] = excelColumns.map((col) => ({
          excelColumn: col,
          systemColumn: savedMappings[col] || null,
        }));
        setColumnMappings(appliedMappings);
        setIsAutoMappingLoaded(true);

        const matchedCount = appliedMappings.filter((m) => m.systemColumn).length;
        toast.success(`이전 매핑 템플릿이 적용되었습니다. (${matchedCount}개 컬럼)`);
      } else {
        // 매핑 템플릿이 없으면 초기 상태로 설정
        console.log("ℹ️ 매핑 템플릿 없음 - 새 엑셀 구조");
        const initialMappings: ColumnMapping[] = excelColumns.map((col) => ({
          excelColumn: col,
          systemColumn: null,
        }));
        setColumnMappings(initialMappings);
        setIsAutoMappingLoaded(false);
      }
    } catch (error) {
      console.error("❌ 테이블 스키마 로드 실패:", error);
      toast.error("테이블 스키마를 불러올 수 없습니다.");
    }
  };

  // 자동 매핑 - 컬럼명과 라벨 모두 비교
  const handleAutoMapping = () => {
    const newMappings = excelColumns.map((excelCol) => {
      const normalizedExcelCol = excelCol.toLowerCase().trim();
      // [마스터], [디테일] 접두사 제거 후 비교
      const cleanExcelCol = normalizedExcelCol.replace(/^\[(마스터|디테일)\]\s*/i, "");

      // 1. 먼저 라벨로 매칭 시도 (접두사 제거 후)
      let matchedSystemCol = systemColumns.find((sysCol) => {
        if (!sysCol.label) return false;
        // [마스터], [디테일] 접두사 제거 후 비교
        const cleanLabel = sysCol.label.toLowerCase().trim().replace(/^\[(마스터|디테일)\]\s*/i, "");
        return cleanLabel === normalizedExcelCol || cleanLabel === cleanExcelCol;
      });

      // 2. 라벨로 매칭되지 않으면 컬럼명으로 매칭 시도
      if (!matchedSystemCol) {
        matchedSystemCol = systemColumns.find((sysCol) => {
          // 마스터-디테일 모드: originalName이 있으면 사용
          const originalName = (sysCol as any).originalName;
          const colName = originalName || sysCol.name;
          return colName.toLowerCase().trim() === normalizedExcelCol || colName.toLowerCase().trim() === cleanExcelCol;
        });
      }

      // 3. 여전히 매칭 안되면 전체 이름(테이블.컬럼)에서 컬럼 부분만 추출해서 비교
      if (!matchedSystemCol) {
        matchedSystemCol = systemColumns.find((sysCol) => {
          // 테이블.컬럼 형식에서 컬럼만 추출
          const nameParts = sysCol.name.split(".");
          const colNameOnly = nameParts.length > 1 ? nameParts[1] : nameParts[0];
          return colNameOnly.toLowerCase().trim() === normalizedExcelCol || colNameOnly.toLowerCase().trim() === cleanExcelCol;
        });
      }

      return {
        excelColumn: excelCol,
        systemColumn: matchedSystemCol ? matchedSystemCol.name : null,
      };
    });

    setColumnMappings(newMappings);
    const matchedCount = newMappings.filter((m) => m.systemColumn).length;
    toast.success(`${matchedCount}개 컬럼이 자동 매핑되었습니다.`);
  };

  // 컬럼 매핑 변경
  const handleMappingChange = (excelColumn: string, systemColumn: string | null) => {
    setColumnMappings((prev) =>
      prev.map((mapping) =>
        mapping.excelColumn === excelColumn ? { ...mapping, systemColumn } : mapping
      )
    );
  };

  // 중복 체크 설정 변경
  const handleDuplicateCheckChange = (excelColumn: string, checkDuplicate: boolean) => {
    setColumnMappings((prev) =>
      prev.map((mapping) =>
        mapping.excelColumn === excelColumn
          ? { ...mapping, checkDuplicate }
          : mapping
      )
    );
  };

  // 중복 체크 설정된 컬럼 수
  const duplicateCheckCount = columnMappings.filter((m) => m.checkDuplicate && m.systemColumn).length;

  // 다음 단계
  const handleNext = () => {
    if (currentStep === 1 && !file) {
      toast.error("파일을 선택해주세요.");
      return;
    }

    if (currentStep === 1 && displayData.length === 0) {
      toast.error("데이터가 없습니다.");
      return;
    }

    // 🆕 마스터-디테일 간단 모드: 마스터 필드 유효성 검사
    if (currentStep === 1 && hasMasterSelectFields && !isMasterFieldsValid()) {
      toast.error("마스터 정보를 모두 입력해주세요.");
      return;
    }

    // 1단계 → 2단계 전환 시: 빈 헤더 열 제외
    if (currentStep === 1) {
      // 빈 헤더가 아닌 열만 필터링
      const validColumnIndices: number[] = [];
      const validColumns: string[] = [];

      excelColumns.forEach((col, index) => {
        if (col && col.trim() !== "") {
          validColumnIndices.push(index);
          validColumns.push(col);
        }
      });

      // 빈 헤더 열이 있었다면 데이터에서도 해당 열 제거
      if (validColumns.length < excelColumns.length) {
        const removedCount = excelColumns.length - validColumns.length;
        
        // 새로운 데이터: 유효한 열만 포함
        const cleanedData = displayData.map((row) => {
          const newRow: Record<string, any> = {};
          validColumns.forEach((colName) => {
            newRow[colName] = row[colName];
          });
          return newRow;
        });

        setExcelColumns(validColumns);
        setDisplayData(cleanedData);
        setAllData(cleanedData);

        if (removedCount > 0) {
          toast.info(`빈 헤더 ${removedCount}개 열이 제외되었습니다.`);
        }
      }
    }

    // 2단계 → 3단계 전환 시: NOT NULL 컬럼 매핑 필수 검증
    if (currentStep === 2) {
      // 매핑된 시스템 컬럼 (원본 이름 그대로 + dot 뒤 이름 둘 다 저장)
      const mappedSystemCols = new Set<string>();
      columnMappings.filter((m) => m.systemColumn).forEach((m) => {
        const colName = m.systemColumn!;
        mappedSystemCols.add(colName); // 원본 (예: user_info.user_id)
        if (colName.includes(".")) {
          mappedSystemCols.add(colName.split(".")[1]); // dot 뒤 (예: user_id)
        }
      });

      const unmappedRequired = systemColumns.filter((col) => {
        const rawName = col.name.includes(".") ? col.name.split(".")[1] : col.name;
        if (AUTO_GENERATED_COLUMNS.includes(rawName.toLowerCase())) return false;
        if (col.nullable) return false;
        if (mappedSystemCols.has(col.name) || mappedSystemCols.has(rawName)) return false;
        if ((col as any).isNumbering) return false;
        return true;
      });

      if (unmappedRequired.length > 0) {
        const colNames = unmappedRequired.map((c) => c.label || c.name).join(", ");
        toast.error(`필수(NOT NULL) 컬럼이 매핑되지 않았습니다: ${colNames}`);
        return;
      }
    }

    setCurrentStep((prev) => Math.min(prev + 1, 3));
  };

  // 이전 단계
  const handlePrevious = () => {
    setCurrentStep((prev) => Math.max(prev - 1, 1));
  };

  // 테이블 타입 관리에서 채번 컬럼 자동 감지
  const detectNumberingColumn = async (
    targetTableName: string
  ): Promise<{ columnName: string; numberingRuleId: string } | null> => {
    try {
      const { getTableColumns } = await import("@/lib/api/tableManagement");
      const response = await getTableColumns(targetTableName);

      if (response.success && response.data?.columns) {
        for (const col of response.data.columns) {
          if (col.inputType === "numbering") {
            try {
              const settings =
                typeof col.detailSettings === "string"
                  ? JSON.parse(col.detailSettings)
                  : col.detailSettings;
              if (settings?.numberingRuleId) {
                console.log(
                  `✅ 채번 컬럼 자동 감지: ${col.columnName} → 규칙 ID: ${settings.numberingRuleId}`
                );
                return {
                  columnName: col.columnName,
                  numberingRuleId: settings.numberingRuleId,
                };
              }
            } catch {
              // detailSettings 파싱 실패 시 무시
            }
          }
        }
      }
      return null;
    } catch (error) {
      console.error("채번 컬럼 감지 실패:", error);
      return null;
    }
  };

  // 업로드 핸들러
  const handleUpload = async () => {
    if (!file || !tableName) {
      toast.error("필수 정보가 누락되었습니다.");
      return;
    }

    setIsUploading(true);

    try {
      // allData를 사용하여 전체 데이터 업로드
      const mappedData = allData.map((row) => {
        const mappedRow: Record<string, any> = {};
        columnMappings.forEach((mapping) => {
          if (mapping.systemColumn) {
            // 마스터-디테일 모드: 테이블.컬럼 형식에서 컬럼명만 추출
            let colName = mapping.systemColumn;
            if (isMasterDetail && colName.includes(".")) {
              colName = colName.split(".")[1];
            }
            mappedRow[colName] = row[mapping.excelColumn];
          }
        });
        return mappedRow;
      });

      // 빈 행 필터링: 모든 값이 비어있거나 undefined/null인 행 제외
      const filteredData = mappedData.filter((row) => {
        const values = Object.values(row);
        return values.some((value) => {
          if (value === undefined || value === null) return false;
          if (typeof value === "string" && value.trim() === "") return false;
          return true;
        });
      });

      console.log(
        `📊 엑셀 업로드: 전체 ${mappedData.length}행 중 유효한 ${filteredData.length}행`
      );

      // 마스터-디테일 간단 모드 처리 (마스터 필드 선택 + 채번 자동 감지)
      if (isSimpleMasterDetailMode && screenId && masterDetailRelation) {
        // 마스터 테이블에서 채번 컬럼 자동 감지
        const masterNumberingInfo = await detectNumberingColumn(masterDetailRelation.masterTable);
        const detectedNumberingRuleId = masterNumberingInfo?.numberingRuleId || masterDetailExcelConfig?.numberingRuleId;

        console.log("📊 마스터-디테일 간단 모드 업로드:", {
          masterDetailRelation,
          masterFieldValues,
          detectedNumberingRuleId,
          autoDetected: !!masterNumberingInfo,
        });

        const uploadResult = await DynamicFormApi.uploadMasterDetailSimple(
          screenId,
          filteredData,
          masterFieldValues,
          detectedNumberingRuleId || undefined,
          masterDetailExcelConfig?.afterUploadFlowId || undefined, // 하위 호환성
          masterDetailExcelConfig?.afterUploadFlows || undefined // 다중 제어
        );

        if (uploadResult.success && uploadResult.data) {
          const { masterInserted, detailInserted, generatedKey, errors } = uploadResult.data;
          
          toast.success(
            `마스터 ${masterInserted}건(${generatedKey || ""}), 디테일 ${detailInserted}건 처리되었습니다.` +
            (errors?.length > 0 ? ` (오류: ${errors.length}건)` : "")
          );

          // 매핑 템플릿 저장
          await saveMappingTemplateInternal();

          onSuccess?.();
        } else {
          toast.error(uploadResult.message || "마스터-디테일 업로드에 실패했습니다.");
        }
      }
      // 🆕 마스터-디테일 기존 모드 처리
      else if (isMasterDetail && screenId && masterDetailRelation) {
        console.log("📊 마스터-디테일 업로드 모드:", masterDetailRelation);

        // 마스터 키 컬럼 매핑 검증 (채번 타입이면 자동 생성되므로 검증 생략)
        const masterKeyCol = masterDetailRelation.masterKeyColumn;
        const hasMasterKey = filteredData.length > 0 && filteredData[0][masterKeyCol] !== undefined && filteredData[0][masterKeyCol] !== null && filteredData[0][masterKeyCol] !== "";
        if (!hasMasterKey) {
          // 채번 여부 확인 - 채번이면 백엔드에서 자동 생성하므로 통과
          const numberingInfo = await detectNumberingColumn(masterDetailRelation.masterTable);
          const isMasterKeyAutoNumbering = numberingInfo && numberingInfo.columnName === masterKeyCol;
          
          if (!isMasterKeyAutoNumbering) {
            toast.error(
              `마스터 키 컬럼(${masterKeyCol})이 매핑되지 않았습니다. 컬럼 매핑에서 [마스터] 항목을 확인해주세요.`
            );
            setIsUploading(false);
            return;
          }
          console.log(`✅ 마스터 키(${masterKeyCol})는 채번 타입 → 백엔드에서 자동 생성`);
        }

        const uploadResult = await DynamicFormApi.uploadMasterDetailData(
          screenId,
          filteredData
        );

        if (uploadResult.success && uploadResult.data) {
          const { masterInserted, masterUpdated, detailInserted, errors } = uploadResult.data;
          
          toast.success(
            `마스터 ${masterInserted + masterUpdated}건, 디테일 ${detailInserted}건 처리되었습니다.` +
            (errors.length > 0 ? ` (오류: ${errors.length}건)` : "")
          );

          // 매핑 템플릿 저장
          await saveMappingTemplateInternal();

          onSuccess?.();
        } else {
          toast.error(uploadResult.message || "마스터-디테일 업로드에 실패했습니다.");
        }
      } else {
        // 기존 단일 테이블 업로드 로직
        let successCount = 0;
        let failCount = 0;
        let skipCount = 0;
        let overwriteCount = 0;

        // 단일 테이블 채번 자동 감지 (테이블 타입 관리에서 input_type = 'numbering' 컬럼)
        const numberingInfo = await detectNumberingColumn(tableName);
        const hasNumbering = !!numberingInfo;

        // 중복 체크 설정 확인
        const duplicateCheckMappings = columnMappings.filter(
          (m) => m.checkDuplicate && m.systemColumn
        );
        const hasDuplicateCheck = duplicateCheckMappings.length > 0;

        // 중복 체크를 위한 기존 데이터 조회 (중복 체크가 설정된 경우에만)
        let existingDataMap: Map<string, any> = new Map();
        if (hasDuplicateCheck) {
          try {
            // 중복 체크할 컬럼들의 값 조회
            const checkColumns = duplicateCheckMappings.map((m) => {
              let colName = m.systemColumn!;
              if (isMasterDetail && colName.includes(".")) {
                colName = colName.split(".")[1];
              }
              return colName;
            });

            // DynamicFormApi.getTableData 사용
            const existingResponse = await DynamicFormApi.getTableData(tableName, {
              page: 1,
              pageSize: 10000,
            });

            console.log("📊 중복 체크용 기존 데이터 조회 결과:", existingResponse);

            // getTableData는 { success, data: [...] } 또는 { success, data: { rows: [...] } } 형식
            const rows = existingResponse.data?.rows || existingResponse.data;
            if (existingResponse.success && rows && Array.isArray(rows)) {
              // 중복 체크 컬럼 값을 키로 하는 맵 생성
              rows.forEach((row: any) => {
                const keyParts = checkColumns.map((col) => String(row[col] || "").trim());
                const key = keyParts.join("|||");
                existingDataMap.set(key, row);
              });
              console.log(`📊 중복 체크용 기존 데이터 로드: ${existingDataMap.size}건`);
            }
          } catch (error) {
            console.error("중복 체크 데이터 조회 오류:", error);
          }
        }

        for (const row of filteredData) {
          try {
            let dataToSave = { ...row };
            let shouldSkip = false;
            let shouldUpdate = false;
            let existingRow: any = null;

            // 중복 체크
            if (hasDuplicateCheck) {
              const checkColumns = duplicateCheckMappings.map((m) => {
                let colName = m.systemColumn!;
                if (isMasterDetail && colName.includes(".")) {
                  colName = colName.split(".")[1];
                }
                return colName;
              });
              
              const keyParts = checkColumns.map((col) => String(dataToSave[col] || "").trim());
              const key = keyParts.join("|||");
              
              if (existingDataMap.has(key)) {
                existingRow = existingDataMap.get(key);
                // 중복 발견 - 전역 설정에 따라 처리
                if (duplicateAction === "skip") {
                  shouldSkip = true;
                  skipCount++;
                  console.log(`⏭️ 중복으로 건너뛰기: ${key}`);
                } else {
                  shouldUpdate = true;
                  console.log(`🔄 중복으로 덮어쓰기: ${key}`);
                }
              }
            }

            // 건너뛰기 처리
            if (shouldSkip) {
              continue;
            }

            // 채번 적용: 각 행마다 채번 API 호출 (신규 등록 시에만, 자동 감지된 채번 규칙 사용)
            if (hasNumbering && numberingInfo && uploadMode === "insert" && !shouldUpdate) {
              try {
                const { apiClient } = await import("@/lib/api/client");
                const numberingResponse = await apiClient.post(`/numbering-rules/${numberingInfo.numberingRuleId}/allocate`);
                const generatedCode = numberingResponse.data?.data?.generatedCode || numberingResponse.data?.data?.code;
                if (numberingResponse.data?.success && generatedCode) {
                  dataToSave[numberingInfo.columnName] = generatedCode;
                }
              } catch (numError) {
                console.error("채번 오류:", numError);
              }
            }

            if (shouldUpdate && existingRow) {
              // 덮어쓰기: 기존 데이터 업데이트
              const formData = { 
                screenId: 0, 
                tableName, 
                data: dataToSave,
              };
              const result = await DynamicFormApi.updateFormData(existingRow.id, formData);
              if (result.success) {
                overwriteCount++;
                successCount++;
              } else {
                failCount++;
              }
            } else if (uploadMode === "insert") {
              // 신규 등록
              const formData = { screenId: 0, tableName, data: dataToSave };
              const result = await DynamicFormApi.saveFormData(formData);
              if (result.success) {
                successCount++;
              } else {
                failCount++;
              }
            }
          } catch (error) {
            failCount++;
          }
        }

        // 업로드 후 제어 실행
        if (afterUploadFlows && afterUploadFlows.length > 0 && successCount > 0) {
          console.log("🔄 업로드 후 제어 실행:", afterUploadFlows);
          try {
            const { apiClient } = await import("@/lib/api/client");
            // 순서대로 실행
            const sortedFlows = [...afterUploadFlows].sort((a, b) => a.order - b.order);
            for (const flow of sortedFlows) {
              await apiClient.post(`/dataflow/node-flows/${flow.flowId}/execute`, {
                sourceData: { tableName, uploadedCount: successCount },
              });
              console.log(`✅ 제어 실행 완료: flowId=${flow.flowId}`);
            }
          } catch (controlError) {
            console.error("제어 실행 오류:", controlError);
          }
        }

        if (successCount > 0 || skipCount > 0) {
          // 상세 결과 메시지 생성
          let message = "";
          if (successCount > 0) {
            message += `${successCount}개 행 업로드`;
            if (overwriteCount > 0) {
              message += ` (덮어쓰기 ${overwriteCount}건)`;
            }
          }
          if (skipCount > 0) {
            message += message ? `, ` : "";
            message += `중복 건너뛰기 ${skipCount}개`;
          }
          if (failCount > 0) {
            message += ` (실패: ${failCount}개)`;
          }
          
          toast.success(message);

          // 매핑 템플릿 저장
          await saveMappingTemplateInternal();

          onSuccess?.();
        } else {
          toast.error("업로드에 실패했습니다.");
        }
      }
    } catch (error) {
      console.error("❌ 엑셀 업로드 실패:", error);
      toast.error("엑셀 업로드 중 오류가 발생했습니다.");
    } finally {
      setIsUploading(false);
    }
  };

  // 매핑 템플릿 저장 헬퍼 함수
  const saveMappingTemplateInternal = async () => {
    try {
      const mappingsToSave: Record<string, string | null> = {};
      columnMappings.forEach((mapping) => {
        mappingsToSave[mapping.excelColumn] = mapping.systemColumn;
      });

      console.log("💾 매핑 템플릿 저장 중...", {
        tableName,
        excelColumns,
        mappingsToSave,
      });
      const saveResult = await saveMappingTemplate(
        tableName,
        excelColumns,
        mappingsToSave
      );

      if (saveResult.success) {
        console.log("✅ 매핑 템플릿 저장 완료:", saveResult.data);
      } else {
        console.warn("⚠️ 매핑 템플릿 저장 실패:", saveResult.error);
      }
    } catch (error) {
      console.warn("⚠️ 매핑 템플릿 저장 중 오류:", error);
    }
  };

  // 모달 닫기 시 초기화
  useEffect(() => {
    if (!open) {
      setCurrentStep(1);
      setFile(null);
      setSheetNames([]);
      setSelectedSheet("");
      setIsAutoMappingLoaded(false);
      setDetectedRange("");
      setAllData([]);
      setDisplayData([]);
      setExcelColumns([]);
      setSystemColumns([]);
      setColumnMappings([]);
      setDuplicateAction("skip");
      // 🆕 마스터-디테일 모드 초기화
      setMasterFieldValues({});
    }
  }, [open]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent
        className="max-h-[95vh] max-w-[95vw] sm:max-w-[1200px]"
        style={{
          width: "1000px",
          height: "700px",
          minWidth: "700px",
          minHeight: "500px",
          maxWidth: "1400px",
          maxHeight: "900px",
        }}
      >
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2 text-base sm:text-lg">
            <FileSpreadsheet className="h-5 w-5" />
            엑셀 데이터 업로드
            {isMasterDetail && (
              <span className="ml-2 rounded bg-blue-100 px-2 py-0.5 text-xs font-normal text-blue-700">
                마스터-디테일
              </span>
            )}
          </DialogTitle>
          <DialogDescription className="text-xs sm:text-sm">
            {isMasterDetail && masterDetailRelation ? (
              <>
                마스터({masterDetailRelation.masterTable}) + 디테일({masterDetailRelation.detailTable}) 구조입니다.
                마스터 데이터는 중복 입력 시 병합됩니다.
              </>
            ) : (
              "엑셀 파일을 선택하고 컬럼을 매핑하여 데이터를 업로드하세요."
            )}
          </DialogDescription>
        </DialogHeader>

        {/* 스텝 인디케이터 (3단계) */}
        <div className="flex items-center justify-between">
          {[
            { num: 1, label: "파일 선택" },
            { num: 2, label: "컬럼 매핑" },
            { num: 3, label: "확인" },
          ].map((step, index) => (
            <React.Fragment key={step.num}>
              <div className="flex flex-col items-center gap-1">
                <div
                  className={cn(
                    "flex h-8 w-8 items-center justify-center rounded-full text-sm font-medium transition-colors sm:h-10 sm:w-10",
                    currentStep === step.num
                      ? "bg-primary text-primary-foreground"
                      : currentStep > step.num
                        ? "bg-success text-white"
                        : "bg-muted text-muted-foreground"
                  )}
                >
                  {currentStep > step.num ? (
                    <CheckCircle2 className="h-4 w-4 sm:h-5 sm:w-5" />
                  ) : (
                    step.num
                  )}
                </div>
                <span
                  className={cn(
                    "text-[10px] font-medium sm:text-xs",
                    currentStep === step.num ? "text-primary" : "text-muted-foreground"
                  )}
                >
                  {step.label}
                </span>
              </div>
              {index < 2 && (
                <div
                  className={cn(
                    "h-0.5 flex-1 transition-colors",
                    currentStep > step.num ? "bg-success" : "bg-muted"
                  )}
                />
              )}
            </React.Fragment>
          ))}
        </div>

        {/* 스텝별 컨텐츠 */}
        <div className="max-h-[calc(95vh-200px)] space-y-4 overflow-y-auto">
          {/* 1단계: 파일 선택 & 미리보기 (통합) */}
          {currentStep === 1 && (
            <div className="space-y-4">
              {/* 🆕 마스터-디테일 간단 모드: 마스터 필드 입력 */}
              {hasMasterSelectFields && (
                <div className="grid gap-3 sm:grid-cols-2">
                  {masterDetailExcelConfig?.masterSelectFields?.map((field) => (
                      <div key={field.columnName} className="space-y-1">
                        <Label className="text-xs">
                          {field.columnLabel}
                          {field.required && <span className="ml-1 text-destructive">*</span>}
                        </Label>
                        {field.inputType === "entity" ? (
                          <Select
                            value={masterFieldValues[field.columnName]?.toString() || ""}
                            onValueChange={(value) => {
                              // 선택한 item 찾기
                              const selectedItem = entitySearchData[field.columnName]?.find(
                                (item: any) => item[field.referenceColumn || "id"]?.toString() === value
                              );
                              
                              // displayColumn에서 name 값도 가져오기
                              const displayColName = 
                                field.displayColumn || 
                                entityDisplayColumns[field.columnName] || 
                                field.referenceColumn || 
                                "id";
                              const displayValue = selectedItem?.[displayColName];
                              
                              // code와 name 컬럼명 추출 (예: supplier_code → supplier_name)
                              const codeColName = field.columnName; // supplier_code
                              const nameColName = codeColName.replace(/_code$/, "_name"); // supplier_name
                              
                              setMasterFieldValues((prev) => {
                                const newValues = {
                                  ...prev,
                                  [codeColName]: value,
                                };
                                
                                // _code로 끝나는 컬럼이면 _name도 함께 저장
                                if (codeColName.endsWith("_code") && displayValue) {
                                  newValues[nameColName] = displayValue;
                                  console.log(`🔗 엔티티 연동: ${codeColName}=${value}, ${nameColName}=${displayValue}`);
                                }
                                
                                return newValues;
                              });
                            }}
                          >
                            <SelectTrigger className="h-9 text-xs">
                              <SelectValue placeholder={`${field.columnLabel} 선택`} />
                            </SelectTrigger>
                            <SelectContent>
                              {entitySearchLoading[field.columnName] ? (
                                <SelectItem value="loading" disabled>
                                  로딩 중...
                                </SelectItem>
                              ) : (
                                entitySearchData[field.columnName]?.map((item: any) => {
                                  const keyValue = item[field.referenceColumn || "id"];
                                  // displayColumn: 저장된 값 → DB에서 조회한 값 → referenceColumn → id
                                  const displayColName = 
                                    field.displayColumn || 
                                    entityDisplayColumns[field.columnName] || 
                                    field.referenceColumn || 
                                    "id";
                                  const displayValue = item[displayColName] || keyValue;
                                  return (
                                    <SelectItem
                                      key={keyValue}
                                      value={keyValue?.toString()}
                                      className="text-xs"
                                    >
                                      {displayValue}
                                    </SelectItem>
                                  );
                                })
                              )}
                            </SelectContent>
                          </Select>
                        ) : field.inputType === "date" ? (
                          <input
                            type="date"
                            value={masterFieldValues[field.columnName] || ""}
                            onChange={(e) =>
                              setMasterFieldValues((prev) => ({
                                ...prev,
                                [field.columnName]: e.target.value,
                              }))
                            }
                            className="h-9 w-full rounded-md border px-3 text-xs"
                          />
                        ) : (
                          <input
                            type="text"
                            value={masterFieldValues[field.columnName] || ""}
                            onChange={(e) =>
                              setMasterFieldValues((prev) => ({
                                ...prev,
                                [field.columnName]: e.target.value,
                              }))
                            }
                            placeholder={field.columnLabel}
                            className="h-9 w-full rounded-md border px-3 text-xs"
                          />
                        )}
                      </div>
                    ))}
                </div>
              )}

              {/* 파일 선택 영역 */}
              <div>
                <Label htmlFor="file-upload" className="text-xs sm:text-sm">
                  파일 선택 *
                </Label>
                <div
                  onDragOver={handleDragOver}
                  onDragLeave={handleDragLeave}
                  onDrop={handleDrop}
                  onClick={() => fileInputRef.current?.click()}
                  className={cn(
                    "mt-2 flex cursor-pointer flex-col items-center justify-center rounded-lg border-2 border-dashed p-4 transition-colors",
                    isDragOver
                      ? "border-primary bg-primary/5"
                      : file
                        ? "border-green-500 bg-green-50"
                        : "border-muted-foreground/25 hover:border-primary hover:bg-muted/50"
                  )}
                >
                  {file ? (
                    <div className="flex items-center gap-3">
                      <FileSpreadsheet className="h-8 w-8 text-green-600" />
                      <div>
                        <p className="text-sm font-medium text-green-700">{file.name}</p>
                        <p className="text-xs text-muted-foreground">
                          클릭하여 다른 파일 선택
                        </p>
                      </div>
                    </div>
                  ) : (
                    <>
                      <Upload
                        className={cn(
                          "mb-2 h-8 w-8",
                          isDragOver ? "text-primary" : "text-muted-foreground"
                        )}
                      />
                      <p
                        className={cn(
                          "text-sm font-medium",
                          isDragOver ? "text-primary" : "text-muted-foreground"
                        )}
                      >
                        {isDragOver
                          ? "파일을 놓으세요"
                          : "파일을 드래그하거나 클릭하여 선택"}
                      </p>
                      <p className="mt-1 text-xs text-muted-foreground">
                        지원 형식: .xlsx, .xls, .csv
                      </p>
                    </>
                  )}
                  <input
                    ref={fileInputRef}
                    id="file-upload"
                    type="file"
                    accept=".xlsx,.xls,.csv"
                    onChange={handleFileChange}
                    className="hidden"
                  />
                </div>
              </div>

              {/* 파일이 선택된 경우에만 미리보기 표시 */}
              {file && displayData.length > 0 && (
                <>
                  {/* 시트 선택 */}
                  <div className="flex items-center gap-3">
                    <div className="flex items-center gap-2">
                      <Label className="text-xs text-muted-foreground sm:text-sm">
                        시트:
                      </Label>
                      <Select value={selectedSheet} onValueChange={handleSheetChange}>
                        <SelectTrigger className="h-8 w-[140px] text-xs sm:h-9 sm:w-[180px] sm:text-sm">
                          <SelectValue placeholder="Sheet1" />
                        </SelectTrigger>
                        <SelectContent>
                          {sheetNames.map((sheetName) => (
                            <SelectItem
                              key={sheetName}
                              value={sheetName}
                              className="text-xs sm:text-sm"
                            >
                              {sheetName}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </div>
                    <span className="text-xs text-muted-foreground">
                      {displayData.length}개 행 · 셀을 클릭하여 편집, Tab/Enter로 이동
                    </span>
                  </div>

                  {/* 엑셀처럼 편집 가능한 스프레드시트 */}
                  <EditableSpreadsheet
                    columns={excelColumns}
                    data={displayData}
                    onColumnsChange={(newColumns) => {
                      setExcelColumns(newColumns);
                      // 범위 재계산
                      const lastCol =
                        newColumns.length > 0
                          ? String.fromCharCode(64 + newColumns.length)
                          : "A";
                      setDetectedRange(`A1:${lastCol}${displayData.length + 1}`);
                    }}
                    onDataChange={(newData) => {
                      setDisplayData(newData);
                      setAllData(newData);
                      // 범위 재계산
                      const lastCol =
                        excelColumns.length > 0
                          ? String.fromCharCode(64 + excelColumns.length)
                          : "A";
                      setDetectedRange(`A1:${lastCol}${newData.length + 1}`);
                    }}
                    maxHeight="320px"
                  />
                </>
              )}
            </div>
          )}

          {/* 2단계: 컬럼 매핑 */}
          {currentStep === 2 && (
            <div className="space-y-4">
              {/* 상단: 제목 + 자동 매핑 버튼 */}
              <div className="flex items-center justify-between">
                <h3 className="text-sm font-semibold sm:text-base">컬럼 매핑 설정</h3>
                <Button
                  type="button"
                  variant="default"
                  size="sm"
                  onClick={handleAutoMapping}
                  className="h-8 text-xs sm:h-9 sm:text-sm"
                >
                  <Zap className="mr-2 h-4 w-4" />
                  자동 매핑
                </Button>
              </div>

              {/* 매핑 리스트 */}
              <div className="space-y-2">
                <div className="grid grid-cols-[1fr_auto_1fr_80px] gap-2 text-[10px] font-medium text-muted-foreground sm:text-xs">
                  <div>엑셀 컬럼</div>
                  <div></div>
                  <div>시스템 컬럼</div>
                  <div className="text-center">중복 키</div>
                </div>

                <div className="max-h-[300px] space-y-2 overflow-y-auto">
                  {columnMappings.map((mapping, index) => (
                    <div
                      key={index}
                      className="grid grid-cols-[1fr_auto_1fr_80px] items-center gap-2"
                    >
                      <div className="rounded-md border border-border bg-muted px-3 py-2 text-xs font-medium sm:text-sm">
                        {mapping.excelColumn}
                      </div>
                      <ArrowRight className="h-4 w-4 text-muted-foreground" />
                      <Select
                        value={mapping.systemColumn || "none"}
                        onValueChange={(value) =>
                          handleMappingChange(
                            mapping.excelColumn,
                            value === "none" ? null : value
                          )
                        }
                      >
                        <SelectTrigger className="h-8 text-xs sm:h-10 sm:text-sm">
                          <SelectValue placeholder="매핑 안함">
                            {mapping.systemColumn
                              ? (() => {
                                  const col = systemColumns.find(
                                    (c) => c.name === mapping.systemColumn
                                  );
                                  return col?.label || mapping.systemColumn;
                                })()
                              : "매핑 안함"}
                          </SelectValue>
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="none" className="text-xs sm:text-sm">
                            매핑 안함
                          </SelectItem>
                          {systemColumns.map((col) => {
                            const isRequired = !col.nullable && !AUTO_GENERATED_COLUMNS.includes(col.name.toLowerCase()) && !(col as any).isNumbering;
                            return (
                            <SelectItem
                              key={col.name}
                              value={col.name}
                              className="text-xs sm:text-sm"
                            >
                              {isRequired && <span className="text-destructive mr-1">*</span>}
                              {col.label || col.name} ({col.type})
                            </SelectItem>
                            );
                          })}
                        </SelectContent>
                      </Select>
                      {/* 중복 체크 체크박스 */}
                      <div className="flex justify-center">
                        {mapping.systemColumn ? (
                          <Checkbox
                            checked={mapping.checkDuplicate || false}
                            onCheckedChange={(checked) =>
                              handleDuplicateCheckChange(mapping.excelColumn, checked as boolean)
                            }
                            className="h-4 w-4"
                          />
                        ) : (
                          <span className="text-[10px] text-muted-foreground">-</span>
                        )}
                      </div>
                    </div>
                  ))}
                </div>
              </div>

              {/* 미매핑 필수(NOT NULL) 컬럼 경고 */}
              {(() => {
                const mappedCols = new Set<string>();
                columnMappings.filter((m) => m.systemColumn).forEach((m) => {
                  const n = m.systemColumn!;
                  mappedCols.add(n);
                  if (n.includes(".")) mappedCols.add(n.split(".")[1]);
                });
                const missing = systemColumns.filter((col) => {
                  const rawName = col.name.includes(".") ? col.name.split(".")[1] : col.name;
                  if (AUTO_GENERATED_COLUMNS.includes(rawName.toLowerCase())) return false;
                  if (col.nullable) return false;
                  if (mappedCols.has(col.name) || mappedCols.has(rawName)) return false;
                  if ((col as any).isNumbering) return false;
                  return true;
                });
                if (missing.length === 0) return null;
                return (
                  <div className="rounded-md border border-destructive/50 bg-destructive/10 p-3">
                    <div className="flex items-start gap-2">
                      <AlertCircle className="mt-0.5 h-4 w-4 text-destructive" />
                      <div className="text-[10px] text-destructive sm:text-xs">
                        <p className="font-medium">필수(NOT NULL) 컬럼이 매핑되지 않았습니다:</p>
                        <p className="mt-1">
                          {missing.map((c) => c.label || c.name).join(", ")}
                        </p>
                      </div>
                    </div>
                  </div>
                );
              })()}

              {/* 중복 체크 안내 */}
              {duplicateCheckCount > 0 ? (
                <div className="rounded-md border border-blue-200 bg-blue-50 p-3">
                  <div className="flex items-start justify-between gap-4">
                    <div className="flex items-start gap-2">
                      <Copy className="mt-0.5 h-4 w-4 text-blue-600" />
                      <div className="text-[10px] text-blue-700 sm:text-xs">
                        <p className="font-medium">
                          중복 키: {columnMappings
                            .filter((m) => m.checkDuplicate && m.systemColumn)
                            .map((m) => {
                              const col = systemColumns.find((c) => c.name === m.systemColumn);
                              return col?.label || m.systemColumn;
                            })
                            .join(" + ")}
                        </p>
                        <p className="mt-1">
                          위 컬럼 값이 모두 일치하는 기존 데이터가 있으면 중복으로 처리합니다.
                        </p>
                      </div>
                    </div>
                    <div className="flex items-center gap-2 shrink-0">
                      <span className="text-[10px] text-blue-700 sm:text-xs">중복 시:</span>
                      <Select
                        value={duplicateAction}
                        onValueChange={(value) => setDuplicateAction(value as "overwrite" | "skip")}
                      >
                        <SelectTrigger className="h-7 w-[100px] text-[10px] sm:text-xs border-blue-300 bg-white">
                          <SelectValue />
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="skip" className="text-xs">건너뛰기</SelectItem>
                          <SelectItem value="overwrite" className="text-xs">덮어쓰기</SelectItem>
                        </SelectContent>
                      </Select>
                    </div>
                  </div>
                </div>
              ) : (
                <div className="rounded-md border border-muted bg-muted/30 p-3">
                  <div className="flex items-start gap-2">
                    <Copy className="mt-0.5 h-4 w-4 text-muted-foreground" />
                    <div className="text-[10px] text-muted-foreground sm:text-xs">
                      <p className="font-medium">중복 체크 (선택사항)</p>
                      <p className="mt-1">
                        "중복 키" 체크박스를 선택하면 해당 컬럼 값으로 기존 데이터와 비교합니다.
                        여러 컬럼을 선택하면 복합 키로 중복을 판단합니다.
                      </p>
                    </div>
                  </div>
                </div>
              )}

              {/* 매핑 자동 저장 안내 */}
              {isAutoMappingLoaded ? (
                <div className="rounded-md border border-success bg-success/10 p-3">
                  <div className="flex items-start gap-2">
                    <CheckCircle2 className="mt-0.5 h-4 w-4 text-success" />
                    <div className="text-[10px] text-success sm:text-xs">
                      <p className="font-medium">이전 매핑이 자동 적용됨</p>
                      <p className="mt-1">
                        동일한 엑셀 구조가 감지되어 이전에 저장된 매핑이 적용되었습니다.
                        수정하면 업로드 시 자동 저장됩니다.
                      </p>
                    </div>
                  </div>
                </div>
              ) : (
                <div className="rounded-md border border-muted bg-muted/30 p-3">
                  <div className="flex items-start gap-2">
                    <Zap className="mt-0.5 h-4 w-4 text-muted-foreground" />
                    <div className="text-[10px] text-muted-foreground sm:text-xs">
                      <p className="font-medium">새로운 엑셀 구조</p>
                      <p className="mt-1">
                        이 엑셀 구조는 처음입니다. 매핑을 설정하면 다음에 같은 구조의
                        엑셀에 자동 적용됩니다.
                      </p>
                    </div>
                  </div>
                </div>
              )}
            </div>
          )}

          {/* 3단계: 확인 */}
          {currentStep === 3 && (
            <div className="space-y-4">
              <div className="rounded-md border border-border bg-muted/50 p-4">
                <h3 className="text-sm font-medium sm:text-base">업로드 요약</h3>
                <div className="mt-2 space-y-1 text-[10px] text-muted-foreground sm:text-xs">
                  <p>
                    <span className="font-medium">파일:</span> {file?.name}
                  </p>
                  <p>
                    <span className="font-medium">시트:</span> {selectedSheet}
                  </p>
                  <p>
                    <span className="font-medium">데이터 행:</span> {allData.length}개
                  </p>
                  <p>
                    <span className="font-medium">테이블:</span> {tableName}
                  </p>
                  <p>
                    <span className="font-medium">모드:</span>{" "}
                    {uploadMode === "insert"
                      ? "신규 등록"
                      : uploadMode === "update"
                        ? "업데이트"
                        : "Upsert"}
                  </p>
                </div>
              </div>

              <div className="rounded-md border border-border bg-muted/50 p-4">
                <h3 className="text-sm font-medium sm:text-base">컬럼 매핑</h3>
                <div className="mt-2 space-y-1 text-[10px] text-muted-foreground sm:text-xs">
                  {columnMappings
                    .filter((m) => m.systemColumn)
                    .map((mapping, index) => {
                      const col = systemColumns.find(
                        (c) => c.name === mapping.systemColumn
                      );
                      return (
                        <p key={index}>
                          <span className="font-medium">{mapping.excelColumn}</span> →{" "}
                          {col?.label || mapping.systemColumn}
                          {mapping.checkDuplicate && (
                            <span className="ml-2 text-blue-600">
                              (중복 체크: {mapping.duplicateAction === "overwrite" ? "덮어쓰기" : "건너뛰기"})
                            </span>
                          )}
                        </p>
                      );
                    })}
                  {columnMappings.filter((m) => m.systemColumn).length === 0 && (
                    <p className="text-destructive">매핑된 컬럼이 없습니다.</p>
                  )}
                </div>
              </div>

              {/* 중복 체크 요약 */}
              {duplicateCheckCount > 0 && (
                <div className="rounded-md border border-blue-200 bg-blue-50 p-4">
                  <h3 className="text-sm font-medium text-blue-800 sm:text-base">중복 체크 설정</h3>
                  <div className="mt-2 space-y-1 text-[10px] text-blue-700 sm:text-xs">
                    <p>
                      <span className="font-medium">중복 키:</span>{" "}
                      {columnMappings
                        .filter((m) => m.checkDuplicate && m.systemColumn)
                        .map((m) => {
                          const col = systemColumns.find((c) => c.name === m.systemColumn);
                          return col?.label || m.systemColumn;
                        })
                        .join(" + ")}
                    </p>
                    <p>
                      <span className="font-medium">중복 시 처리:</span>{" "}
                      {duplicateAction === "overwrite" ? "덮어쓰기 (기존 데이터 업데이트)" : "건너뛰기 (해당 행 무시)"}
                    </p>
                  </div>
                </div>
              )}

              <div className="rounded-md border border-warning bg-warning/10 p-3">
                <div className="flex items-start gap-2">
                  <AlertCircle className="mt-0.5 h-4 w-4 text-warning" />
                  <div className="text-[10px] text-warning sm:text-xs">
                    <p className="font-medium">주의사항</p>
                    <p className="mt-1">
                      업로드를 진행하면 데이터가 데이터베이스에 저장됩니다.
                      계속하시겠습니까?
                    </p>
                  </div>
                </div>
              </div>
            </div>
          )}
        </div>

        <DialogFooter className="gap-2 sm:gap-0">
          <Button
            variant="outline"
            onClick={currentStep === 1 ? () => onOpenChange(false) : handlePrevious}
            disabled={isUploading}
            className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
          >
            {currentStep === 1 ? "취소" : "이전"}
          </Button>
          {currentStep < 3 ? (
            <Button
              onClick={handleNext}
              disabled={isUploading || (currentStep === 1 && !file)}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              다음
            </Button>
          ) : (
            <Button
              onClick={handleUpload}
              disabled={
                isUploading || columnMappings.filter((m) => m.systemColumn).length === 0
              }
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              {isUploading ? "업로드 중..." : "업로드"}
            </Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>
  );
};
