"use client";

import React, { useState, useEffect, useCallback } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Badge } from "@/components/ui/badge";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import { Label } from "@/components/ui/label";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Separator } from "@/components/ui/separator";
import {
  Search,
  ChevronLeft,
  ChevronRight,
  RotateCcw,
  Database,
  Loader2,
  Plus,
  Edit,
  Trash2,
  File,
  Download,
  Eye,
  X,
  ZoomIn,
  ZoomOut,
  RotateCw,
} from "lucide-react";
import { tableTypeApi } from "@/lib/api/screen";
import { getCurrentUser, UserInfo } from "@/lib/api/client";
import { DataTableComponent, DataTableColumn, DataTableFilter } from "@/types/screen";
import { cn } from "@/lib/utils";
import { downloadFile } from "@/lib/api/file";
import { toast } from "sonner";

// 파일 데이터 타입 정의
interface FileInfo {
  id: string;
  name: string;
  size: number;
  type: string;
  extension: string;
  uploadedAt: string;
  lastModified: string;
  serverFilename?: string; // 서버에 저장된 파일명 (다운로드용)
}

interface FileColumnData {
  files: FileInfo[];
  totalCount: number;
  totalSize: number;
  lastModified: string;
}

interface InteractiveDataTableProps {
  component: DataTableComponent;
  className?: string;
  style?: React.CSSProperties;
}

