"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,
  Download,
  Loader2,
  Check,
  ChevronsUpDown,
} from "lucide-react";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import { importFromExcel, getExcelSheetNames, exportToExcel } from "@/lib/utils/excelExport";
import { cn } from "@/lib/utils";
import { EditableSpreadsheet } from "./EditableSpreadsheet";
import {
  TableChainConfig,
  uploadMultiTableExcel,
} from "@/lib/api/multiTableExcel";
import { getCategoryValues } from "@/lib/api/tableCategoryValue";
import { getTableColumns } from "@/lib/api/tableManagement";

export interface MultiTableExcelUploadModalProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  config: TableChainConfig;
  onSuccess?: () => void;
}

interface ColumnMapping {
  excelColumn: string;
  targetColumn: string | null;
}

interface FlatCategoryValue {
  valueCode: string;
  valueLabel: string;
  depth: number;
  ancestors: string[];
}

function flattenCategoryValues(
  values: Array<{ valueCode: string; valueLabel: string; children?: any[] }>
): FlatCategoryValue[] {
  const result: FlatCategoryValue[] = [];
  const traverse = (items: any[], depth: number, ancestors: string[]) => {
    for (const item of items) {
      result.push({
        valueCode: item.valueCode,
        valueLabel: item.valueLabel,
        depth,
        ancestors,
      });
      if (item.children?.length > 0) {
        traverse(item.children, depth + 1, [...ancestors, item.valueLabel]);
      }
    }
  };
  traverse(values, 0, []);
  return result;
}