export const InteractiveDataTable: React.FC<InteractiveDataTableProps> = ({
  component,
  className = "",
  style = {},
}) => {
  const [data, setData] = useState<Record<string, any>[]>([]);
  const [loading, setLoading] = useState(false);
  const [searchValues, setSearchValues] = useState<Record<string, any>>({});
  const [currentPage, setCurrentPage] = useState(1);
  const [totalPages, setTotalPages] = useState(1);
  const [total, setTotal] = useState(0);
  const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());
  const [showAddModal, setShowAddModal] = useState(false);
  const [addFormData, setAddFormData] = useState<Record<string, any>>({});
  const [isAdding, setIsAdding] = useState(false);
  const [showEditModal, setShowEditModal] = useState(false);
  const [editFormData, setEditFormData] = useState<Record<string, any>>({});
  const [editingRowData, setEditingRowData] = useState<Record<string, any> | null>(null);
  const [isEditing, setIsEditing] = useState(false);

  // 이미지 미리보기 상태
  const [previewImage, setPreviewImage] = useState<FileInfo | null>(null);
  const [showPreviewModal, setShowPreviewModal] = useState(false);
  const [zoom, setZoom] = useState(1);
  const [rotation, setRotation] = useState(0);

  // 이미지 미리보기 핸들러들
  const handlePreviewImage = useCallback((fileInfo: FileInfo) => {
    setPreviewImage(fileInfo);
    setShowPreviewModal(true);
    setZoom(1);
    setRotation(0);
  }, []);

  const closePreviewModal = useCallback(() => {
    setShowPreviewModal(false);
    setPreviewImage(null);
    setZoom(1);
    setRotation(0);
  }, []);

  const handleZoom = useCallback((direction: "in" | "out") => {
    setZoom((prev) => {
      if (direction === "in") {
        return Math.min(prev + 0.25, 3);
      } else {
        return Math.max(prev - 0.25, 0.25);
      }
    });
  }, []);

  const handleRotate = useCallback(() => {
    setRotation((prev) => (prev + 90) % 360);
  }, []);

  const formatFileSize = useCallback((bytes: number): string => {
    if (bytes === 0) return "0 Bytes";
    const k = 1024;
    const sizes = ["Bytes", "KB", "MB", "GB"];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + " " + sizes[i];
  }, []);
  const [showFileModal, setShowFileModal] = useState(false);
  const [currentFileData, setCurrentFileData] = useState<FileColumnData | null>(null);
  const [currentFileColumn, setCurrentFileColumn] = useState<DataTableColumn | null>(null);
  const [showDeleteDialog, setShowDeleteDialog] = useState(false);
  const [isDeleting, setIsDeleting] = useState(false);

  // 현재 사용자 정보
  const [currentUser, setCurrentUser] = useState<UserInfo | null>(null);

  // 테이블 컬럼 타입 정보 (웹 타입 포함)
  const [tableColumns, setTableColumns] = useState<any[]>([]);

  // 파일 업로드 관련 상태
  const [uploadingFiles, setUploadingFiles] = useState<Record<string, boolean>>({});
  const [uploadedFiles, setUploadedFiles] = useState<Record<string, File[]>>({});

  // 검색 가능한 컬럼만 필터링
  const visibleColumns = component.columns?.filter((col: DataTableColumn) => col.visible) || [];
  const searchFilters = component.filters || [];

  // 컬럼의 실제 웹 타입 정보 찾기
  const getColumnWebType = useCallback(
    (columnName: string) => {
      // 먼저 컴포넌트에 설정된 컬럼에서 찾기 (화면 관리에서 설정한 값 우선)
      const componentColumn = component.columns?.find((col) => col.columnName === columnName);
      if (componentColumn?.widgetType && componentColumn.widgetType !== "text") {
        return componentColumn.widgetType;
      }

      // 없으면 테이블 타입 관리에서 설정된 값 찾기
      const tableColumn = tableColumns.find((col) => col.columnName === columnName);
      return tableColumn?.webType || "text";
    },
    [component.columns, tableColumns],
  );

  // 컬럼의 상세 설정 정보 찾기
  const getColumnDetailSettings = useCallback(
    (columnName: string) => {
      // 먼저 컴포넌트에 설정된 컬럼에서 찾기 (화면 관리에서 설정한 값 우선)
      const componentColumn = component.columns?.find((col) => col.columnName === columnName);
      if (componentColumn?.webTypeConfig) {
        return componentColumn.webTypeConfig;
      }

      // 없으면 테이블 타입 관리에서 설정된 값 찾기
      const tableColumn = tableColumns.find((col) => col.columnName === columnName);
      try {
        return tableColumn?.detailSettings ? JSON.parse(tableColumn.detailSettings) : {};
      } catch {
        console.warn("상세 설정 파싱 실패:", tableColumn?.detailSettings);
        return {};
      }
    },
    [component.columns, tableColumns],
  );

  // 그리드 컬럼 계산
  const totalGridColumns = visibleColumns.reduce((sum, col) => sum + (col.gridColumns || 2), 0);

  // 페이지 크기 설정
  const pageSize = component.pagination?.pageSize || 10;

  // 데이터 로드 함수
  const loadData = useCallback(
    async (page: number = 1, searchParams: Record<string, any> = {}) => {
      if (!component.tableName) return;

      setLoading(true);
      try {
        console.log("🔍 테이블 데이터 조회:", {
          tableName: component.tableName,
          page,
          pageSize,
          searchParams,
        });

        const result = await tableTypeApi.getTableData(component.tableName, {
          page,
          size: pageSize,
          search: searchParams,
        });

        console.log("✅ 테이블 데이터 조회 결과:", result);

        setData(result.data);
        setTotal(result.total);
        setTotalPages(result.totalPages);
        setCurrentPage(result.page);
      } catch (error) {
        console.error("❌ 테이블 데이터 조회 실패:", error);
        setData([]);
        setTotal(0);
        setTotalPages(1);
      } finally {
        setLoading(false);
      }
    },
    [component.tableName, pageSize],
  );

  // 현재 사용자 정보 로드
  useEffect(() => {
    const fetchCurrentUser = async () => {
      try {
        const response = await getCurrentUser();
        if (response.success && response.data) {
          setCurrentUser(response.data);
        }
      } catch (error) {
        console.error("현재 사용자 정보 로드 실패:", error);
      }
    };

    fetchCurrentUser();
  }, []);

  // 테이블 컬럼 정보 로드 (웹 타입 정보 포함)
  useEffect(() => {
    const fetchTableColumns = async () => {
      try {
        console.log("🔄 테이블 컬럼 정보 로드 시작:", component.tableName);
        const columns = await tableTypeApi.getColumns(component.tableName);
        setTableColumns(columns);
        console.log("✅ 테이블 컬럼 정보 로드 완료:", columns);
      } catch (error) {
        console.error("테이블 컬럼 정보 로드 실패:", error);
      }
    };

    if (component.tableName) {
      fetchTableColumns();
    }
  }, [component.tableName]);

  // 초기 데이터 로드
  useEffect(() => {
    loadData(1, searchValues);
  }, [loadData]);

  // 검색 실행
  const handleSearch = useCallback(() => {
    console.log("🔍 검색 실행:", searchValues);
    loadData(1, searchValues);
  }, [searchValues, loadData]);

  // 검색값 변경
  const handleSearchValueChange = useCallback((columnName: string, value: any) => {
    setSearchValues((prev) => ({
      ...prev,
      [columnName]: value,
    }));
  }, []);

  // 페이지 변경
  const handlePageChange = useCallback(
    (page: number) => {
      loadData(page, searchValues);
    },
    [loadData, searchValues],
  );

  // 행 선택 핸들러
  const handleRowSelect = useCallback((rowIndex: number, isSelected: boolean) => {
    setSelectedRows((prev) => {
      const newSet = new Set(prev);
      if (isSelected) {
        newSet.add(rowIndex);
      } else {
        newSet.delete(rowIndex);
      }
      return newSet;
    });
  }, []);

  // 전체 선택/해제 핸들러
  const handleSelectAll = useCallback(
    (isSelected: boolean) => {
      if (isSelected) {
        setSelectedRows(new Set(Array.from({ length: data.length }, (_, i) => i)));
      } else {
        setSelectedRows(new Set());
      }
    },
    [data.length],
  );

  // 모달에 표시할 컬럼 계산
  const getDisplayColumns = useCallback(() => {
    const { hiddenFields, fieldOrder, advancedFieldConfigs } = component.addModalConfig || {};

    // 숨겨진 필드와 고급 설정에서 숨겨진 필드 제외
    let displayColumns = visibleColumns.filter((col) => {
      // 기본 숨김 필드 체크
      if (hiddenFields?.includes(col.columnName)) return false;

      // 고급 설정에서 숨김 체크
      const config = advancedFieldConfigs?.[col.columnName];
      if (config?.inputType === "hidden") return false;

      return true;
    });

    // 필드 순서 적용
    if (fieldOrder && fieldOrder.length > 0) {
      const orderedColumns: typeof displayColumns = [];
      const remainingColumns = [...displayColumns];

      // 지정된 순서대로 추가
      fieldOrder.forEach((columnName) => {
        const column = remainingColumns.find((col) => col.columnName === columnName);
        if (column) {
          orderedColumns.push(column);
          const index = remainingColumns.indexOf(column);
          remainingColumns.splice(index, 1);
        }
      });

      // 나머지 컬럼들 추가
      orderedColumns.push(...remainingColumns);
      displayColumns = orderedColumns;
    }

    return displayColumns;
  }, [visibleColumns, component.addModalConfig]);

  // 자동 값 생성
  const generateAutoValue = useCallback(
    (autoValueType: string): string => {
      const now = new Date();
      switch (autoValueType) {
        case "current_datetime":
          return now.toISOString().slice(0, 19); // YYYY-MM-DDTHH:mm:ss
        case "current_date":
          return now.toISOString().slice(0, 10); // YYYY-MM-DD
        case "current_time":
          return now.toTimeString().slice(0, 8); // HH:mm:ss
        case "current_user":
          return currentUser?.userName || currentUser?.userId || "unknown_user";
        case "uuid":
          return crypto.randomUUID();
        case "sequence":
          return `SEQ_${Date.now()}`;
        default:
          return "";
      }
    },
    [currentUser],
  );

  // 데이터 추가 핸들러
  const handleAddData = useCallback(() => {
    // 폼 데이터 초기화
    const initialData: Record<string, any> = {};
    const displayColumns = getDisplayColumns();
    const advancedConfigs = component.addModalConfig?.advancedFieldConfigs || {};

    displayColumns.forEach((col) => {
      const config = advancedConfigs[col.columnName];

      if (config?.inputType === "auto") {
        // 자동 값 설정
        if (config.autoValueType === "custom") {
          initialData[col.columnName] = config.customValue || "";
        } else {
          initialData[col.columnName] = generateAutoValue(config.autoValueType);
        }
      } else if (config?.defaultValue) {
        // 기본값 설정
        initialData[col.columnName] = config.defaultValue;
      } else {
        // 일반 빈 값
        initialData[col.columnName] = "";
      }
    });

    setAddFormData(initialData);
    setShowAddModal(true);
  }, [getDisplayColumns, generateAutoValue, component.addModalConfig]);

  // 추가 폼 데이터 변경 핸들러
  const handleAddFormChange = useCallback((columnName: string, value: any) => {
    setAddFormData((prev) => ({
      ...prev,
      [columnName]: value,
    }));
  }, []);

  // 데이터 수정 핸들러
  const handleEditData = useCallback(() => {
    if (selectedRows.size !== 1) return;

    const selectedIndex = Array.from(selectedRows)[0];
    const selectedRowData = data[selectedIndex];

    if (!selectedRowData) return;

    // 수정할 데이터로 폼 초기화
    const initialData: Record<string, any> = {};
    const displayColumns = getDisplayColumns();

    displayColumns.forEach((col) => {
      initialData[col.columnName] = selectedRowData[col.columnName] || "";
    });

    setEditFormData(initialData);
    setEditingRowData(selectedRowData);
    setShowEditModal(true);
  }, [selectedRows, data, getDisplayColumns]);

  // 수정 폼 데이터 변경 핸들러
  const handleEditFormChange = useCallback((columnName: string, value: any) => {
    setEditFormData((prev) => ({
      ...prev,
      [columnName]: value,
    }));
  }, []);

  // 파일 업로드 핸들러
  const handleFileUpload = useCallback(
    async (columnName: string, files: FileList | null, isEdit: boolean = false) => {
      if (!files || files.length === 0) return;

      const detailSettings = getColumnDetailSettings(columnName);
      const maxSize = detailSettings?.maxSize || 10 * 1024 * 1024; // 기본 10MB
      const acceptedTypes = detailSettings?.accept
        ? detailSettings.accept.split(",").map((type: string) => type.trim())
        : [];
      const multiple = detailSettings?.multiple || false;

      // 파일 검증
      const validFiles: File[] = [];
      for (let i = 0; i < files.length; i++) {
        const file = files[i];

        // 크기 체크
        if (file.size > maxSize) {
          alert(`파일 크기가 너무 큽니다. 최대 ${Math.round(maxSize / 1024 / 1024)}MB까지 가능합니다.`);
          continue;
        }

        // 타입 체크
        if (
          acceptedTypes.length > 0 &&
          !acceptedTypes.some((type: string) => {
            if (type.startsWith(".")) {
              return file.name.toLowerCase().endsWith(type.toLowerCase());
            } else {
              return file.type.includes(type);
            }
          })
        ) {
          alert(`지원하지 않는 파일 형식입니다. (${acceptedTypes.join(", ")})`);
          continue;
        }

        validFiles.push(file);
        if (!multiple) break; // 단일 파일만 허용
      }

      if (validFiles.length === 0) return;

      try {
        setUploadingFiles((prev) => ({ ...prev, [columnName]: true }));

        // TODO: 실제 파일 업로드 API 호출
        // const uploadPromises = validFiles.map(file => uploadFileToServer(file));
        // const uploadResults = await Promise.all(uploadPromises);

        // 임시: 파일 정보를 로컬 상태에 저장
        setUploadedFiles((prev) => ({
          ...prev,
          [columnName]: multiple ? [...(prev[columnName] || []), ...validFiles] : validFiles,
        }));

        // 폼 데이터 업데이트
        const fileNames = validFiles.map((file) => file.name).join(", ");
        if (isEdit) {
          handleEditFormChange(columnName, fileNames);
        } else {
          handleAddFormChange(columnName, fileNames);
        }

        console.log("✅ 파일 업로드 완료:", validFiles);
      } catch (error) {
        console.error("파일 업로드 실패:", error);
        alert("파일 업로드에 실패했습니다.");
      } finally {
        setUploadingFiles((prev) => ({ ...prev, [columnName]: false }));
      }
    },
    [getColumnDetailSettings, handleAddFormChange, handleEditFormChange],
  );

  // 파일 제거 핸들러
  const handleFileRemove = useCallback(
    (columnName: string, fileIndex: number, isEdit: boolean = false) => {
      setUploadedFiles((prev) => {
        const currentFiles = prev[columnName] || [];
        const newFiles = currentFiles.filter((_, index) => index !== fileIndex);

        // 폼 데이터 업데이트
        const fileNames = newFiles.map((file) => file.name).join(", ");
        if (isEdit) {
          handleEditFormChange(columnName, fileNames);
        } else {
          handleAddFormChange(columnName, fileNames);
        }

        return { ...prev, [columnName]: newFiles };
      });
    },
    [handleAddFormChange, handleEditFormChange],
  );

  // 파일 목록 렌더링 컴포넌트
  const renderFileList = useCallback(
    (columnName: string, isEdit: boolean = false) => {
      const currentFiles = uploadedFiles[columnName] || [];
      const isUploading = uploadingFiles[columnName];

      if (currentFiles.length === 0 && !isUploading) return null;

      return (
        <div className="mt-2 space-y-2">
          {currentFiles.map((file, index) => (
            <div key={index} className="flex items-center justify-between rounded border bg-gray-50 p-2">
              <div className="flex items-center space-x-2">
                <div className="text-xs text-gray-600">📄</div>
                <div>
                  <p className="text-sm font-medium">{file.name}</p>
                  <p className="text-xs text-gray-500">{(file.size / 1024).toFixed(1)} KB</p>
                </div>
              </div>
              <Button
                type="button"
                variant="ghost"
                size="sm"
                onClick={() => handleFileRemove(columnName, index, isEdit)}
                className="h-6 w-6 p-0"
              >
                <Trash2 className="h-3 w-3" />
              </Button>
            </div>
          ))}
          {isUploading && (
            <div className="flex items-center space-x-2 rounded border bg-blue-50 p-2">
              <Loader2 className="h-4 w-4 animate-spin" />
              <span className="text-sm text-blue-600">업로드 중...</span>
            </div>
          )}
        </div>
      );
    },
    [uploadedFiles, uploadingFiles, handleFileRemove],
  );

  // 데이터 추가 제출 핸들러
  const handleAddSubmit = useCallback(async () => {
    try {
      setIsAdding(true);

      // 실제 API 호출로 데이터 추가
      console.log("🔥 추가할 데이터:", addFormData);
      await tableTypeApi.addTableData(component.tableName, addFormData);

      // 모달 닫기 및 폼 초기화
      setShowAddModal(false);
      setAddFormData({});

      // 첫 페이지로 이동하여 새 데이터 확인
      loadData(1, searchValues);
    } catch (error) {
      console.error("데이터 추가 실패:", error);
      alert("데이터 추가에 실패했습니다.");
    } finally {
      setIsAdding(false);
    }
  }, [addFormData, loadData, searchValues]);

  // 데이터 수정 제출 핸들러
  const handleEditSubmit = useCallback(async () => {
    try {
      setIsEditing(true);

      // 실제 API 호출로 데이터 수정
      console.log("🔥 수정할 데이터:", editFormData);
      console.log("🔥 원본 데이터:", editingRowData);

      if (editingRowData) {
        await tableTypeApi.editTableData(component.tableName, editingRowData, editFormData);

        // 모달 닫기 및 폼 초기화
        setShowEditModal(false);
        setEditFormData({});
        setEditingRowData(null);
        setSelectedRows(new Set()); // 선택 해제

        // 현재 페이지 데이터 새로고침
        loadData(currentPage, searchValues);
      }
    } catch (error) {
      console.error("데이터 수정 실패:", error);
      alert("데이터 수정에 실패했습니다.");
    } finally {
      setIsEditing(false);
    }
  }, [editFormData, editingRowData, component.tableName, currentPage, searchValues, loadData]);

  // 추가 모달 닫기 핸들러
  const handleAddModalClose = useCallback(() => {
    if (!isAdding) {
      setShowAddModal(false);
      setAddFormData({});
      setUploadedFiles({}); // 파일 상태 초기화
    }
  }, [isAdding]);

  // 데이터 삭제 핸들러
  const handleDeleteData = useCallback(() => {
    if (selectedRows.size === 0) {
      alert("삭제할 데이터를 선택해주세요.");
      return;
    }
    setShowDeleteDialog(true);
  }, [selectedRows.size]);

  // 삭제 확인 핸들러
  const handleDeleteConfirm = useCallback(async () => {
    try {
      setIsDeleting(true);

      // 선택된 행의 실제 데이터 가져오기
      const selectedData = Array.from(selectedRows).map((index) => data[index]);

      // 실제 삭제 API 호출
      console.log("🗑️ 삭제할 데이터:", selectedData);
      await tableTypeApi.deleteTableData(component.tableName, selectedData);

      // 선택 해제 및 다이얼로그 닫기
      setSelectedRows(new Set());
      setShowDeleteDialog(false);

      // 데이터 새로고침
      loadData(currentPage, searchValues);
    } catch (error) {
      console.error("데이터 삭제 실패:", error);
      alert("데이터 삭제에 실패했습니다.");
    } finally {
      setIsDeleting(false);
    }
  }, [selectedRows, data, currentPage, searchValues, loadData]);

  // 삭제 다이얼로그 닫기 핸들러
  const handleDeleteDialogClose = useCallback(() => {
    if (!isDeleting) {
      setShowDeleteDialog(false);
    }
  }, [isDeleting]);

  // 필수 필드 여부 확인
  const isRequiredField = useCallback(
    (columnName: string) => {
      return component.addModalConfig?.requiredFields?.includes(columnName) || false;
    },
    [component.addModalConfig],
  );

  // 모달 크기 클래스 가져오기
  const getModalSizeClass = useCallback(() => {
    const width = component.addModalConfig?.width || "lg";
    const sizeMap = {
      sm: "max-w-sm",
      md: "max-w-md",
      lg: "max-w-lg",
      xl: "max-w-xl",
      "2xl": "max-w-2xl",
      full: "max-w-full mx-4",
    };
    return sizeMap[width];
  }, [component.addModalConfig]);

  // 레이아웃 클래스 가져오기
  const getLayoutClass = useCallback(() => {
    const layout = component.addModalConfig?.layout || "two-column";
    const gridColumns = component.addModalConfig?.gridColumns || 2;

    switch (layout) {
      case "single":
        return "grid grid-cols-1 gap-4";
      case "two-column":
        return "grid grid-cols-2 gap-4";
      case "grid":
        return `grid grid-cols-${Math.min(gridColumns, 4)} gap-4`;
      default:
        return "grid grid-cols-2 gap-4";
    }
  }, [component.addModalConfig]);

  // 수정 폼 입력 컴포넌트 렌더링
  const renderEditFormInput = (column: DataTableColumn) => {
    const value = editFormData[column.columnName] || "";
    const isRequired = isRequiredField(column.columnName);
    const advancedConfig = component.addModalConfig?.advancedFieldConfigs?.[column.columnName];

    // 데이터베이스에서 실제 웹 타입 가져오기
    const actualWebType = getColumnWebType(column.columnName);
    const detailSettings = getColumnDetailSettings(column.columnName);

    // 자동 생성 필드는 수정에서 읽기 전용으로 처리
    if (advancedConfig?.inputType === "auto") {
      return (
        <div className="relative">
          <Input
            value={value}
            readOnly
            className="bg-gray-50 text-gray-700"
            placeholder={`${column.label} (자동 생성됨)`}
          />
          <p className="mt-1 text-xs text-gray-500">자동 생성된 필드는 수정할 수 없습니다.</p>
        </div>
      );
    }

    // 읽기 전용 필드
    if (advancedConfig?.inputType === "readonly") {
      return (
        <div className="relative">
          <Input
            value={value}
            readOnly
            className="bg-gray-50 text-gray-700"
            placeholder={advancedConfig?.placeholder || `${column.label} (읽기 전용)`}
          />
          {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
        </div>
      );
    }

    // 일반 입력 필드 렌더링
    const commonProps = {
      value,
      onChange: (e: React.ChangeEvent<HTMLInputElement>) => handleEditFormChange(column.columnName, e.target.value),
      placeholder: advancedConfig?.placeholder || `${column.label} 입력...`,
      required: isRequired,
      className: isRequired && !value ? "border-orange-300 focus:border-orange-500" : "",
    };

    // 실제 웹 타입에 따라 입력 컴포넌트 렌더링
    switch (actualWebType) {
      case "text":
      case "email":
      case "tel":
        return (
          <div>
            <Input
              type={actualWebType === "email" ? "email" : actualWebType === "tel" ? "tel" : "text"}
              {...commonProps}
              maxLength={detailSettings?.maxLength}
            />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "number":
      case "decimal":
        return (
          <div>
            <Input
              type="number"
              step={actualWebType === "decimal" ? detailSettings?.step || "0.01" : "1"}
              min={detailSettings?.min}
              max={detailSettings?.max}
              {...commonProps}
            />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "date":
        return (
          <div>
            <Input type="date" min={detailSettings?.minDate} max={detailSettings?.maxDate} {...commonProps} />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "datetime":
        return (
          <div>
            <Input type="datetime-local" min={detailSettings?.minDate} max={detailSettings?.maxDate} {...commonProps} />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "select":
      case "dropdown":
        // 상세 설정에서 옵션 목록 가져오기
        const options = detailSettings?.options || [];
        if (options.length > 0) {
          return (
            <div>
              <Select value={value} onValueChange={(newValue) => handleEditFormChange(column.columnName, newValue)}>
                <SelectTrigger className={commonProps.className}>
                  <SelectValue placeholder={commonProps.placeholder} />
                </SelectTrigger>
                <SelectContent>
                  {options.map((option: any, index: number) => (
                    <SelectItem key={index} value={option.value || option}>
                      {option.label || option}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
            </div>
          );
        } else {
          return <Input {...commonProps} placeholder={`${column.label} 선택... (옵션 설정 필요)`} readOnly />;
        }

      case "radio":
        // 상세 설정에서 옵션 목록 가져오기
        const radioOptions = detailSettings?.options || [];
        if (radioOptions.length > 0) {
          return (
            <div>
              <div className="space-y-2">
                {radioOptions.map((option: any, index: number) => (
                  <div key={index} className="flex items-center space-x-2">
                    <input
                      type="radio"
                      id={`${column.columnName}-edit-${index}`}
                      name={`${column.columnName}-edit`}
                      value={option.value || option}
                      checked={value === (option.value || option)}
                      onChange={(e) => handleEditFormChange(column.columnName, e.target.value)}
                      className="text-primary focus:ring-primary"
                    />
                    <Label htmlFor={`${column.columnName}-edit-${index}`} className="text-sm">
                      {option.label || option}
                    </Label>
                  </div>
                ))}
              </div>
              {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
            </div>
          );
        } else {
          return <Input {...commonProps} placeholder={`${column.label} 선택... (옵션 설정 필요)`} readOnly />;
        }

      case "textarea":
        return (
          <div>
            <textarea
              value={value}
              onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
                handleEditFormChange(column.columnName, e.target.value)
              }
              placeholder={advancedConfig?.placeholder || `${column.label} 입력...`}
              required={isRequired}
              className={`border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[80px] w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 ${
                isRequired && !value ? "border-orange-300 focus:border-orange-500" : ""
              }`}
              rows={detailSettings?.rows || 3}
              maxLength={detailSettings?.maxLength}
            />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "boolean":
      case "checkbox":
        return (
          <div className="flex items-center space-x-2">
            <Checkbox
              checked={value === true || value === "true" || value === 1}
              onCheckedChange={(checked) => handleEditFormChange(column.columnName, checked)}
            />
            <Label>{column.label}</Label>
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "file":
        return (
          <div>
            <div className="space-y-2">
              <div className="flex items-center space-x-2">
                <Input
                  type="file"
                  accept={detailSettings?.accept}
                  multiple={detailSettings?.multiple}
                  onChange={(e) => handleFileUpload(column.columnName, e.target.files, true)}
                  className="hidden"
                  id={`file-edit-${column.columnName}`}
                />
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() => document.getElementById(`file-edit-${column.columnName}`)?.click()}
                  disabled={uploadingFiles[column.columnName]}
                  className="gap-2"
                >
                  {uploadingFiles[column.columnName] ? (
                    <Loader2 className="h-4 w-4 animate-spin" />
                  ) : (
                    <Plus className="h-4 w-4" />
                  )}
                  파일 선택
                </Button>
                {detailSettings?.accept && <span className="text-xs text-gray-500">({detailSettings.accept})</span>}
              </div>
              {renderFileList(column.columnName, true)}
            </div>
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      default:
        return (
          <div>
            <Input {...commonProps} />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );
    }
  };

  // 추가 폼 입력 컴포넌트 렌더링
  const renderAddFormInput = (column: DataTableColumn) => {
    const value = addFormData[column.columnName] || "";
    const isRequired = isRequiredField(column.columnName);
    const advancedConfig = component.addModalConfig?.advancedFieldConfigs?.[column.columnName];

    // 데이터베이스에서 실제 웹 타입 가져오기
    const actualWebType = getColumnWebType(column.columnName);
    const detailSettings = getColumnDetailSettings(column.columnName);

    // 읽기 전용 또는 자동 값인 경우
    if (advancedConfig?.inputType === "readonly" || advancedConfig?.inputType === "auto") {
      return (
        <div className="relative">
          <Input
            value={value}
            readOnly
            className="bg-gray-50 text-gray-700"
            placeholder={advancedConfig?.placeholder || `${column.label} (자동 생성)`}
          />
          {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
        </div>
      );
    }

    // 일반 입력 필드 렌더링
    const commonProps = {
      value,
      onChange: (e: React.ChangeEvent<HTMLInputElement>) => handleAddFormChange(column.columnName, e.target.value),
      placeholder: advancedConfig?.placeholder || `${column.label} 입력...`,
      required: isRequired,
      className: isRequired && !value ? "border-orange-300 focus:border-orange-500" : "",
    };

    // 실제 웹 타입에 따라 입력 컴포넌트 렌더링
    switch (actualWebType) {
      case "text":
      case "email":
      case "tel":
        return (
          <div>
            <Input
              type={actualWebType === "email" ? "email" : actualWebType === "tel" ? "tel" : "text"}
              {...commonProps}
              maxLength={detailSettings?.maxLength}
            />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "number":
      case "decimal":
        return (
          <div>
            <Input
              type="number"
              step={actualWebType === "decimal" ? detailSettings?.step || "0.01" : "1"}
              min={detailSettings?.min}
              max={detailSettings?.max}
              {...commonProps}
            />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "date":
        return (
          <div>
            <Input type="date" min={detailSettings?.minDate} max={detailSettings?.maxDate} {...commonProps} />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "datetime":
        return (
          <div>
            <Input type="datetime-local" min={detailSettings?.minDate} max={detailSettings?.maxDate} {...commonProps} />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "select":
      case "dropdown":
        // 상세 설정에서 옵션 목록 가져오기
        const options = detailSettings?.options || [];
        if (options.length > 0) {
          return (
            <div>
              <Select value={value} onValueChange={(newValue) => handleAddFormChange(column.columnName, newValue)}>
                <SelectTrigger className={commonProps.className}>
                  <SelectValue placeholder={commonProps.placeholder} />
                </SelectTrigger>
                <SelectContent>
                  {options.map((option: any, index: number) => (
                    <SelectItem key={index} value={option.value || option}>
                      {option.label || option}
                    </SelectItem>
                  ))}
                </SelectContent>
              </Select>
              {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
            </div>
          );
        } else {
          return <Input {...commonProps} placeholder={`${column.label} 선택... (옵션 설정 필요)`} readOnly />;
        }

      case "radio":
        // 상세 설정에서 옵션 목록 가져오기
        const radioOptions = detailSettings?.options || [];
        const defaultValue = detailSettings?.defaultValue;

        // 추가 모달에서는 기본값이 있으면 초기값으로 설정
        if (radioOptions.length > 0) {
          // 폼 데이터에 값이 없고 기본값이 있으면 기본값 설정
          if (!value && defaultValue) {
            setTimeout(() => handleAddFormChange(column.columnName, defaultValue), 0);
          }

          return (
            <div>
              <div className="space-y-2">
                {radioOptions.map((option: any, index: number) => (
                  <div key={index} className="flex items-center space-x-2">
                    <input
                      type="radio"
                      id={`${column.columnName}-add-${index}`}
                      name={`${column.columnName}-add`}
                      value={option.value || option}
                      checked={value === (option.value || option)}
                      onChange={(e) => handleAddFormChange(column.columnName, e.target.value)}
                      className="text-primary focus:ring-primary"
                    />
                    <Label htmlFor={`${column.columnName}-add-${index}`} className="text-sm">
                      {option.label || option}
                    </Label>
                  </div>
                ))}
              </div>
              {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
            </div>
          );
        } else {
          return <Input {...commonProps} placeholder={`${column.label} 선택... (옵션 설정 필요)`} readOnly />;
        }

      case "boolean":
      case "checkbox":
        return (
          <div className="flex items-center space-x-2">
            <Checkbox
              checked={value === true || value === "true" || value === 1}
              onCheckedChange={(checked) => handleAddFormChange(column.columnName, checked)}
            />
            <Label>{column.label}</Label>
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "textarea":
        return (
          <div>
            <textarea
              value={value}
              onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) =>
                handleAddFormChange(column.columnName, e.target.value)
              }
              placeholder={advancedConfig?.placeholder || `${column.label} 입력...`}
              required={isRequired}
              className={`border-input bg-background ring-offset-background placeholder:text-muted-foreground focus-visible:ring-ring flex min-h-[80px] w-full rounded-md border px-3 py-2 text-sm focus-visible:ring-2 focus-visible:ring-offset-2 focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50 ${
                isRequired && !value ? "border-orange-300 focus:border-orange-500" : ""
              }`}
              rows={detailSettings?.rows || 3}
              maxLength={detailSettings?.maxLength}
            />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      case "file":
        return (
          <div>
            <div className="space-y-2">
              <div className="flex items-center space-x-2">
                <Input
                  type="file"
                  accept={detailSettings?.accept}
                  multiple={detailSettings?.multiple}
                  onChange={(e) => handleFileUpload(column.columnName, e.target.files, false)}
                  className="hidden"
                  id={`file-add-${column.columnName}`}
                />
                <Button
                  type="button"
                  variant="outline"
                  size="sm"
                  onClick={() => document.getElementById(`file-add-${column.columnName}`)?.click()}
                  disabled={uploadingFiles[column.columnName]}
                  className="gap-2"
                >
                  {uploadingFiles[column.columnName] ? (
                    <Loader2 className="h-4 w-4 animate-spin" />
                  ) : (
                    <Plus className="h-4 w-4" />
                  )}
                  파일 선택
                </Button>
                {detailSettings?.accept && <span className="text-xs text-gray-500">({detailSettings.accept})</span>}
              </div>
              {renderFileList(column.columnName, false)}
            </div>
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );

      default:
        return (
          <div>
            <Input {...commonProps} />
            {advancedConfig?.helpText && <p className="mt-1 text-xs text-gray-500">{advancedConfig.helpText}</p>}
          </div>
        );
    }
  };

  // 검색 필터 렌더링
  const renderSearchFilter = (filter: DataTableFilter) => {
    const value = searchValues[filter.columnName] || "";

    switch (filter.widgetType) {
      case "text":
      case "email":
      case "tel":
        return (
          <Input
            key={filter.columnName}
            placeholder={`${filter.label} 검색...`}
            value={value}
            onChange={(e) => handleSearchValueChange(filter.columnName, e.target.value)}
            onKeyPress={(e) => {
              if (e.key === "Enter") {
                handleSearch();
              }
            }}
          />
        );

      case "number":
      case "decimal":
        return (
          <Input
            key={filter.columnName}
            type="number"
            placeholder={`${filter.label} 입력...`}
            value={value}
            onChange={(e) => handleSearchValueChange(filter.columnName, e.target.value)}
            onKeyPress={(e) => {
              if (e.key === "Enter") {
                handleSearch();
              }
            }}
          />
        );

      case "date":
        return (
          <Input
            key={filter.columnName}
            type="date"
            value={value}
            onChange={(e) => handleSearchValueChange(filter.columnName, e.target.value)}
          />
        );

      case "datetime":
        return (
          <Input
            key={filter.columnName}
            type="datetime-local"
            value={value}
            onChange={(e) => handleSearchValueChange(filter.columnName, e.target.value)}
          />
        );

      case "select":
        // TODO: 선택 옵션은 추후 구현
        return (
          <Select
            key={filter.columnName}
            value={value}
            onValueChange={(newValue) => handleSearchValueChange(filter.columnName, newValue)}
          >
            <SelectTrigger>
              <SelectValue placeholder={`${filter.label} 선택...`} />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="">전체</SelectItem>
              {/* TODO: 동적 옵션 로드 */}
            </SelectContent>
          </Select>
        );

      default:
        return (
          <Input
            key={filter.columnName}
            placeholder={`${filter.label} 검색...`}
            value={value}
            onChange={(e) => handleSearchValueChange(filter.columnName, e.target.value)}
            onKeyPress={(e) => {
              if (e.key === "Enter") {
                handleSearch();
              }
            }}
          />
        );
    }
  };

  // 파일 모달 열기
  const openFileModal = (fileData: FileColumnData, column: DataTableColumn) => {
    setCurrentFileData(fileData);
    setCurrentFileColumn(column);
    setShowFileModal(true);
  };

  // 파일 다운로드
  const handleDownloadFile = useCallback(async (fileInfo: FileInfo) => {
    try {
      console.log("📥 파일 다운로드 시작:", fileInfo);

      // serverFilename이 없는 경우 처리
      if (!fileInfo.serverFilename) {
        // _file 속성이 있는 경우 로컬 파일로 다운로드
        if ((fileInfo as any)._file) {
          console.log("📁 로컬 파일 다운로드 시도:", fileInfo.name);
          try {
            const file = (fileInfo as any)._file;

            // File 객체 유효성 검사
            if (!(file instanceof File) && !(file instanceof Blob)) {
              console.error("❌ 잘못된 파일 객체:", file);
              toast.error("파일 객체가 손상되었습니다. 파일을 다시 업로드해주세요.");
              return;
            }

            console.log("📁 유효한 파일 객체 확인됨:", {
              name: file.name || fileInfo.name,
              size: file.size,
              type: file.type,
            });

            const url = URL.createObjectURL(file);
            const link = document.createElement("a");
            link.href = url;
            link.download = fileInfo.name || file.name || "download";
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
            URL.revokeObjectURL(url);
            toast.success(`${fileInfo.name} 다운로드가 완료되었습니다.`);
            return;
          } catch (error) {
            console.error("❌ 로컬 파일 다운로드 오류:", error);
            toast.error("로컬 파일 다운로드에 실패했습니다. 파일을 다시 업로드해주세요.");
            return;
          }
        }

        toast.error("이 파일은 이전 버전에서 저장된 파일입니다. 파일을 다시 업로드해주세요.");
        return;
      }

      toast.loading(`${fileInfo.name} 다운로드 중...`);

      await downloadFile({
        fileId: fileInfo.id,
        serverFilename: fileInfo.serverFilename,
        originalName: fileInfo.name,
      });

      toast.success(`${fileInfo.name} 다운로드가 완료되었습니다.`);
    } catch (error) {
      console.error("파일 다운로드 오류:", error);
      toast.error(`${fileInfo.name} 다운로드에 실패했습니다.`);
    }
  }, []);

  // 셀 값 포맷팅
  const formatCellValue = (value: any, column: DataTableColumn): React.ReactNode => {
    if (value === null || value === undefined) return "";

    // 디버깅을 위한 로그 추가
    if (column.columnName === "file_path") {
      console.log("📊 formatCellValue (file_path 컬럼):", {
        columnName: column.columnName,
        widgetType: column.widgetType,
        value: value,
        valueType: typeof value,
        fullColumn: column,
      });
    }

    // file_path 컬럼은 강제로 파일 타입으로 처리 (임시 해결책)
    const isFileColumn = column.widgetType === "file" || column.columnName === "file_path";

    switch (column.widgetType) {
      case "file":
        console.log("🗂️ 파일 타입 컬럼 처리 중:", value);
        if (value) {
          try {
            // JSON 문자열이면 파싱
            const fileData = typeof value === "string" ? JSON.parse(value) : value;
            console.log("📁 파싱된 파일 데이터:", fileData);

            if (fileData?.files && Array.isArray(fileData.files) && fileData.files.length > 0) {
              return (
                <div className="flex items-center gap-2">
                  <Button
                    variant="ghost"
                    size="sm"
                    className="h-8 px-2 text-blue-600 hover:bg-blue-50 hover:text-blue-800"
                    onClick={() => openFileModal(fileData, column)}
                  >
                    <File className="mr-1 h-4 w-4" />
                    {fileData.totalCount === 1 ? "파일 1개" : `파일 ${fileData.totalCount}개`}
                  </Button>
                  <Badge variant="secondary" className="text-xs">
                    {(fileData.totalSize / 1024 / 1024).toFixed(1)}MB
                  </Badge>
                </div>
              );
            }
          } catch (error) {
            console.warn("파일 데이터 파싱 오류:", error);
          }
        }
        return <span className="text-sm text-gray-400 italic">파일 없음</span>;

      case "date":
        if (value) {
          try {
            const date = new Date(value);
            return date.toLocaleDateString("ko-KR");
          } catch {
            return value;
          }
        }
        break;

      case "datetime":
        if (value) {
          try {
            const date = new Date(value);
            return date.toLocaleString("ko-KR");
          } catch {
            return value;
          }
        }
        break;

      case "number":
      case "decimal":
        if (typeof value === "number") {
          return value.toLocaleString();
        }
        break;

      default:
        return String(value);
    }

    return String(value);
  };

  return (
    <Card className={cn("flex h-full flex-col", className)} style={{ ...style, minHeight: "680px" }}>
      {/* 헤더 */}
      <CardHeader className="pb-3">
        <div className="flex items-center justify-between">
          <div className="flex items-center space-x-2">
            <Database className="text-muted-foreground h-4 w-4" />
            <CardTitle className="text-lg">{component.title || component.label}</CardTitle>
            {loading && (
              <Badge variant="secondary" className="flex items-center gap-1">
                <Loader2 className="h-3 w-3 animate-spin" />
                로딩중...
              </Badge>
            )}
          </div>
          <div className="flex items-center space-x-2">
            {/* 선택된 행 개수 표시 */}
            {selectedRows.size > 0 && (
              <Badge variant="secondary" className="text-xs">
                {selectedRows.size}개 선택됨
              </Badge>
            )}

            {searchFilters.length > 0 && (
              <Badge variant="outline" className="text-xs">
                <Search className="mr-1 h-3 w-3" />
                필터 {searchFilters.length}개
              </Badge>
            )}

            {/* CRUD 버튼들 */}
            {component.enableAdd && (
              <Button size="sm" onClick={handleAddData} disabled={loading} className="gap-2">
                <Plus className="h-3 w-3" />
                {component.addButtonText || "추가"}
              </Button>
            )}

            {component.enableEdit && selectedRows.size === 1 && (
              <Button size="sm" onClick={handleEditData} disabled={loading} className="gap-2" variant="outline">
                <Edit className="h-3 w-3" />
                {component.editButtonText || "수정"}
              </Button>
            )}

            {component.enableDelete && selectedRows.size > 0 && (
              <Button size="sm" variant="destructive" onClick={handleDeleteData} disabled={loading} className="gap-2">
                <Trash2 className="h-3 w-3" />
                {component.deleteButtonText || "삭제"}
              </Button>
            )}

            {component.showSearchButton && (
              <Button size="sm" onClick={handleSearch} disabled={loading} className="gap-2">
                <Search className="h-3 w-3" />
                {component.searchButtonText || "검색"}
              </Button>
            )}

            <Button size="sm" variant="outline" onClick={() => loadData(1, {})} disabled={loading} className="gap-2">
              <RotateCcw className="h-3 w-3" />
              새로고침
            </Button>
          </div>
        </div>

        {/* 검색 필터 */}
        {searchFilters.length > 0 && (
          <>
            <Separator className="my-2" />
            <div className="space-y-3">
              <CardDescription className="flex items-center gap-2">
                <Search className="h-3 w-3" />
                검색 필터
              </CardDescription>
              <div
                className="grid gap-3"
                style={{
                  gridTemplateColumns: searchFilters
                    .map((filter: DataTableFilter) => `${filter.gridColumns || 3}fr`)
                    .join(" "),
                }}
              >
                {searchFilters.map((filter: DataTableFilter) => (
                  <div key={filter.columnName} className="space-y-1">
                    <label className="text-muted-foreground text-xs font-medium">{filter.label}</label>
                    {renderSearchFilter(filter)}
                  </div>
                ))}
              </div>
            </div>
          </>
        )}
      </CardHeader>

      {/* 테이블 내용 */}
      <CardContent className="flex-1 p-0">
        <div className="flex h-full flex-col">
          {visibleColumns.length > 0 ? (
            <>
              <Table>
                <TableHeader>
                  <TableRow>
                    {/* 체크박스 컬럼 (삭제 기능이 활성화된 경우) */}
                    {component.enableDelete && (
                      <TableHead className="w-12 px-4">
                        <Checkbox
                          checked={selectedRows.size === data.length && data.length > 0}
                          onCheckedChange={handleSelectAll}
                        />
                      </TableHead>
                    )}
                    {visibleColumns.map((column: DataTableColumn) => (
                      <TableHead
                        key={column.id}
                        className="px-4 font-semibold"
                        style={{ width: `${((column.gridColumns || 2) / totalGridColumns) * 100}%` }}
                      >
                        {column.label}
                      </TableHead>
                    ))}
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {loading ? (
                    <TableRow>
                      <TableCell
                        colSpan={visibleColumns.length + (component.enableDelete ? 1 : 0)}
                        className="h-32 text-center"
                      >
                        <div className="text-muted-foreground flex items-center justify-center gap-2">
                          <Loader2 className="h-4 w-4 animate-spin" />
                          데이터를 불러오는 중...
                        </div>
                      </TableCell>
                    </TableRow>
                  ) : data.length > 0 ? (
                    data.map((row, rowIndex) => (
                      <TableRow key={rowIndex} className="hover:bg-muted/50">
                        {/* 체크박스 셀 (삭제 기능이 활성화된 경우) */}
                        {component.enableDelete && (
                          <TableCell className="w-12 px-4">
                            <Checkbox
                              checked={selectedRows.has(rowIndex)}
                              onCheckedChange={(checked) => handleRowSelect(rowIndex, checked as boolean)}
                            />
                          </TableCell>
                        )}
                        {visibleColumns.map((column: DataTableColumn) => (
                          <TableCell key={column.id} className="px-4 font-mono text-sm">
                            {formatCellValue(row[column.columnName], column)}
                          </TableCell>
                        ))}
                      </TableRow>
                    ))
                  ) : (
                    <TableRow>
                      <TableCell
                        colSpan={visibleColumns.length + (component.enableDelete ? 1 : 0)}
                        className="h-32 text-center"
                      >
                        <div className="text-muted-foreground flex flex-col items-center gap-2">
                          <Database className="h-8 w-8" />
                          <p>검색 결과가 없습니다</p>
                          <p className="text-xs">검색 조건을 변경하거나 새로고침을 시도해보세요</p>
                        </div>
                      </TableCell>
                    </TableRow>
                  )}
                </TableBody>
              </Table>

              {/* 페이지네이션 */}
              {component.pagination?.enabled && totalPages > 1 && (
                <div className="bg-muted/20 mt-auto border-t">
                  <div className="flex items-center justify-between px-6 py-3">
                    {component.pagination.showPageInfo && (
                      <div className="text-muted-foreground text-sm">
                        총 <span className="font-medium">{total.toLocaleString()}</span>개 중{" "}
                        <span className="font-medium">{((currentPage - 1) * pageSize + 1).toLocaleString()}</span>-
                        <span className="font-medium">{Math.min(currentPage * pageSize, total).toLocaleString()}</span>
                      </div>
                    )}
                    <div className="flex items-center space-x-2">
                      {component.pagination.showFirstLast && (
                        <Button
                          size="sm"
                          variant="outline"
                          onClick={() => handlePageChange(1)}
                          disabled={currentPage === 1 || loading}
                          className="gap-1"
                        >
                          처음
                        </Button>
                      )}
                      <Button
                        size="sm"
                        variant="outline"
                        onClick={() => handlePageChange(currentPage - 1)}
                        disabled={currentPage === 1 || loading}
                        className="gap-1"
                      >
                        <ChevronLeft className="h-3 w-3" />
                        이전
                      </Button>
                      <div className="flex items-center gap-1 text-sm font-medium">
                        <span>{currentPage}</span>
                        <span className="text-muted-foreground">/</span>
                        <span>{totalPages}</span>
                      </div>
                      <Button
                        size="sm"
                        variant="outline"
                        onClick={() => handlePageChange(currentPage + 1)}
                        disabled={currentPage === totalPages || loading}
                        className="gap-1"
                      >
                        다음
                        <ChevronRight className="h-3 w-3" />
                      </Button>
                      {component.pagination.showFirstLast && (
                        <Button
                          size="sm"
                          variant="outline"
                          onClick={() => handlePageChange(totalPages)}
                          disabled={currentPage === totalPages || loading}
                          className="gap-1"
                        >
                          마지막
                        </Button>
                      )}
                    </div>
                  </div>
                </div>
              )}
            </>
          ) : (
            <div className="flex flex-1 items-center justify-center">
              <div className="text-muted-foreground flex flex-col items-center gap-2">
                <Database className="h-8 w-8" />
                <p className="text-sm">표시할 컬럼이 없습니다</p>
                <p className="text-xs">테이블 설정에서 컬럼을 추가해주세요</p>
              </div>
            </div>
          )}
        </div>
      </CardContent>

      {/* 데이터 추가 모달 */}
      <Dialog open={showAddModal} onOpenChange={handleAddModalClose}>
        <DialogContent className={`max-h-[80vh] overflow-y-auto ${getModalSizeClass()}`}>
          <DialogHeader>
            <DialogTitle>{component.addModalConfig?.title || "새 데이터 추가"}</DialogTitle>
            <DialogDescription>
              {component.addModalConfig?.description ||
                `${component.title || component.label}에 새로운 데이터를 추가합니다.`}
            </DialogDescription>
          </DialogHeader>

          <div className="py-4">
            <div className={getLayoutClass()}>
              {getDisplayColumns().map((column) => (
                <div key={column.id} className="space-y-2">
                  <Label htmlFor={column.columnName} className="text-sm font-medium">
                    {column.label}
                    {isRequiredField(column.columnName) && <span className="ml-1 text-orange-500">*</span>}
                  </Label>
                  <div>{renderAddFormInput(column)}</div>
                </div>
              ))}
            </div>
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={handleAddModalClose} disabled={isAdding}>
              {component.addModalConfig?.cancelButtonText || "취소"}
            </Button>
            <Button onClick={handleAddSubmit} disabled={isAdding}>
              {isAdding ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  추가 중...
                </>
              ) : (
                <>
                  <Plus className="mr-2 h-4 w-4" />
                  {component.addModalConfig?.submitButtonText || "추가"}
                </>
              )}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 데이터 수정 모달 */}
      <Dialog
        open={showEditModal}
        onOpenChange={(open) => {
          if (!isEditing && !open) {
            setShowEditModal(false);
            setEditFormData({});
            setEditingRowData(null);
            setUploadedFiles({}); // 파일 상태 초기화
          }
        }}
      >
        <DialogContent className={`max-h-[80vh] overflow-y-auto ${getModalSizeClass()}`}>
          <DialogHeader>
            <DialogTitle>데이터 수정</DialogTitle>
            <DialogDescription>선택된 데이터를 수정합니다.</DialogDescription>
          </DialogHeader>

          <div className="py-4">
            <div className={getLayoutClass()}>
              {getDisplayColumns().map((column) => (
                <div key={column.id} className="space-y-2">
                  <Label htmlFor={`edit-${column.columnName}`} className="text-sm font-medium">
                    {column.label}
                    {isRequiredField(column.columnName) && <span className="ml-1 text-orange-500">*</span>}
                  </Label>
                  <div>{renderEditFormInput(column)}</div>
                </div>
              ))}
            </div>
          </div>

          <DialogFooter>
            <Button
              variant="outline"
              onClick={() => {
                setShowEditModal(false);
                setEditFormData({});
                setEditingRowData(null);
                setUploadedFiles({}); // 파일 상태 초기화
              }}
              disabled={isEditing}
            >
              취소
            </Button>
            <Button onClick={handleEditSubmit} disabled={isEditing}>
              {isEditing ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  수정 중...
                </>
              ) : (
                <>
                  <Edit className="mr-2 h-4 w-4" />
                  {component.editButtonText || "수정"}
                </>
              )}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 파일 정보 모달 */}
      <Dialog open={showFileModal} onOpenChange={setShowFileModal}>
        <DialogContent className="flex max-h-[80vh] max-w-2xl flex-col overflow-hidden">
          <DialogHeader>
            <DialogTitle className="flex items-center gap-2">
              <File className="h-5 w-5" />
              파일 정보 - {currentFileColumn?.label || "파일"}
            </DialogTitle>
            <DialogDescription>
              {currentFileData?.totalCount === 1
                ? "1개의 파일이 저장되어 있습니다."
                : `총 ${currentFileData?.totalCount}개의 파일이 저장되어 있습니다.`}
            </DialogDescription>
          </DialogHeader>

          <div className="flex-1 overflow-auto">
            {currentFileData?.files && Array.isArray(currentFileData.files) && (
              <div className="space-y-3">
                {currentFileData.files.map((fileInfo: FileInfo, index: number) => {
                  const isImage = fileInfo.type?.startsWith("image/");

                  return (
                    <div key={index} className="rounded-lg border bg-gray-50 p-4 transition-colors hover:bg-gray-100">
                      <div className="flex items-start gap-4">
                        {/* 파일 아이콘/미리보기 */}
                        <div className="flex-shrink-0">
                          {isImage ? (
                            <div className="flex h-16 w-16 items-center justify-center rounded border bg-white">
                              <div className="text-xs font-medium text-green-600">IMG</div>
                            </div>
                          ) : (
                            <div className="flex h-16 w-16 items-center justify-center rounded border bg-white">
                              <File className="h-8 w-8 text-gray-500" />
                            </div>
                          )}
                        </div>

                        {/* 파일 정보 */}
                        <div className="min-w-0 flex-1">
                          <h4 className="truncate font-medium text-gray-900" title={fileInfo.name}>
                            {fileInfo.name}
                          </h4>
                          <div className="mt-1 space-y-1 text-sm text-gray-600">
                            <div className="flex items-center gap-4">
                              <span>크기: {(fileInfo.size / 1024 / 1024).toFixed(2)} MB</span>
                              <span>타입: {fileInfo.type || "알 수 없음"}</span>
                            </div>
                            <div className="flex items-center gap-4">
                              <span>확장자: {fileInfo.extension || "N/A"}</span>
                              <span>업로드: {new Date(fileInfo.uploadedAt).toLocaleString("ko-KR")}</span>
                            </div>
                            {fileInfo.lastModified && (
                              <div>
                                <span>수정: {new Date(fileInfo.lastModified).toLocaleString("ko-KR")}</span>
                              </div>
                            )}
                          </div>
                        </div>

                        {/* 액션 버튼 */}
                        <div className="flex flex-col gap-2">
                          {isImage && (
                            <Button
                              variant="outline"
                              size="sm"
                              className="w-full"
                              onClick={() => handlePreviewImage(fileInfo)}
                            >
                              <Eye className="mr-1 h-4 w-4" />
                              미리보기
                            </Button>
                          )}
                          <Button
                            variant="outline"
                            size="sm"
                            className="w-full"
                            onClick={() => handleDownloadFile(fileInfo)}
                          >
                            <Download className="mr-1 h-4 w-4" />
                            다운로드
                          </Button>
                        </div>
                      </div>
                    </div>
                  );
                })}
              </div>
            )}

            {/* 요약 정보 */}
            {currentFileData && (
              <div className="mt-4 rounded-lg border border-blue-200 bg-blue-50 p-3">
                <h5 className="mb-2 font-medium text-blue-900">파일 요약</h5>
                <div className="grid grid-cols-2 gap-4 text-sm text-blue-800">
                  <div>
                    <span className="font-medium">총 파일 수:</span>
                    {"  "}
                    {currentFileData.totalCount}개
                  </div>
                  <div>
                    <span className="font-medium">총 크기:</span>
                    {"  "}
                    {(currentFileData.totalSize / 1024 / 1024).toFixed(2)} MB
                  </div>
                  <div className="col-span-2">
                    <span className="font-medium">최종 수정:</span>
                    {"  "}
                    {new Date(currentFileData.lastModified).toLocaleString("ko-KR")}
                  </div>
                </div>
              </div>
            )}
          </div>

          <DialogFooter>
            <Button variant="outline" onClick={() => setShowFileModal(false)}>
              <X className="mr-1 h-4 w-4" />
              닫기
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 데이터 삭제 확인 다이얼로그 */}
      <Dialog open={showDeleteDialog} onOpenChange={handleDeleteDialogClose}>
        <DialogContent>
          <DialogHeader>
            <DialogTitle>데이터 삭제 확인</DialogTitle>
            <DialogDescription>
              선택된 <strong>{selectedRows.size}개</strong>의 데이터를 삭제하시겠습니까?
              <br />
              <span className="text-red-600">이 작업은 되돌릴 수 없습니다.</span>
            </DialogDescription>
          </DialogHeader>

          <DialogFooter>
            <Button variant="outline" onClick={handleDeleteDialogClose} disabled={isDeleting}>
              취소
            </Button>
            <Button variant="destructive" onClick={handleDeleteConfirm} disabled={isDeleting}>
              {isDeleting ? (
                <>
                  <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                  삭제 중...
                </>
              ) : (
                <>
                  <Trash2 className="mr-2 h-4 w-4" />
                  삭제
                </>
              )}
            </Button>
          </DialogFooter>
        </DialogContent>
      </Dialog>

      {/* 이미지 미리보기 다이얼로그 */}
      <Dialog open={showPreviewModal} onOpenChange={closePreviewModal}>
        <DialogContent className="max-h-[90vh] max-w-4xl overflow-hidden">
          <DialogHeader>
            <DialogTitle className="flex items-center justify-between">
              <span className="truncate">{previewImage?.name}</span>
              <div className="flex items-center space-x-2">
                <Button size="sm" variant="outline" onClick={() => handleZoom("out")} disabled={zoom <= 0.25}>
                  <ZoomOut className="h-4 w-4" />
                </Button>
                <span className="min-w-[60px] text-center text-sm text-gray-500">{Math.round(zoom * 100)}%</span>
                <Button size="sm" variant="outline" onClick={() => handleZoom("in")} disabled={zoom >= 3}>
                  <ZoomIn className="h-4 w-4" />
                </Button>
                <Button size="sm" variant="outline" onClick={handleRotate}>
                  <RotateCw className="h-4 w-4" />
                </Button>
                {previewImage && (
                  <Button
                    size="sm"
                    variant="outline"
                    onClick={() => {
                      handleDownloadFile(previewImage);
                    }}
                  >
                    <Download className="h-4 w-4" />
                  </Button>
                )}
              </div>
            </DialogTitle>
          </DialogHeader>

          <div className="flex flex-1 items-center justify-center overflow-auto rounded-lg bg-gray-50 p-4">
            {previewImage && (
              <img
                src={`${process.env.NEXT_PUBLIC_API_URL}/files/preview/${previewImage.id}?serverFilename=${previewImage.serverFilename}`}
                alt={previewImage.name}
                className="max-h-full max-w-full object-contain transition-transform duration-200"
                style={{
                  transform: `scale(${zoom}) rotate(${rotation}deg)`,
                }}
                onError={() => {
                  console.error("이미지 로딩 실패:", previewImage);
                  toast.error("이미지를 불러올 수 없습니다.");
                }}
              />
            )}
          </div>

          {previewImage && (
            <div className="flex items-center justify-between border-t pt-3 text-sm text-gray-500">
              <div>크기: {formatFileSize(previewImage.size)}</div>
              <div>타입: {previewImage.type}</div>
              <div>업로드: {new Date(previewImage.uploadedAt).toLocaleDateString("ko-KR")}</div>
            </div>
          )}
        </DialogContent>
      </Dialog>
    </Card>
  );
};