export const MultiTableExcelUploadModal: React.FC<MultiTableExcelUploadModalProps> = ({
  open,
  onOpenChange,
  config,
  onSuccess,
}) => {
  // 스텝: 1=모드선택+파일, 2=컬럼매핑, 3=확인
  const [currentStep, setCurrentStep] = useState(1);

  // 모드 선택
  const [selectedModeId, setSelectedModeId] = useState<string>(
    config.uploadModes[0]?.id || ""
  );

  // 파일
  const [file, setFile] = useState<File | null>(null);
  const [sheetNames, setSheetNames] = useState<string[]>([]);
  const [selectedSheet, setSelectedSheet] = useState("");
  const [isDragOver, setIsDragOver] = useState(false);
  const fileInputRef = useRef<HTMLInputElement>(null);
  const [allData, setAllData] = useState<Record<string, any>[]>([]);
  const [displayData, setDisplayData] = useState<Record<string, any>[]>([]);
  const [excelColumns, setExcelColumns] = useState<string[]>([]);

  // 매핑
  const [columnMappings, setColumnMappings] = useState<ColumnMapping[]>([]);

  // 업로드
  const [isUploading, setIsUploading] = useState(false);

  // 카테고리 검증 관련
  const [showCategoryValidation, setShowCategoryValidation] = useState(false);
  const [isCategoryValidating, setIsCategoryValidating] = useState(false);
  const [categoryMismatches, setCategoryMismatches] = useState<
    Record<string, Array<{
      invalidValue: string;
      replacement: string | null;
      validOptions: Array<{ code: string; label: string; depth: number; ancestors: string[] }>;
      rowIndices: number[];
    }>>
  >({});

  const selectedMode = config.uploadModes.find((m) => m.id === selectedModeId);

  // 선택된 모드에서 활성화되는 컬럼 목록
  const activeColumns = React.useMemo(() => {
    if (!selectedMode) return [];
    const cols: Array<{ dbColumn: string; excelHeader: string; required: boolean; levelLabel: string }> = [];
    for (const levelIdx of selectedMode.activeLevels) {
      const level = config.levels[levelIdx];
      if (!level) continue;
      for (const col of level.columns) {
        cols.push({
          ...col,
          levelLabel: level.label,
        });
      }
    }
    return cols;
  }, [selectedMode, config.levels]);

  // 템플릿 다운로드
  const handleDownloadTemplate = () => {
    if (!selectedMode) return;

    const headers: string[] = [];
    const sampleRow: Record<string, string> = {};
    const sampleRow2: Record<string, string> = {};

    for (const levelIdx of selectedMode.activeLevels) {
      const level = config.levels[levelIdx];
      if (!level) continue;
      for (const col of level.columns) {
        headers.push(col.excelHeader);
        sampleRow[col.excelHeader] = col.required ? "(필수)" : "";
        sampleRow2[col.excelHeader] = "";
      }
    }

    // 예시 데이터 생성 (config에 맞춰)
    exportToExcel(
      [sampleRow, sampleRow2],
      `${config.name}_${selectedMode.label}_템플릿.xlsx`,
      "Sheet1"
    );

    toast.success("템플릿 파일이 다운로드되었습니다.");
  };

  // 파일 처리
  const processFile = async (selectedFile: File) => {
    const ext = selectedFile.name.split(".").pop()?.toLowerCase();
    if (!["xlsx", "xls", "csv"].includes(ext || "")) {
      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) {
        setExcelColumns(Object.keys(data[0]));
      }

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

  const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const selectedFile = e.target.files?.[0];
    if (selectedFile) await processFile(selectedFile);
  };

  const handleDragOver = (e: React.DragEvent) => {
    e.preventDefault();
    e.stopPropagation();
    setIsDragOver(true);
  };

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

  const handleDrop = async (e: React.DragEvent) => {
    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) {
        setExcelColumns(Object.keys(data[0]));
      }
    } catch (error) {
      console.error("시트 읽기 오류:", error);
      toast.error("시트를 읽는 중 오류가 발생했습니다.");
    }
  };

  // 2단계 진입 시 자동 매핑 시도
  useEffect(() => {
    if (currentStep === 2 && excelColumns.length > 0) {
      performAutoMapping();
    }
  }, [currentStep]);

  const performAutoMapping = () => {
    const newMappings: ColumnMapping[] = excelColumns.map((excelCol) => {
      const normalizedExcel = excelCol.toLowerCase().trim();
      const matched = activeColumns.find((ac) => {
        return (
          ac.excelHeader.toLowerCase().trim() === normalizedExcel ||
          ac.dbColumn.toLowerCase().trim() === normalizedExcel
        );
      });
      return {
        excelColumn: excelCol,
        targetColumn: matched ? matched.excelHeader : null,
      };
    });
    setColumnMappings(newMappings);

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

  const handleMappingChange = (excelColumn: string, targetColumn: string | null) => {
    setColumnMappings((prev) =>
      prev.map((m) =>
        m.excelColumn === excelColumn ? { ...m, targetColumn } : m
      )
    );
  };

  // 업로드 실행
  const handleUpload = async () => {
    if (!file || !selectedMode) return;

    setIsUploading(true);

    try {
      // 엑셀 데이터를 excelHeader 기준으로 변환
      const mappedRows = allData.map((row) => {
        const mappedRow: Record<string, any> = {};
        columnMappings.forEach((mapping) => {
          if (mapping.targetColumn) {
            mappedRow[mapping.targetColumn] = row[mapping.excelColumn];
          }
        });
        return mappedRow;
      });

      // 빈 행 필터링
      const filteredRows = mappedRows.filter((row) =>
        Object.values(row).some(
          (v) => v !== undefined && v !== null && (typeof v !== "string" || v.trim() !== "")
        )
      );

      console.log(`다중 테이블 업로드: ${filteredRows.length}행`);

      const result = await uploadMultiTableExcel({
        config,
        modeId: selectedModeId,
        rows: filteredRows,
      });

      if (result.success && result.data) {
        const { results, errors } = result.data;
        const summaryParts = results
          .filter((r) => r.inserted + r.updated > 0)
          .map((r) => {
            const parts: string[] = [];
            if (r.inserted > 0) parts.push(`신규 ${r.inserted}건`);
            if (r.updated > 0) parts.push(`수정 ${r.updated}건`);
            return `${r.tableName}: ${parts.join(", ")}`;
          });

        const msg = summaryParts.join(" / ");
        const errorMsg = errors.length > 0 ? ` (오류: ${errors.length}건)` : "";

        toast.success(`업로드 완료: ${msg}${errorMsg}`);

        if (errors.length > 0) {
          console.warn("업로드 오류 목록:", errors);
        }

        onSuccess?.();
        onOpenChange(false);
      } else {
        toast.error(result.message || "업로드에 실패했습니다.");
      }
    } catch (error) {
      console.error("다중 테이블 업로드 실패:", error);
      toast.error("업로드 중 오류가 발생했습니다.");
    } finally {
      setIsUploading(false);
    }
  };

  // 카테고리 검증: 매핑된 컬럼 중 카테고리 타입인 것의 유효하지 않은 값 감지
  const validateCategoryColumns = async () => {
    try {
      setIsCategoryValidating(true);

      if (!selectedMode) return null;

      const mismatches: typeof categoryMismatches = {};

      // 활성 레벨별로 카테고리 컬럼 검증
      for (const levelIdx of selectedMode.activeLevels) {
        const level = config.levels[levelIdx];
        if (!level) continue;

        // 해당 테이블의 카테고리 타입 컬럼 조회
        const colResponse = await getTableColumns(level.tableName);
        if (!colResponse.success || !colResponse.data?.columns) continue;

        const categoryColumns = colResponse.data.columns.filter(
          (col: any) => col.inputType === "category"
        );
        if (categoryColumns.length === 0) continue;

        // 매핑된 컬럼 중 카테고리 타입인 것 찾기
        for (const catCol of categoryColumns) {
          const catColName = catCol.columnName || catCol.column_name;
          const catDisplayName = catCol.displayName || catCol.display_name || catColName;

          // level.columns에서 해당 dbColumn 찾기
          const levelCol = level.columns.find((lc) => lc.dbColumn === catColName);
          if (!levelCol) continue;

          // 매핑에서 해당 excelHeader에 연결된 엑셀 컬럼 찾기
          const mapping = columnMappings.find((m) => m.targetColumn === levelCol.excelHeader);
          if (!mapping) continue;

          // 유효한 카테고리 값 조회
          const valuesResponse = await getCategoryValues(level.tableName, catColName);
          if (!valuesResponse.success || !valuesResponse.data) continue;

          const validValues = flattenCategoryValues(valuesResponse.data as any[]);

          const validCodes = new Set(validValues.map((v) => v.valueCode));
          const validLabels = new Set(validValues.map((v) => v.valueLabel));
          const validLabelsLower = new Set(validValues.map((v) => v.valueLabel.toLowerCase()));

          // 엑셀 데이터에서 유효하지 않은 값 수집
          const invalidMap = new Map<string, number[]>();

          allData.forEach((row, rowIdx) => {
            const val = row[mapping.excelColumn];
            if (val === undefined || val === null || String(val).trim() === "") return;
            const strVal = String(val).trim();

            if (validCodes.has(strVal)) return;
            if (validLabels.has(strVal)) return;
            if (validLabelsLower.has(strVal.toLowerCase())) return;

            if (!invalidMap.has(strVal)) {
              invalidMap.set(strVal, []);
            }
            invalidMap.get(strVal)!.push(rowIdx);
          });

          if (invalidMap.size > 0) {
            const options = validValues.map((v) => ({
              code: v.valueCode,
              label: v.valueLabel,
              depth: v.depth,
              ancestors: v.ancestors,
            }));

            const key = `${catColName}|||[${level.label}] ${catDisplayName}`;
            mismatches[key] = Array.from(invalidMap.entries()).map(
              ([invalidValue, rowIndices]) => ({
                invalidValue,
                replacement: null,
                validOptions: options,
                rowIndices,
              })
            );
          }
        }
      }

      if (Object.keys(mismatches).length > 0) {
        return mismatches;
      }
      return null;
    } catch (error) {
      console.error("카테고리 검증 실패:", error);
      return null;
    } finally {
      setIsCategoryValidating(false);
    }
  };

  // 카테고리 대체값 적용
  const applyCategoryReplacements = () => {
    for (const [, items] of Object.entries(categoryMismatches)) {
      for (const item of items) {
        if (item.replacement === null) {
          toast.error("모든 항목의 대체 값을 선택해주세요.");
          return false;
        }
      }
    }

    // 시스템 컬럼명 → 엑셀 컬럼명 역매핑 구축
    const dbColToExcelCol = new Map<string, string>();
    if (selectedMode) {
      for (const levelIdx of selectedMode.activeLevels) {
        const level = config.levels[levelIdx];
        if (!level) continue;
        for (const lc of level.columns) {
          const mapping = columnMappings.find((m) => m.targetColumn === lc.excelHeader);
          if (mapping) {
            dbColToExcelCol.set(lc.dbColumn, mapping.excelColumn);
          }
        }
      }
    }

    const newData = allData.map((row) => ({ ...row }));

    for (const [key, items] of Object.entries(categoryMismatches)) {
      const systemCol = key.split("|||")[0];
      const excelCol = dbColToExcelCol.get(systemCol);
      if (!excelCol) continue;

      for (const item of items) {
        if (!item.replacement) continue;
        const selectedOption = item.validOptions.find((opt) => opt.code === item.replacement);
        const replacementLabel = selectedOption?.label || item.replacement;

        for (const rowIdx of item.rowIndices) {
          if (newData[rowIdx]) {
            newData[rowIdx][excelCol] = replacementLabel;
          }
        }
      }
    }

    setAllData(newData);
    setDisplayData(newData);
    setShowCategoryValidation(false);
    setCategoryMismatches({});
    toast.success("카테고리 값이 대체되었습니다. '다음'을 눌러 진행해주세요.");
    return true;
  };

  // 다음/이전 단계
  const handleNext = async () => {
    if (currentStep === 1) {
      if (!file) {
        toast.error("파일을 선택해주세요.");
        return;
      }
      if (displayData.length === 0) {
        toast.error("데이터가 없습니다.");
        return;
      }
    }

    if (currentStep === 2) {
      // 필수 컬럼 매핑 확인
      const mappedTargets = new Set(
        columnMappings.filter((m) => m.targetColumn).map((m) => m.targetColumn)
      );
      const unmappedRequired = activeColumns
        .filter((ac) => ac.required && !mappedTargets.has(ac.excelHeader))
        .map((ac) => `${ac.excelHeader}`);

      if (unmappedRequired.length > 0) {
        toast.error(`필수 컬럼이 매핑되지 않았습니다: ${unmappedRequired.join(", ")}`);
        return;
      }

      // 카테고리 컬럼 검증
      const mismatches = await validateCategoryColumns();
      if (mismatches) {
        setCategoryMismatches(mismatches);
        setShowCategoryValidation(true);
        return;
      }
    }

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

  const handlePrevious = () => {
    setCurrentStep((prev) => Math.max(prev - 1, 1));
  };

  // 모달 닫기 시 초기화
  useEffect(() => {
    if (!open) {
      setCurrentStep(1);
      setSelectedModeId(config.uploadModes[0]?.id || "");
      setFile(null);
      setSheetNames([]);
      setSelectedSheet("");
      setAllData([]);
      setDisplayData([]);
      setExcelColumns([]);
      setColumnMappings([]);
      setShowCategoryValidation(false);
      setCategoryMismatches({});
      setIsCategoryValidating(false);
    }
  }, [open, config.uploadModes]);

  return (
    <>
    <Dialog open={open} onOpenChange={(v) => { if (!showCategoryValidation) onOpenChange(v); }}>
      <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" />
            {config.name} - 엑셀 업로드
            <span className="ml-2 rounded bg-indigo-100 px-2 py-0.5 text-xs font-normal text-indigo-700">
              다중 테이블
            </span>
          </DialogTitle>
          <DialogDescription className="text-xs sm:text-sm">
            {config.description}
          </DialogDescription>
        </DialogHeader>

        {/* 스텝 인디케이터 */}
        <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">
              {/* 업로드 모드 선택 */}
              <div>
                <Label className="text-xs font-medium sm:text-sm">업로드 모드 *</Label>
                <div className="mt-2 grid gap-2 sm:grid-cols-3">
                  {config.uploadModes.map((mode) => (
                    <button
                      key={mode.id}
                      type="button"
                      onClick={() => {
                        setSelectedModeId(mode.id);
                        setFile(null);
                        setAllData([]);
                        setDisplayData([]);
                        setExcelColumns([]);
                      }}
                      className={cn(
                        "rounded-lg border p-3 text-left transition-all",
                        selectedModeId === mode.id
                          ? "border-primary bg-primary/5 ring-2 ring-primary/20"
                          : "border-border hover:border-primary/50 hover:bg-muted/50"
                      )}
                    >
                      <p className="text-xs font-semibold sm:text-sm">{mode.label}</p>
                      <p className="mt-1 text-[10px] text-muted-foreground sm:text-xs">
                        {mode.description}
                      </p>
                    </button>
                  ))}
                </div>
              </div>

              {/* 템플릿 다운로드 */}
              <div className="flex items-center justify-between rounded-md border border-muted bg-muted/30 p-3">
                <div className="flex items-center gap-2 text-xs text-muted-foreground sm:text-sm">
                  <Download className="h-4 w-4" />
                  <span>선택한 모드에 맞는 엑셀 양식을 다운로드하세요</span>
                </div>
                <Button
                  variant="outline"
                  size="sm"
                  onClick={handleDownloadTemplate}
                  className="h-8 text-xs sm:text-sm"
                >
                  <Download className="mr-1 h-3 w-3" />
                  템플릿 다운로드
                </Button>
              </div>

              {/* 파일 선택 */}
              <div>
                <Label htmlFor="multi-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="multi-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((name) => (
                            <SelectItem key={name} value={name} className="text-xs sm:text-sm">
                              {name}
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </div>
                    <span className="text-xs text-muted-foreground">
                      {displayData.length}개 행
                    </span>
                  </div>

                  <EditableSpreadsheet
                    columns={excelColumns}
                    data={displayData}
                    onColumnsChange={setExcelColumns}
                    onDataChange={(newData) => {
                      setDisplayData(newData);
                      setAllData(newData);
                    }}
                    maxHeight="250px"
                  />
                </>
              )}
            </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={performAutoMapping}
                  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] gap-2 text-[10px] font-medium text-muted-foreground sm:text-xs">
                  <div>엑셀 컬럼</div>
                  <div></div>
                  <div>시스템 컬럼</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] 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.targetColumn || "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.targetColumn || "매핑 안함"}
                          </SelectValue>
                        </SelectTrigger>
                        <SelectContent>
                          <SelectItem value="none" className="text-xs sm:text-sm">
                            매핑 안함
                          </SelectItem>
                          {activeColumns.map((ac) => (
                            <SelectItem
                              key={`${ac.levelLabel}-${ac.dbColumn}`}
                              value={ac.excelHeader}
                              className="text-xs sm:text-sm"
                            >
                              {ac.required && (
                                <span className="mr-1 text-destructive">*</span>
                              )}
                              [{ac.levelLabel}] {ac.excelHeader} ({ac.dbColumn})
                            </SelectItem>
                          ))}
                        </SelectContent>
                      </Select>
                    </div>
                  ))}
                </div>
              </div>

              {/* 미매핑 필수 컬럼 경고 */}
              {(() => {
                const mappedTargets = new Set(
                  columnMappings.filter((m) => m.targetColumn).map((m) => m.targetColumn)
                );
                const missing = activeColumns.filter(
                  (ac) => ac.required && !mappedTargets.has(ac.excelHeader)
                );
                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">필수 컬럼이 매핑되지 않았습니다:</p>
                        <p className="mt-1">
                          {missing.map((m) => `[${m.levelLabel}] ${m.excelHeader}`).join(", ")}
                        </p>
                      </div>
                    </div>
                  </div>
                );
              })()}

              {/* 모드 정보 */}
              {selectedMode && (
                <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">모드: {selectedMode.label}</p>
                      <p className="mt-1">
                        대상 테이블:{" "}
                        {selectedMode.activeLevels
                          .map((i) => config.levels[i]?.label)
                          .filter(Boolean)
                          .join(" → ")}
                      </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> {selectedMode?.label}</p>
                  <p>
                    <span className="font-medium">대상 테이블:</span>{" "}
                    {selectedMode?.activeLevels
                      .map((i) => {
                        const level = config.levels[i];
                        return level
                          ? `${level.label}(${level.tableName})`
                          : "";
                      })
                      .filter(Boolean)
                      .join(" → ")}
                  </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.targetColumn)
                    .map((mapping, idx) => {
                      const ac = activeColumns.find(
                        (c) => c.excelHeader === mapping.targetColumn
                      );
                      return (
                        <p key={idx}>
                          <span className="font-medium">{mapping.excelColumn}</span>{" "}
                          → [{ac?.levelLabel}] {mapping.targetColumn}
                        </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 || isCategoryValidating || (currentStep === 1 && !file)}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              {isCategoryValidating ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  검증 중...
                </>
              ) : (
                "다음"
              )}
            </Button>
          ) : (
            <Button
              onClick={handleUpload}
              disabled={isUploading || columnMappings.filter((m) => m.targetColumn).length === 0}
              className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
            >
              {isUploading ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  업로드 중...
                </>
              ) : (
                "업로드"
              )}
            </Button>
          )}
        </DialogFooter>
      </DialogContent>
    </Dialog>

    {/* 카테고리 대체값 선택 다이얼로그 */}
    <Dialog open={showCategoryValidation} onOpenChange={(open) => {
      if (!open) {
        setShowCategoryValidation(false);
        setCategoryMismatches({});
      }
    }}>
      <DialogContent className="max-w-[95vw] sm:max-w-[600px]">
        <DialogHeader>
          <DialogTitle className="flex items-center gap-2 text-base sm:text-lg">
            <AlertCircle className="h-5 w-5 text-warning" />
            존재하지 않는 카테고리 값 감지
          </DialogTitle>
          <DialogDescription className="text-xs sm:text-sm">
            엑셀 데이터에 등록되지 않은 카테고리 값이 있습니다. 각 항목에 대해 대체할 값을 선택해주세요.
          </DialogDescription>
        </DialogHeader>

        <div className="max-h-[400px] space-y-4 overflow-y-auto pr-1">
          {Object.entries(categoryMismatches).map(([key, items]) => {
            const [, displayName] = key.split("|||");
            return (
              <div key={key} className="space-y-2">
                <h4 className="text-sm font-semibold text-foreground">
                  {displayName}
                </h4>
                {items.map((item, idx) => (
                  <div
                    key={`${key}-${idx}`}
                    className="grid grid-cols-[1fr_auto_1fr] items-center gap-2 rounded-md border border-border bg-muted/30 p-2"
                  >
                    <div className="flex flex-col">
                      <span className="text-xs font-medium text-destructive line-through">
                        {item.invalidValue}
                      </span>
                      <span className="text-[10px] text-muted-foreground">
                        {item.rowIndices.length}건
                      </span>
                    </div>
                    <ArrowRight className="h-4 w-4 text-muted-foreground" />
                    <Popover>
                      <PopoverTrigger asChild>
                        <Button
                          variant="outline"
                          role="combobox"
                          className="h-8 w-full justify-between text-xs sm:h-9 sm:text-sm"
                        >
                          <span className="truncate">
                            {item.replacement
                              ? item.validOptions.find((o) => o.code === item.replacement)?.label || item.replacement
                              : "대체 값 선택"}
                          </span>
                          <ChevronsUpDown className="ml-1 h-3 w-3 shrink-0 opacity-50" />
                        </Button>
                      </PopoverTrigger>
                      <PopoverContent className="w-[260px] p-0" align="start">
                        <Command
                          filter={(value, search) => {
                            const opt = item.validOptions.find((o) => o.code === value);
                            if (!opt) return 0;
                            const s = search.toLowerCase();
                            if (opt.label.toLowerCase().includes(s)) return 1;
                            if (opt.ancestors.some((a) => a.toLowerCase().includes(s))) return 1;
                            return 0;
                          }}
                        >
                          <CommandInput placeholder="카테고리 검색..." className="text-xs" />
                          <CommandList className="max-h-52">
                            <CommandEmpty className="py-3 text-xs">찾을 수 없습니다</CommandEmpty>
                            <CommandGroup>
                              {item.validOptions.map((opt) => (
                                <CommandItem
                                  key={opt.code}
                                  value={opt.code}
                                  onSelect={(val) => {
                                    setCategoryMismatches((prev) => {
                                      const updated = { ...prev };
                                      updated[key] = updated[key].map((it, i) =>
                                        i === idx ? { ...it, replacement: val } : it
                                      );
                                      return updated;
                                    });
                                  }}
                                  className="text-xs sm:text-sm"
                                >
                                  <Check className={cn("mr-2 h-3 w-3", item.replacement === opt.code ? "opacity-100" : "opacity-0")} />
                                  <span style={{ paddingLeft: `${opt.depth * 12}px` }}>
                                    {opt.depth > 0 && <span className="mr-1 text-muted-foreground">ㄴ</span>}
                                    {opt.label}
                                  </span>
                                </CommandItem>
                              ))}
                            </CommandGroup>
                          </CommandList>
                        </Command>
                      </PopoverContent>
                    </Popover>
                  </div>
                ))}
              </div>
            );
          })}
        </div>

        <DialogFooter className="gap-2 sm:gap-0">
          <Button
            variant="outline"
            onClick={() => {
              setShowCategoryValidation(false);
              setCategoryMismatches({});
            }}
            className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
          >
            취소
          </Button>
          <Button
            onClick={applyCategoryReplacements}
            className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
          >
            적용
          </Button>
        </DialogFooter>
      </DialogContent>
    </Dialog>
    </>
  );
};
