"use client";

import { useState, useEffect, useMemo, useCallback, useRef } from "react";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
import { Badge } from "@/components/ui/badge";
import { Checkbox } from "@/components/ui/checkbox";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "@/components/ui/command";
import {
  Search,
  Database,
  RefreshCw,
  Save,
  Plus,
  Activity,
  Trash2,
  Copy,
  Check,
  ChevronsUpDown,
  Loader2,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { LoadingSpinner } from "@/components/common/LoadingSpinner";
import { toast } from "sonner";
import { showErrorToast } from "@/lib/utils/toastUtils";
import { useMultiLang } from "@/hooks/useMultiLang";
import { useAuth } from "@/hooks/useAuth";
import { TABLE_MANAGEMENT_KEYS } from "@/constants/tableManagement";
import { INPUT_TYPE_OPTIONS } from "@/types/input-types";
import { apiClient } from "@/lib/api/client";
import { commonCodeApi } from "@/lib/api/commonCode";
import { entityJoinApi, ReferenceTableColumn } from "@/lib/api/entityJoin";
import { ddlApi } from "@/lib/api/ddl";
import { getSecondLevelMenus, createColumnMapping, deleteColumnMappingsByColumn } from "@/lib/api/tableCategoryValue";
import { saveNumberingRuleToTest } from "@/lib/api/numberingRule";
import { CreateTableModal } from "@/components/admin/CreateTableModal";
import { AddColumnModal } from "@/components/admin/AddColumnModal";
import { DDLLogViewer } from "@/components/admin/DDLLogViewer";
import { TableLogViewer } from "@/components/admin/TableLogViewer";
import { ScrollToTop } from "@/components/common/ScrollToTop";
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogFooter,
  DialogHeader,
  DialogTitle,
} from "@/components/ui/dialog";
import type { TableInfo, ColumnTypeInfo, SecondLevelMenu } from "@/components/admin/table-type/types";
import { TypeOverviewStrip } from "@/components/admin/table-type/TypeOverviewStrip";
import { ColumnGrid } from "@/components/admin/table-type/ColumnGrid";
import { ColumnDetailPanel } from "@/components/admin/table-type/ColumnDetailPanel";

export default function TableManagementPage() {
  const { userLang, getText } = useMultiLang({ companyCode: "*" });
  const { user } = useAuth();
  const [tables, setTables] = useState<TableInfo[]>([]);
  const [columns, setColumns] = useState<ColumnTypeInfo[]>([]);
  const [selectedTable, setSelectedTable] = useState<string | null>(null);
  const [searchTerm, setSearchTerm] = useState("");
  const [loading, setLoading] = useState(false);
  const [columnsLoading, setColumnsLoading] = useState(false);
  const [originalColumns, setOriginalColumns] = useState<ColumnTypeInfo[]>([]); // 원본 데이터 저장
  const [uiTexts, setUiTexts] = useState<Record<string, string>>({});

  // 페이지네이션 상태
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(9999); // 전체 컬럼 표시
  const [totalColumns, setTotalColumns] = useState(0);

  // 테이블 라벨 상태
  const [tableLabel, setTableLabel] = useState("");
  const [tableDescription, setTableDescription] = useState("");

  // 🎯 Entity 조인 관련 상태
  const [referenceTableColumns, setReferenceTableColumns] = useState<Record<string, ReferenceTableColumn[]>>({});

  // 🆕 Entity 타입 Combobox 열림/닫힘 상태 (컬럼별 관리)
  const [entityComboboxOpen, setEntityComboboxOpen] = useState<
    Record<
      string,
      {
        table: boolean;
        joinColumn: boolean;
        displayColumn: boolean;
      }
    >
  >({});

  // DDL 기능 관련 상태
  const [createTableModalOpen, setCreateTableModalOpen] = useState(false);
  const [addColumnModalOpen, setAddColumnModalOpen] = useState(false);
  const [ddlLogViewerOpen, setDdlLogViewerOpen] = useState(false);

  // 테이블 복제 관련 상태
  const [duplicateModalMode, setDuplicateModalMode] = useState<"create" | "duplicate">("create");
  const [duplicateSourceTable, setDuplicateSourceTable] = useState<string | null>(null);

  // 🆕 Category 타입용: 2레벨 메뉴 목록
  const [secondLevelMenus, setSecondLevelMenus] = useState<SecondLevelMenu[]>([]);

  // 채번 타입은 옵션설정 > 채번설정에서 관리 (별도 선택 불필요)

  // 로그 뷰어 상태
  const [logViewerOpen, setLogViewerOpen] = useState(false);
  const [logViewerTableName, setLogViewerTableName] = useState<string>("");

  // 저장 중 상태 (중복 실행 방지)
  const [isSaving, setIsSaving] = useState(false);

  // 테이블 삭제 확인 다이얼로그 상태
  const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
  const [tableToDelete, setTableToDelete] = useState<string>("");
  const [isDeleting, setIsDeleting] = useState(false);

  // PK/인덱스 관리 상태
  const [constraints, setConstraints] = useState<{
    primaryKey: { name: string; columns: string[] };
    indexes: Array<{ name: string; columns: string[]; isUnique: boolean }>;
  }>({ primaryKey: { name: "", columns: [] }, indexes: [] });
  const [pkDialogOpen, setPkDialogOpen] = useState(false);
  const [pendingPkColumns, setPendingPkColumns] = useState<string[]>([]);

  // 선택된 테이블 목록 (체크박스)
  const [selectedTableIds, setSelectedTableIds] = useState<Set<string>>(new Set());

  // 컬럼 그리드: 선택된 컬럼(우측 상세 패널 표시)
  const [selectedColumn, setSelectedColumn] = useState<string | null>(null);
  // 타입 오버뷰 스트립: 타입 필터 (null = 전체)
  const [typeFilter, setTypeFilter] = useState<string | null>(null);

  // 최고 관리자 여부 확인 (회사코드가 "*" AND userType이 "SUPER_ADMIN")
  const isSuperAdmin = user?.companyCode === "*" && user?.userType === "SUPER_ADMIN";

  // 다국어 텍스트 로드
  useEffect(() => {
    const loadTexts = async () => {
      if (!userLang) return;

      try {
        const response = await apiClient.post(
          "/multilang/batch",
          {
            langKeys: Object.values(TABLE_MANAGEMENT_KEYS),
          },
          {
            params: {
              companyCode: "*",
              menuCode: "TABLE_MANAGEMENT",
              userLang: userLang,
            },
          },
        );

        if (response.data.success) {
          setUiTexts(response.data.data);
        }
      } catch (error) {
        // console.error("다국어 텍스트 로드 실패:", error);
      }
    };

    loadTexts();
  }, [userLang]);

  // 텍스트 가져오기 함수
  const getTextFromUI = (key: string, fallback?: string) => {
    return uiTexts[key] || fallback || key;
  };

  // 🎯 참조 테이블 컬럼 정보 로드
  const loadReferenceTableColumns = useCallback(
    async (tableName: string) => {
      if (!tableName) {
        return;
      }

      // 이미 로드된 경우이지만 빈 배열이 아닌 경우만 스킵
      const existingColumns = referenceTableColumns[tableName];
      if (existingColumns && existingColumns.length > 0) {
        // console.log(`🎯 참조 테이블 컬럼 이미 로드됨: ${tableName}`, existingColumns);
        return;
      }

      // console.log(`🎯 참조 테이블 컬럼 로드 시작: ${tableName}`);
      try {
        const result = await entityJoinApi.getReferenceTableColumns(tableName);
        // console.log(`🎯 참조 테이블 컬럼 로드 성공: ${tableName}`, result.columns);
        setReferenceTableColumns((prev) => ({
          ...prev,
          [tableName]: result.columns,
        }));
      } catch (error) {
        // console.error(`참조 테이블 컬럼 로드 실패: ${tableName}`, error);
        setReferenceTableColumns((prev) => ({
          ...prev,
          [tableName]: [],
        }));
      }
    },
    [], // 의존성 배열에서 referenceTableColumns 제거
  );

  // 입력 타입 옵션 (8개 핵심 타입)
  const inputTypeOptions = INPUT_TYPE_OPTIONS.map((option) => ({
    value: option.value,
    label: option.label,
    description: option.description,
  }));

  // 메모이제이션된 입력타입 옵션
  const memoizedInputTypeOptions = useMemo(() => inputTypeOptions, []);

  // 참조 테이블 옵션 (한글라벨 (영어명) 동시 표시)
  const referenceTableOptions = [
    { value: "none", label: getTextFromUI(TABLE_MANAGEMENT_KEYS.LABEL_NONE, "선택 안함") },
    ...tables.map((table) => ({
      value: table.tableName,
      label:
        table.displayName && table.displayName !== table.tableName
          ? `${table.displayName} (${table.tableName})`
          : table.tableName,
    })),
  ];

  // 공통 코드 카테고리 목록 상태
  const [commonCodeCategories, setCommonCodeCategories] = useState<Array<{ value: string; label: string }>>([]);

  // 공통 코드 옵션
  const commonCodeOptions = [
    { value: "none", label: getTextFromUI(TABLE_MANAGEMENT_KEYS.SELECT_CODE_PLACEHOLDER, "코드 선택") },
    ...commonCodeCategories,
  ];

  // 공통코드 카테고리 목록 로드
  const loadCommonCodeCategories = async () => {
    try {
      const response = await commonCodeApi.categories.getList({ isActive: true });
      // console.log("🔍 공통코드 카테고리 API 응답:", response);

      if (response.success && response.data) {
        // console.log("📋 공통코드 카테고리 데이터:", response.data);

        const categories = response.data.map((category) => {
          // console.log("🏷️ 카테고리 항목:", category);
          return {
            value: category.category_code,
            label: category.category_name || category.category_code,
          };
        });

        // console.log("✅ 매핑된 카테고리 옵션:", categories);
        setCommonCodeCategories(categories);
      }
    } catch (error) {
      // console.error("공통코드 카테고리 로드 실패:", error);
      // 에러는 로그만 남기고 사용자에게는 알리지 않음 (선택적 기능)
    }
  };

  // 🆕 2레벨 메뉴 목록 로드
  const loadSecondLevelMenus = async () => {
    try {
      const response = await getSecondLevelMenus();
      if (response.success && response.data) {
        setSecondLevelMenus(response.data);
      } else {
        console.warn("⚠️ 2레벨 메뉴 로드 실패:", response);
        setSecondLevelMenus([]); // 빈 배열로 설정하여 로딩 상태 해제
      }
    } catch (error) {
      console.error("❌ 2레벨 메뉴 로드 에러:", error);
      setSecondLevelMenus([]); // 에러 발생 시에도 빈 배열로 설정
    }
  };

  // 🆕 채번규칙 목록 로드
  // 테이블 목록 로드
  const loadTables = async () => {
    setLoading(true);
    try {
      const response = await apiClient.get("/table-management/tables");

      // 응답 상태 확인
      if (response.data.success) {
        setTables(response.data.data);
        toast.success("테이블 목록을 성공적으로 로드했습니다.");
      } else {
        showErrorToast("테이블 목록을 불러오는 데 실패했습니다", response.data.message, {
          guidance: "네트워크 연결을 확인해 주세요.",
        });
      }
    } catch (error) {
      // console.error("테이블 목록 로드 실패:", error);
      showErrorToast("테이블 목록을 불러오는 데 실패했습니다", error, {
        guidance: "네트워크 연결을 확인해 주세요.",
      });
    } finally {
      setLoading(false);
    }
  };

  // 컬럼 타입 정보 로드 (페이지네이션 적용)
  const loadColumnTypes = useCallback(async (tableName: string, page: number = 1, size: number = 50) => {
    setColumnsLoading(true);
    try {
      const response = await apiClient.get(`/table-management/tables/${tableName}/columns`, {
        params: { page, size },
      });

      // 응답 상태 확인
      if (response.data.success) {
        const data = response.data.data;

        console.log("📥 원본 API 응답:", {
          hasColumns: !!(data.columns || data),
          firstColumn: (data.columns || data)[0],
          statusColumn: (data.columns || data).find((col: any) => col.columnName === "status"),
        });

        // 컬럼 데이터에 기본값 설정
        const processedColumns = (data.columns || data).map((col: any) => {
          let hierarchyRole: "large" | "medium" | "small" | undefined = undefined;
          if (col.detailSettings && typeof col.detailSettings === "string") {
            try {
              const parsed = JSON.parse(col.detailSettings);
              if (
                parsed.hierarchyRole === "large" ||
                parsed.hierarchyRole === "medium" ||
                parsed.hierarchyRole === "small"
              ) {
                hierarchyRole = parsed.hierarchyRole;
              }
            } catch {
              // JSON 파싱 실패 시 무시
            }
          }

          return {
            ...col,
            inputType: col.inputType || "text",
            isUnique: col.isUnique || "NO",
            categoryMenus: col.categoryMenus || [],
            hierarchyRole,
            categoryRef: col.categoryRef || null,
          };
        });

        if (page === 1) {
          setColumns(processedColumns);
          setOriginalColumns(processedColumns);
        } else {
          // 페이지 추가 로드 시 기존 데이터에 추가
          setColumns((prev) => [...prev, ...processedColumns]);
        }
        setTotalColumns(data.total || processedColumns.length);
        toast.success("컬럼 정보를 성공적으로 로드했습니다.");
      } else {
        showErrorToast("컬럼 정보를 불러오는 데 실패했습니다", response.data.message, {
          guidance: "네트워크 연결을 확인해 주세요.",
        });
      }
    } catch (error) {
      // console.error("컬럼 타입 정보 로드 실패:", error);
      showErrorToast("컬럼 정보를 불러오는 데 실패했습니다", error, {
        guidance: "네트워크 연결을 확인해 주세요.",
      });
    } finally {
      setColumnsLoading(false);
    }
  }, []);

  // PK/인덱스 제약조건 로드
  const loadConstraints = useCallback(async (tableName: string) => {
    try {
      const response = await apiClient.get(`/table-management/tables/${tableName}/constraints`);
      if (response.data.success) {
        setConstraints(response.data.data);
      }
    } catch (error) {
      console.error("제약조건 로드 실패:", error);
      setConstraints({ primaryKey: { name: "", columns: [] }, indexes: [] });
    }
  }, []);

  // 테이블 선택
  const handleTableSelect = useCallback(
    (tableName: string) => {
      setSelectedTable(tableName);
      setCurrentPage(1);
      setColumns([]);
      setSelectedColumn(null);
      setTypeFilter(null);

      // 선택된 테이블 정보에서 라벨 설정
      const tableInfo = tables.find((table) => table.tableName === tableName);
      setTableLabel(tableInfo?.displayName || tableName);
      setTableDescription(tableInfo?.description || "");

      loadColumnTypes(tableName, 1, pageSize);
      loadConstraints(tableName);
    },
    [loadColumnTypes, loadConstraints, pageSize, tables],
  );

  // 입력 타입 변경 - 이전 타입의 설정값 초기화 포함
  const handleInputTypeChange = useCallback(
    (columnName: string, newInputType: string) => {
      setColumns((prev) =>
        prev.map((col) => {
          if (col.columnName === columnName) {
            const inputTypeOption = memoizedInputTypeOptions.find((option) => option.value === newInputType);
            const updated: typeof col = {
              ...col,
              inputType: newInputType,
              detailSettings: inputTypeOption?.description || col.detailSettings,
            };

            // 엔티티가 아닌 타입으로 변경 시 참조 설정 초기화
            if (newInputType !== "entity") {
              updated.referenceTable = undefined;
              updated.referenceColumn = undefined;
              updated.displayColumn = undefined;
            }

            // 코드가 아닌 타입으로 변경 시 코드 설정 초기화
            if (newInputType !== "code") {
              updated.codeCategory = undefined;
              updated.codeValue = undefined;
              updated.hierarchyRole = undefined;
            }

            // 카테고리가 아닌 타입으로 변경 시 카테고리 참조 초기화
            if (newInputType !== "category") {
              updated.categoryRef = undefined;
            }

            return updated;
          }
          return col;
        }),
      );
    },
    [memoizedInputTypeOptions],
  );

  // 상세 설정 변경 (코드/엔티티 타입용)
  const handleDetailSettingsChange = useCallback(
    (columnName: string, settingType: string, value: string) => {
      setColumns((prev) =>
        prev.map((col) => {
          if (col.columnName === columnName) {
            let newDetailSettings = col.detailSettings;
            let codeCategory = col.codeCategory;
            let codeValue = col.codeValue;
            let referenceTable = col.referenceTable;
            let referenceColumn = col.referenceColumn;
            let displayColumn = col.displayColumn;
            let hierarchyRole = col.hierarchyRole;

            if (settingType === "code") {
              if (value === "none") {
                newDetailSettings = "";
                codeCategory = undefined;
                codeValue = undefined;
                hierarchyRole = undefined; // 코드 선택 해제 시 계층 역할도 초기화
              } else {
                // 기존 hierarchyRole 유지하면서 JSON 형식으로 저장
                const existingHierarchyRole = hierarchyRole;
                newDetailSettings = JSON.stringify({
                  codeCategory: value,
                  hierarchyRole: existingHierarchyRole,
                });
                codeCategory = value;
                codeValue = value;
              }
            } else if (settingType === "hierarchy_role") {
              // 계층구조 역할 변경 - JSON 형식으로 저장
              hierarchyRole = value === "none" ? undefined : (value as "large" | "medium" | "small");
              // detailSettings를 JSON으로 업데이트
              let existingSettings: Record<string, any> = {};
              if (typeof col.detailSettings === "string" && col.detailSettings.trim().startsWith("{")) {
                try {
                  existingSettings = JSON.parse(col.detailSettings);
                } catch {
                  existingSettings = {};
                }
              }
              newDetailSettings = JSON.stringify({
                ...existingSettings,
                hierarchyRole: hierarchyRole,
              });
            } else if (settingType === "entity") {
              if (value === "none") {
                newDetailSettings = "";
                referenceTable = undefined;
                referenceColumn = undefined;
                displayColumn = undefined;
              } else {
                const tableOption = referenceTableOptions.find((option) => option.value === value);
                newDetailSettings = tableOption ? `참조테이블: ${tableOption.label}` : "";
                referenceTable = value;
                // 🎯 참조 컬럼을 소스 컬럼명과 동일하게 설정 (일반적인 경우)
                // 예: user_info.dept_code -> dept_info.dept_code
                referenceColumn = col.columnName;
                // 참조 테이블의 컬럼 정보 로드
                loadReferenceTableColumns(value);
              }
            } else if (settingType === "entity_reference_column") {
              // 🎯 Entity 참조 컬럼 변경 (조인할 컬럼)
              referenceColumn = value;
              const tableOption = referenceTableOptions.find((option) => option.value === col.referenceTable);
              newDetailSettings = tableOption ? `참조테이블: ${tableOption.label}` : "";
            } else if (settingType === "entity_display_column") {
              // 🎯 Entity 표시 컬럼 변경
              displayColumn = value;
              const tableOption = referenceTableOptions.find((option) => option.value === col.referenceTable);
              newDetailSettings = tableOption ? `참조테이블: ${tableOption.label} (${value})` : "";
            }

            return {
              ...col,
              detailSettings: newDetailSettings,
              codeCategory,
              codeValue,
              referenceTable,
              referenceColumn,
              displayColumn,
              hierarchyRole,
            };
          }
          return col;
        }),
      );
    },
    [commonCodeOptions, referenceTableOptions, loadReferenceTableColumns],
  );

  // 라벨 변경 핸들러 추가
  const handleLabelChange = useCallback((columnName: string, newLabel: string) => {
    setColumns((prev) =>
      prev.map((col) => {
        if (col.columnName === columnName) {
          return {
            ...col,
            displayName: newLabel,
          };
        }
        return col;
      }),
    );
  }, []);

  // 컬럼 변경 핸들러 (인덱스 기반)
  const handleColumnChange = useCallback((index: number, field: keyof ColumnTypeInfo, value: any) => {
    setColumns((prev) =>
      prev.map((col, i) => {
        if (i === index) {
          return {
            ...col,
            [field]: value,
          };
        }
        return col;
      }),
    );
  }, []);

  // 개별 컬럼 저장
  const handleSaveColumn = async (column: ColumnTypeInfo) => {
    if (!selectedTable) return;

    try {
      // 🎯 Entity 타입인 경우 detailSettings에 엔티티 설정을 JSON으로 포함
      let finalDetailSettings = column.detailSettings || "";

      if (column.inputType === "entity" && column.referenceTable) {
        // 기존 detailSettings를 파싱하거나 새로 생성
        let existingSettings: Record<string, unknown> = {};
        if (typeof column.detailSettings === "string" && column.detailSettings.trim().startsWith("{")) {
          try {
            existingSettings = JSON.parse(column.detailSettings);
          } catch {
            existingSettings = {};
          }
        }

        // 엔티티 설정 추가
        const entitySettings = {
          ...existingSettings,
          entityTable: column.referenceTable,
          entityCodeColumn: column.referenceColumn || "id",
          entityLabelColumn: column.displayColumn || "name",
          placeholder: (existingSettings.placeholder as string) || "항목을 선택하세요",
          searchable: existingSettings.searchable ?? true,
        };

        finalDetailSettings = JSON.stringify(entitySettings);
        console.log("🔧 Entity 설정 JSON 생성:", entitySettings);
      }

      // 🎯 Code 타입인 경우 hierarchyRole을 detailSettings에 포함
      if (column.inputType === "code" && column.hierarchyRole) {
        let existingSettings: Record<string, unknown> = {};
        if (typeof finalDetailSettings === "string" && finalDetailSettings.trim().startsWith("{")) {
          try {
            existingSettings = JSON.parse(finalDetailSettings);
          } catch {
            existingSettings = {};
          }
        }

        const codeSettings = {
          ...existingSettings,
          hierarchyRole: column.hierarchyRole,
        };

        finalDetailSettings = JSON.stringify(codeSettings);
        console.log("🔧 Code 계층 역할 설정 JSON 생성:", codeSettings);
      }

      const columnSetting = {
        columnName: column.columnName,
        columnLabel: column.displayName,
        inputType: column.inputType || "text",
        detailSettings: finalDetailSettings,
        codeCategory: column.codeCategory || "",
        codeValue: column.codeValue || "",
        referenceTable: column.referenceTable || "",
        referenceColumn: column.referenceColumn || "",
        displayColumn: column.displayColumn || "",
        categoryRef: column.categoryRef || null,
      };

      // console.log("저장할 컬럼 설정:", columnSetting);

      console.log("💾 저장할 컬럼 정보:", {
        columnName: column.columnName,
        inputType: column.inputType,
        categoryMenus: column.categoryMenus,
        hasCategoryMenus: !!column.categoryMenus,
        categoryMenusLength: column.categoryMenus?.length || 0,
      });

      const response = await apiClient.post(`/table-management/tables/${selectedTable}/columns/settings`, [
        columnSetting,
      ]);

      if (response.data.success) {
        console.log("✅ 컬럼 설정 저장 성공");

        // 🆕 Category 타입인 경우 컬럼 매핑 처리
        console.log("🔍 카테고리 조건 체크:", {
          isCategory: column.inputType === "category",
          hasCategoryMenus: !!column.categoryMenus,
          length: column.categoryMenus?.length || 0,
        });

        if (column.inputType === "category" && !column.categoryRef) {
          // 참조가 아닌 자체 카테고리만 메뉴 매핑 처리
          console.log("기존 카테고리 메뉴 매핑 삭제 시작:", {
            tableName: selectedTable,
            columnName: column.columnName,
          });

          try {
            const deleteResponse = await deleteColumnMappingsByColumn(selectedTable, column.columnName);
            console.log("🗑️ 기존 매핑 삭제 결과:", deleteResponse);
          } catch (error) {
            console.error("❌ 기존 매핑 삭제 실패:", error);
          }

          // 2. 새로운 매핑 추가 (선택된 메뉴가 있는 경우만)
          if (column.categoryMenus && column.categoryMenus.length > 0) {
            console.log("📥 카테고리 메뉴 매핑 시작:", {
              columnName: column.columnName,
              categoryMenus: column.categoryMenus,
              count: column.categoryMenus.length,
            });

            let successCount = 0;
            let failCount = 0;

            for (const menuObjid of column.categoryMenus) {
              try {
                const mappingResponse = await createColumnMapping({
                  tableName: selectedTable,
                  logicalColumnName: column.columnName,
                  physicalColumnName: column.columnName,
                  menuObjid,
                  description: `${column.displayName} (메뉴별 카테고리)`,
                });

                if (mappingResponse.success) {
                  successCount++;
                } else {
                  console.error("❌ 매핑 생성 실패:", mappingResponse);
                  failCount++;
                }
              } catch (error) {
                console.error(`❌ 메뉴 ${menuObjid}에 대한 매핑 생성 실패:`, error);
                failCount++;
              }
            }

            if (successCount > 0 && failCount === 0) {
              toast.success(`컬럼 설정 및 ${successCount}개 메뉴 매핑이 저장되었습니다.`);
            } else if (successCount > 0 && failCount > 0) {
              toast.warning(`컬럼 설정 저장 성공. ${successCount}개 메뉴 매핑 성공, ${failCount}개 실패.`);
            } else if (failCount > 0) {
              toast.error("컬럼 설정 저장 성공. 메뉴 매핑 생성 실패.");
            }
          } else {
            toast.success("컬럼 설정이 저장되었습니다. (메뉴 매핑 없음)");
          }
        } else {
          toast.success("컬럼 설정이 성공적으로 저장되었습니다.");
        }

        // 원본 데이터 업데이트
        setOriginalColumns((prev) => prev.map((col) => (col.columnName === column.columnName ? column : col)));

        // 저장 후 데이터 확인을 위해 다시 로드
        setTimeout(() => {
          loadColumnTypes(selectedTable);
        }, 1000);
      } else {
        showErrorToast("컬럼 설정 저장에 실패했습니다", response.data.message, {
          guidance: "입력 데이터를 확인하고 다시 시도해 주세요.",
        });
      }
    } catch (error) {
      // console.error("컬럼 설정 저장 실패:", error);
      showErrorToast("컬럼 설정 저장에 실패했습니다", error, {
        guidance: "입력 데이터를 확인하고 다시 시도해 주세요.",
      });
    }
  };

  // 전체 저장 (테이블 라벨 + 모든 컬럼 설정)
  const saveAllSettings = async () => {
    if (!selectedTable) return;
    if (isSaving) return; // 저장 중 중복 실행 방지

    setIsSaving(true);
    try {
      // 1. 테이블 라벨 저장 (변경된 경우에만)
      if (tableLabel !== selectedTable || tableDescription) {
        try {
          await apiClient.put(`/table-management/tables/${selectedTable}/label`, {
            displayName: tableLabel,
            description: tableDescription,
          });
        } catch (error) {
          // console.warn("테이블 라벨 저장 실패 (API 미구현 가능):", error);
        }
      }

      // 2. 모든 컬럼 설정 저장
      if (columns.length > 0) {
        const columnSettings = columns.map((column) => {
          // detailSettings 계산
          let finalDetailSettings = column.detailSettings || "";

          // 🆕 Entity 타입인 경우 detailSettings에 엔티티 설정 포함
          if (column.inputType === "entity" && column.referenceTable) {
            let existingSettings: Record<string, unknown> = {};
            if (typeof finalDetailSettings === "string" && finalDetailSettings.trim().startsWith("{")) {
              try {
                existingSettings = JSON.parse(finalDetailSettings);
              } catch {
                existingSettings = {};
              }
            }
            const entitySettings = {
              ...existingSettings,
              entityTable: column.referenceTable,
              entityCodeColumn: column.referenceColumn || "id",
              entityLabelColumn: column.displayColumn || "name",
            };
            finalDetailSettings = JSON.stringify(entitySettings);
          }

          // 🆕 Code 타입인 경우 hierarchyRole을 detailSettings에 포함
          if (column.inputType === "code" && column.hierarchyRole) {
            let existingSettings: Record<string, unknown> = {};
            if (typeof finalDetailSettings === "string" && finalDetailSettings.trim().startsWith("{")) {
              try {
                existingSettings = JSON.parse(finalDetailSettings);
              } catch {
                existingSettings = {};
              }
            }
            const codeSettings = {
              ...existingSettings,
              hierarchyRole: column.hierarchyRole,
            };
            finalDetailSettings = JSON.stringify(codeSettings);
          }

          return {
            columnName: column.columnName,
            columnLabel: column.displayName,
            inputType: column.inputType || "text",
            detailSettings: finalDetailSettings,
            description: column.description || "",
            codeCategory: column.codeCategory || "",
            codeValue: column.codeValue || "",
            referenceTable: column.referenceTable || "",
            referenceColumn: column.referenceColumn || "",
            displayColumn: column.displayColumn || "",
            categoryRef: column.categoryRef || null,
          };
        });

        // console.log("저장할 전체 설정:", { tableLabel, tableDescription, columnSettings });

        // 전체 테이블 설정을 한 번에 저장
        const response = await apiClient.post(
          `/table-management/tables/${selectedTable}/columns/settings`,
          columnSettings,
        );

        if (response.data.success) {
          // 자체 카테고리 컬럼만 메뉴 매핑 처리 (참조 컬럼 제외)
          const categoryColumns = columns.filter((col) => col.inputType === "category" && !col.categoryRef);

          console.log("📥 전체 저장: 카테고리 컬럼 확인", {
            totalColumns: columns.length,
            categoryColumns: categoryColumns.length,
            categoryColumnsData: categoryColumns.map((col) => ({
              columnName: col.columnName,
              categoryMenus: col.categoryMenus,
            })),
          });

          if (categoryColumns.length > 0) {
            let totalSuccessCount = 0;
            let totalFailCount = 0;

            for (const column of categoryColumns) {
              // 1. 먼저 기존 매핑 모두 삭제
              console.log("🗑️ 기존 카테고리 메뉴 매핑 삭제:", {
                tableName: selectedTable,
                columnName: column.columnName,
              });

              try {
                const deleteResponse = await deleteColumnMappingsByColumn(selectedTable, column.columnName);
                console.log("🗑️ 기존 매핑 삭제 결과:", deleteResponse);
              } catch (error) {
                console.error("❌ 기존 매핑 삭제 실패:", error);
              }

              // 2. 새로운 매핑 추가 (선택된 메뉴가 있는 경우만)
              if (column.categoryMenus && column.categoryMenus.length > 0) {
                for (const menuObjid of column.categoryMenus) {
                  try {
                    console.log("🔄 매핑 API 호출:", {
                      tableName: selectedTable,
                      columnName: column.columnName,
                      menuObjid,
                    });

                    const mappingResponse = await createColumnMapping({
                      tableName: selectedTable,
                      logicalColumnName: column.columnName,
                      physicalColumnName: column.columnName,
                      menuObjid,
                      description: `${column.displayName} (메뉴별 카테고리)`,
                    });

                    console.log("✅ 매핑 API 응답:", mappingResponse);

                    if (mappingResponse.success) {
                      totalSuccessCount++;
                    } else {
                      console.error("❌ 매핑 생성 실패:", mappingResponse);
                      totalFailCount++;
                    }
                  } catch (error) {
                    console.error(`❌ 메뉴 ${menuObjid}에 대한 매핑 생성 실패:`, error);
                    totalFailCount++;
                  }
                }
              }
            }

            console.log("📊 전체 매핑 결과:", { totalSuccessCount, totalFailCount });

            if (totalSuccessCount > 0) {
              toast.success(`테이블 설정 및 ${totalSuccessCount}개 카테고리 메뉴 매핑이 저장되었습니다.`);
            } else if (totalFailCount > 0) {
              toast.warning(`테이블 설정은 저장되었으나 ${totalFailCount}개 메뉴 매핑 생성 실패.`);
            } else {
              toast.success(`테이블 '${selectedTable}' 설정이 모두 저장되었습니다.`);
            }
          } else {
            toast.success(`테이블 '${selectedTable}' 설정이 모두 저장되었습니다.`);
          }

          // 저장 성공 후 원본 데이터 업데이트
          setOriginalColumns([...columns]);

          // 테이블 목록 새로고침 (라벨 변경 반영)
          loadTables();

          // 저장 후 데이터 다시 로드
          setTimeout(() => {
            loadColumnTypes(selectedTable, 1, pageSize);
          }, 1000);
        } else {
          showErrorToast("설정 저장에 실패했습니다", response.data.message, {
            guidance: "잠시 후 다시 시도해 주세요.",
          });
        }
      }
    } catch (error) {
      // console.error("설정 저장 실패:", error);
      showErrorToast("설정 저장에 실패했습니다", error, {
        guidance: "잠시 후 다시 시도해 주세요.",
      });
    } finally {
      setIsSaving(false);
    }
  };

  // Ctrl+S 단축키: 테이블 설정 전체 저장
  // saveAllSettings를 ref로 참조하여 useEffect 의존성 문제 방지
  const saveAllSettingsRef = useRef(saveAllSettings);
  saveAllSettingsRef.current = saveAllSettings;

  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === "s") {
        e.preventDefault(); // 브라우저 기본 저장 동작 방지
        if (selectedTable && columns.length > 0) {
          saveAllSettingsRef.current();
        }
      }
    };

    window.addEventListener("keydown", handleKeyDown);
    return () => window.removeEventListener("keydown", handleKeyDown);
  }, [selectedTable, columns.length]);

  // 필터링 + 한글 우선 정렬 (ㄱ~ㅎ → a~z)
  const filteredTables = useMemo(() => {
    const filtered = tables.filter(
      (table) =>
        table.tableName.toLowerCase().includes(searchTerm.toLowerCase()) ||
        table.displayName.toLowerCase().includes(searchTerm.toLowerCase()),
    );
    const isKorean = (str: string) => /^[가-힣ㄱ-ㅎ]/.test(str);
    return filtered.sort((a, b) => {
      const nameA = a.displayName || a.tableName;
      const nameB = b.displayName || b.tableName;
      const aKo = isKorean(nameA);
      const bKo = isKorean(nameB);
      if (aKo && !bKo) return -1;
      if (!aKo && bKo) return 1;
      return nameA.localeCompare(nameB, aKo ? "ko" : "en");
    });
  }, [tables, searchTerm]);

  // 선택된 테이블 정보
  const selectedTableInfo = tables.find((table) => table.tableName === selectedTable);

  useEffect(() => {
    loadTables();
    loadCommonCodeCategories();
    loadSecondLevelMenus();
  }, []);

  // 🎯 컬럼 로드 후 이미 설정된 참조 테이블들의 컬럼 정보 로드
  useEffect(() => {
    if (columns.length > 0) {
      const entityColumns = columns.filter(
        (col) => col.inputType === "entity" && col.referenceTable && col.referenceTable !== "none",
      );

      entityColumns.forEach((col) => {
        if (col.referenceTable) {
          // console.log(`🎯 기존 Entity 컬럼 발견, 참조 테이블 컬럼 로드: ${col.columnName} -> ${col.referenceTable}`);
          loadReferenceTableColumns(col.referenceTable);
        }
      });
    }
  }, [columns, loadReferenceTableColumns]);

  // 더 많은 데이터 로드
  const loadMoreColumns = useCallback(() => {
    if (selectedTable && columns.length < totalColumns && !columnsLoading) {
      const nextPage = Math.floor(columns.length / pageSize) + 1;
      loadColumnTypes(selectedTable, nextPage, pageSize);
    }
  }, [selectedTable, columns.length, totalColumns, columnsLoading, pageSize, loadColumnTypes]);

  // PK 체크박스 변경 핸들러
  const handlePkToggle = useCallback(
    (columnName: string, checked: boolean) => {
      const currentPkCols = [...constraints.primaryKey.columns];
      let newPkCols: string[];
      if (checked) {
        newPkCols = [...currentPkCols, columnName];
      } else {
        newPkCols = currentPkCols.filter((c) => c !== columnName);
      }
      // PK 변경은 확인 다이얼로그 표시
      setPendingPkColumns(newPkCols);
      setPkDialogOpen(true);
    },
    [constraints.primaryKey.columns],
  );

  // PK 변경 확인
  const handlePkConfirm = async () => {
    if (!selectedTable) return;
    try {
      if (pendingPkColumns.length === 0) {
        toast.error("PK 컬럼을 최소 1개 이상 선택해야 합니다.");
        setPkDialogOpen(false);
        return;
      }
      const response = await apiClient.put(`/table-management/tables/${selectedTable}/primary-key`, {
        columns: pendingPkColumns,
      });
      if (response.data.success) {
        toast.success(response.data.message);
        await loadConstraints(selectedTable);
      } else {
        toast.error(response.data.message || "PK 설정 실패");
      }
    } catch (error: any) {
      showErrorToast("PK 설정에 실패했습니다", error, {
        guidance: "컬럼 정보를 확인하고 다시 시도해 주세요.",
      });
    } finally {
      setPkDialogOpen(false);
    }
  };

  // 인덱스 토글 핸들러 (일반 인덱스만 DB 레벨 - 유니크는 앱 레벨 소프트 제약조건으로 분리됨)
  const handleIndexToggle = useCallback(
    async (columnName: string, indexType: "index", checked: boolean) => {
      if (!selectedTable) return;
      const action = checked ? "create" : "drop";
      try {
        const response = await apiClient.post(`/table-management/tables/${selectedTable}/indexes`, {
          columnName,
          indexType,
          action,
        });
        if (response.data.success) {
          toast.success(response.data.message);
          await loadConstraints(selectedTable);
        } else {
          toast.error(response.data.message || "인덱스 설정 실패");
        }
      } catch (error: any) {
        showErrorToast("인덱스 설정에 실패했습니다", error, {
          guidance: "컬럼 정보를 확인하고 다시 시도해 주세요.",
        });
      }
    },
    [selectedTable, loadConstraints],
  );

  // 컬럼별 인덱스 상태 헬퍼
  const getColumnIndexState = useCallback(
    (columnName: string) => {
      const isPk = constraints.primaryKey.columns.includes(columnName);
      const hasIndex = constraints.indexes.some(
        (idx) => !idx.isUnique && idx.columns.length === 1 && idx.columns[0] === columnName,
      );
      return { isPk, hasIndex };
    },
    [constraints],
  );

  // UNIQUE 토글 핸들러 (앱 레벨 소프트 제약조건 - NOT NULL과 동일 패턴)
  const handleUniqueToggle = useCallback(
    async (columnName: string, currentIsUnique: string) => {
      if (!selectedTable) return;
      const isCurrentlyUnique = currentIsUnique === "YES";
      const newUnique = !isCurrentlyUnique;
      try {
        const response = await apiClient.put(
          `/table-management/tables/${selectedTable}/columns/${columnName}/unique`,
          { unique: newUnique },
        );
        if (response.data.success) {
          toast.success(response.data.message);
          setColumns((prev) =>
            prev.map((col) =>
              col.columnName === columnName
                ? { ...col, isUnique: newUnique ? "YES" : "NO" }
                : col,
            ),
          );
        } else {
          showErrorToast("UNIQUE 제약 조건 설정에 실패했습니다", response.data.message, {
            guidance: "해당 컬럼에 중복 데이터가 없는지 확인해 주세요.",
          });
        }
      } catch (error: any) {
        showErrorToast("UNIQUE 제약 조건 설정에 실패했습니다", error, {
          guidance: "해당 컬럼에 중복 데이터가 없는지 확인해 주세요.",
        });
      }
    },
    [selectedTable],
  );

  // NOT NULL 토글 핸들러
  const handleNullableToggle = useCallback(
    async (columnName: string, currentIsNullable: string) => {
      if (!selectedTable) return;
      // isNullable이 "YES"면 nullable, "NO"면 NOT NULL
      // 체크박스 체크 = NOT NULL 설정 (nullable: false)
      // 체크박스 해제 = NOT NULL 해제 (nullable: true)
      const isCurrentlyNotNull = currentIsNullable === "NO";
      const newNullable = isCurrentlyNotNull; // NOT NULL이면 해제, NULL이면 설정
      try {
        const response = await apiClient.put(
          `/table-management/tables/${selectedTable}/columns/${columnName}/nullable`,
          { nullable: newNullable },
        );
        if (response.data.success) {
          toast.success(response.data.message);
          // 컬럼 상태 로컬 업데이트
          setColumns((prev) =>
            prev.map((col) =>
              col.columnName === columnName
                ? { ...col, isNullable: newNullable ? "YES" : "NO" }
                : col,
            ),
          );
        } else {
          showErrorToast("NOT NULL 제약 조건 설정에 실패했습니다", response.data.message, {
            guidance: "해당 컬럼에 NULL 값이 없는지 확인해 주세요.",
          });
        }
      } catch (error: any) {
        showErrorToast("NOT NULL 제약 조건 설정에 실패했습니다", error, {
          guidance: "해당 컬럼에 NULL 값이 없는지 확인해 주세요.",
        });
      }
    },
    [selectedTable],
  );

  // 테이블 삭제 확인
  const handleDeleteTableClick = (tableName: string) => {
    setTableToDelete(tableName);
    setDeleteDialogOpen(true);
  };

  // 테이블 삭제 실행
  const handleDeleteTable = async () => {
    if (!tableToDelete) return;

    setIsDeleting(true);
    try {
      const result = await ddlApi.dropTable(tableToDelete);

      if (result.success) {
        toast.success(`테이블 '${tableToDelete}'이 성공적으로 삭제되었습니다.`);

        // 삭제된 테이블이 선택된 테이블이었다면 선택 해제
        if (selectedTable === tableToDelete) {
          setSelectedTable(null);
          setColumns([]);
        }

        // 테이블 목록 새로고침
        await loadTables();
      } else {
        showErrorToast("테이블 삭제에 실패했습니다", result.message, {
          guidance: "테이블에 종속된 데이터가 있는지 확인해 주세요.",
        });
      }
    } catch (error: any) {
      showErrorToast("테이블 삭제에 실패했습니다", error, {
        guidance: "테이블에 종속된 데이터가 있는지 확인해 주세요.",
      });
    } finally {
      setIsDeleting(false);
      setDeleteDialogOpen(false);
      setTableToDelete("");
    }
  };

  // 체크박스 선택 핸들러
  const handleTableCheck = (tableName: string, checked: boolean) => {
    setSelectedTableIds((prev) => {
      const newSet = new Set(prev);
      if (checked) {
        newSet.add(tableName);
      } else {
        newSet.delete(tableName);
      }
      return newSet;
    });
  };

  // 전체 선택/해제
  const handleSelectAll = (checked: boolean) => {
    if (checked) {
      const filteredTables = tables.filter(
        (table) =>
          table.tableName.toLowerCase().includes(searchTerm.toLowerCase()) ||
          (table.displayName && table.displayName.toLowerCase().includes(searchTerm.toLowerCase())),
      );
      setSelectedTableIds(new Set(filteredTables.map((table) => table.tableName)));
    } else {
      setSelectedTableIds(new Set());
    }
  };

  // 일괄 삭제 확인
  const handleBulkDeleteClick = () => {
    if (selectedTableIds.size === 0) return;
    setDeleteDialogOpen(true);
  };

  // 일괄 삭제 실행
  const handleBulkDelete = async () => {
    if (selectedTableIds.size === 0) return;

    setIsDeleting(true);
    try {
      const tablesToDelete = Array.from(selectedTableIds);
      let successCount = 0;
      let failCount = 0;

      for (const tableName of tablesToDelete) {
        try {
          const result = await ddlApi.dropTable(tableName);
          if (result.success) {
            successCount++;
            // 삭제된 테이블이 선택된 테이블이었다면 선택 해제
            if (selectedTable === tableName) {
              setSelectedTable(null);
              setColumns([]);
            }
          } else {
            failCount++;
          }
        } catch (error) {
          failCount++;
        }
      }

      if (successCount > 0) {
        toast.success(`${successCount}개의 테이블이 성공적으로 삭제되었습니다.`);
      }
      if (failCount > 0) {
        toast.error(`${failCount}개의 테이블 삭제에 실패했습니다.`);
      }

      // 선택 초기화 및 테이블 목록 새로고침
      setSelectedTableIds(new Set());
      await loadTables();
    } catch (error: any) {
      showErrorToast("테이블 삭제에 실패했습니다", error, {
        guidance: "테이블에 종속된 데이터가 있는지 확인해 주세요.",
      });
    } finally {
      setIsDeleting(false);
      setDeleteDialogOpen(false);
      setTableToDelete("");
    }
  };

  return (
    <div className="bg-background flex h-screen flex-col overflow-hidden">
      {/* 컴팩트 탑바 (52px) */}
      <div className="flex h-[52px] flex-shrink-0 items-center justify-between border-b px-5">
        <div className="flex items-center gap-3">
          <Database className="h-4.5 w-4.5 text-muted-foreground" />
          <h1 className="text-[15px] font-bold tracking-tight">
            {getTextFromUI(TABLE_MANAGEMENT_KEYS.PAGE_TITLE, "테이블 타입 관리")}
          </h1>
          <Badge variant="secondary" className="text-[10px] font-bold">
            {tables.length} 테이블
          </Badge>
        </div>
        <div className="flex items-center gap-1.5">
          {isSuperAdmin && (
            <>
              <Button
                onClick={() => {
                  setDuplicateModalMode("create");
                  setDuplicateSourceTable(null);
                  setCreateTableModalOpen(true);
                }}
                size="sm"
                className="h-8 gap-1.5 text-xs"
              >
                <Plus className="h-3.5 w-3.5" />
                새 테이블
              </Button>
              <Button
                onClick={() => {
                  if (selectedTableIds.size !== 1) {
                    toast.error("복제할 테이블을 1개만 선택해주세요.");
                    return;
                  }
                  const sourceTable = Array.from(selectedTableIds)[0];
                  setDuplicateSourceTable(sourceTable);
                  setDuplicateModalMode("duplicate");
                  setCreateTableModalOpen(true);
                }}
                variant="outline"
                size="sm"
                disabled={selectedTableIds.size !== 1}
                className="h-8 gap-1.5 text-xs"
              >
                <Copy className="h-3.5 w-3.5" />
                복제
              </Button>
              {selectedTable && (
                <Button
                  onClick={() => setAddColumnModalOpen(true)}
                  variant="outline"
                  size="sm"
                  className="h-8 gap-1.5 text-xs"
                >
                  <Plus className="h-3.5 w-3.5" />
                  컬럼 추가
                </Button>
              )}
              <Button
                onClick={() => setDdlLogViewerOpen(true)}
                variant="ghost"
                size="sm"
                className="h-8 gap-1.5 text-xs"
              >
                <Activity className="h-3.5 w-3.5" />
                DDL
              </Button>
            </>
          )}
          <Button
            onClick={loadTables}
            disabled={loading}
            variant="ghost"
            size="sm"
            className="h-8 gap-1.5 text-xs"
          >
            <RefreshCw className={cn("h-3.5 w-3.5", loading && "animate-spin")} />
          </Button>
        </div>
      </div>

      {/* 3패널 메인 */}
      <div className="flex flex-1 overflow-hidden">
        {/* 좌측: 테이블 목록 (240px) */}
        <div className="bg-card flex w-[280px] min-w-[280px] flex-shrink-0 flex-col border-r">
          {/* 검색 */}
          <div className="flex-shrink-0 p-3 pb-0">
            <div className="relative">
              <Search className="text-muted-foreground absolute top-1/2 left-2.5 h-3.5 w-3.5 -translate-y-1/2" />
              <Input
                placeholder={getTextFromUI(TABLE_MANAGEMENT_KEYS.SEARCH_PLACEHOLDER, "테이블 검색...")}
                value={searchTerm}
                onChange={(e) => setSearchTerm(e.target.value)}
                className="bg-background h-[34px] pl-8 text-xs"
              />
            </div>
            {isSuperAdmin && (
              <div className="mt-2 flex items-center justify-between border-b pb-2">
                <div className="flex items-center gap-1.5">
                  <Checkbox
                    checked={
                      filteredTables.length > 0 &&
                      filteredTables.every((table) => selectedTableIds.has(table.tableName))
                    }
                    onCheckedChange={handleSelectAll}
                    aria-label="전체 선택"
                    className="h-3.5 w-3.5"
                  />
                  <span className="text-muted-foreground text-[10px]">
                    {selectedTableIds.size > 0 ? `${selectedTableIds.size}개` : "전체"}
                  </span>
                </div>
                {selectedTableIds.size > 0 && (
                  <Button
                    variant="destructive"
                    size="sm"
                    onClick={handleBulkDeleteClick}
                    className="h-6 gap-1 px-2 text-[10px]"
                  >
                    <Trash2 className="h-3 w-3" />
                    삭제
                  </Button>
                )}
              </div>
            )}
          </div>

          {/* 테이블 리스트 */}
          <div className="flex-1 overflow-y-auto px-1">
            {loading ? (
              <div className="flex items-center justify-center py-8">
                <LoadingSpinner />
              </div>
            ) : filteredTables.length === 0 ? (
              <div className="text-muted-foreground py-8 text-center text-xs">
                {getTextFromUI(TABLE_MANAGEMENT_KEYS.MESSAGE_NO_TABLES, "테이블이 없습니다")}
              </div>
            ) : (
              filteredTables.map((table, idx) => {
                const isActive = selectedTable === table.tableName;
                const prevTable = idx > 0 ? filteredTables[idx - 1] : null;
                const isKo = /^[가-힣ㄱ-ㅎ]/.test(table.displayName || table.tableName);
                const prevIsKo = prevTable ? /^[가-힣ㄱ-ㅎ]/.test(prevTable.displayName || prevTable.tableName) : null;
                const showDivider = idx === 0 || (prevIsKo !== null && isKo !== prevIsKo);

                return (
                  <div key={table.tableName}>
                    {showDivider && (
                      <div className="text-muted-foreground/60 mt-2 mb-1 px-2 text-[9px] font-bold uppercase tracking-widest">
                        {isKo ? "한글" : "ENGLISH"}
                      </div>
                    )}
                    <div
                      className={cn(
                        "group relative flex items-center gap-2 rounded-md px-2.5 py-[7px] transition-colors",
                        isActive
                          ? "bg-accent text-foreground"
                          : "text-foreground/80 hover:bg-accent/50",
                      )}
                      onClick={() => handleTableSelect(table.tableName)}
                      role="button"
                      tabIndex={0}
                      onKeyDown={(e) => {
                        if (e.key === "Enter" || e.key === " ") {
                          e.preventDefault();
                          handleTableSelect(table.tableName);
                        }
                      }}
                    >
                      {isActive && (
                        <div className="bg-primary absolute top-1.5 bottom-1.5 left-0 w-[3px] rounded-r" />
                      )}
                      {isSuperAdmin && (
                        <Checkbox
                          checked={selectedTableIds.has(table.tableName)}
                          onCheckedChange={(checked) => handleTableCheck(table.tableName, checked as boolean)}
                          aria-label={`${table.displayName || table.tableName} 선택`}
                          className="h-3.5 w-3.5 flex-shrink-0"
                          onClick={(e) => e.stopPropagation()}
                        />
                      )}
                      <div className="min-w-0 flex-1">
                        <div className="flex items-baseline gap-1">
                          <span className={cn(
                            "truncate text-[16px] leading-tight",
                            isActive ? "font-bold" : "font-medium",
                          )}>
                            {table.displayName || table.tableName}
                          </span>
                        </div>
                        <div className="text-muted-foreground truncate font-mono text-[12px] leading-tight tracking-tight">
                          {table.tableName}
                        </div>
                      </div>
                      <span className={cn(
                        "flex-shrink-0 rounded-full px-1.5 py-0.5 font-mono text-[10px] font-bold leading-none",
                        isActive
                          ? "bg-primary/15 text-primary"
                          : "text-muted-foreground",
                      )}>
                        {table.columnCount}
                      </span>
                    </div>
                  </div>
                );
              })
            )}
          </div>

          {/* 하단 정보 */}
          <div className="text-muted-foreground flex-shrink-0 border-t px-3 py-2 text-[10px] font-medium">
            {filteredTables.length} / {tables.length} 테이블
          </div>
        </div>

        {/* 중앙: 컬럼 그리드 */}
        <div className="flex min-w-0 flex-1 flex-col overflow-hidden">
          {!selectedTable ? (
            <div className="flex flex-1 flex-col items-center justify-center gap-2">
              <Database className="text-muted-foreground/40 h-10 w-10" />
              <p className="text-muted-foreground text-sm">
                {getTextFromUI(TABLE_MANAGEMENT_KEYS.SELECT_TABLE_PLACEHOLDER, "테이블을 선택해주세요")}
              </p>
            </div>
          ) : (
            <>
              {/* 중앙 헤더: 테이블명 + 라벨 입력 + 저장 */}
              <div className="bg-card flex flex-shrink-0 items-center gap-3 border-b px-5 py-3">
                <div className="min-w-0 flex-shrink-0">
                  <div className="text-[15px] font-bold tracking-tight">
                    {tableLabel || selectedTable}
                  </div>
                  <div className="text-muted-foreground font-mono text-[11px] tracking-tight">
                    {selectedTable}
                  </div>
                </div>
                <div className="flex min-w-0 flex-1 items-center gap-2">
                  <Input
                    value={tableLabel}
                    onChange={(e) => setTableLabel(e.target.value)}
                    placeholder="표시명"
                    className="h-8 max-w-[160px] text-xs"
                  />
                  <Input
                    value={tableDescription}
                    onChange={(e) => setTableDescription(e.target.value)}
                    placeholder="설명"
                    className="h-8 max-w-[200px] text-xs"
                  />
                </div>
                <Button
                  onClick={saveAllSettings}
                  disabled={!selectedTable || columns.length === 0 || isSaving}
                  size="sm"
                  className="h-8 gap-1.5 text-xs"
                >
                  {isSaving ? (
                    <Loader2 className="h-3.5 w-3.5 animate-spin" />
                  ) : (
                    <Save className="h-3.5 w-3.5" />
                  )}
                  {isSaving ? "저장 중..." : "전체 설정 저장"}
                </Button>
              </div>

              {columnsLoading ? (
                <div className="flex flex-1 items-center justify-center">
                  <LoadingSpinner />
                  <span className="text-muted-foreground ml-2 text-sm">
                    {getTextFromUI(TABLE_MANAGEMENT_KEYS.MESSAGE_LOADING_COLUMNS, "컬럼 정보 로딩 중...")}
                  </span>
                </div>
              ) : columns.length === 0 ? (
                <div className="text-muted-foreground flex flex-1 items-center justify-center text-sm">
                  {getTextFromUI(TABLE_MANAGEMENT_KEYS.MESSAGE_NO_COLUMNS, "컬럼이 없습니다")}
                </div>
              ) : (
                <>
                  <TypeOverviewStrip
                    columns={columns}
                    activeFilter={typeFilter}
                    onFilterChange={setTypeFilter}
                  />
                  <ColumnGrid
                    columns={columns}
                    selectedColumn={selectedColumn}
                    onSelectColumn={setSelectedColumn}
                    onColumnChange={(columnName, field, value) => {
                      if (field === "isUnique") {
                        const currentColumn = columns.find((c) => c.columnName === columnName);
                        if (currentColumn) {
                          handleUniqueToggle(columnName, currentColumn.isUnique || "NO");
                        }
                        return;
                      }
                      if (field === "isNullable") {
                        const currentColumn = columns.find((c) => c.columnName === columnName);
                        if (currentColumn) {
                          handleNullableToggle(columnName, currentColumn.isNullable || "YES");
                        }
                        return;
                      }
                      const idx = columns.findIndex((c) => c.columnName === columnName);
                      if (idx >= 0) handleColumnChange(idx, field, value);
                    }}
                    constraints={constraints}
                    typeFilter={typeFilter}
                    getColumnIndexState={getColumnIndexState}
                    onPkToggle={handlePkToggle}
                    onIndexToggle={(columnName, checked) =>
                      handleIndexToggle(columnName, "index", checked)
                    }
                    tables={tables}
                    referenceTableColumns={referenceTableColumns}
                  />
                </>
              )}
            </>
          )}
        </div>

        {/* 우측: 상세 패널 (selectedColumn 있을 때만) */}
        {selectedColumn && (
          <div className="w-[380px] min-w-[380px] flex-shrink-0 overflow-hidden">
            <ColumnDetailPanel
              column={columns.find((c) => c.columnName === selectedColumn) ?? null}
              tables={tables}
              referenceTableColumns={referenceTableColumns}
              secondLevelMenus={secondLevelMenus}
              numberingRules={[]}
              onColumnChange={(field, value) => {
                if (!selectedColumn) return;
                if (field === "inputType") {
                  handleInputTypeChange(selectedColumn, value as string);
                  return;
                }
                if (field === "referenceTable" && value) {
                  loadReferenceTableColumns(value as string);
                }
                setColumns((prev) =>
                  prev.map((c) =>
                    c.columnName === selectedColumn ? { ...c, [field]: value } : c,
                  ),
                );
              }}
              onClose={() => setSelectedColumn(null)}
              onLoadReferenceColumns={loadReferenceTableColumns}
              codeCategoryOptions={commonCodeOptions}
              referenceTableOptions={referenceTableOptions}
            />
          </div>
        )}
      </div>

        {/* DDL 모달 컴포넌트들 */}
        {isSuperAdmin && (
          <>
            <CreateTableModal
              isOpen={createTableModalOpen}
              onClose={() => {
                setCreateTableModalOpen(false);
                setDuplicateModalMode("create");
                setDuplicateSourceTable(null);
              }}
              onSuccess={async (result) => {
                const message =
                  duplicateModalMode === "duplicate"
                    ? "테이블이 성공적으로 복제되었습니다!"
                    : "테이블이 성공적으로 생성되었습니다!";
                toast.success(message);
                // 테이블 목록 새로고침
                await loadTables();
                // 새로 생성된 테이블 자동 선택 및 컬럼 로드
                if (result.data?.tableName) {
                  setSelectedTable(result.data.tableName);
                  setCurrentPage(1);
                  setColumns([]);
                  await loadColumnTypes(result.data.tableName, 1, pageSize);
                }
                // 선택 초기화
                setSelectedTableIds(new Set());
                // 상태 초기화
                setDuplicateModalMode("create");
                setDuplicateSourceTable(null);
              }}
              mode={duplicateModalMode}
              sourceTableName={duplicateSourceTable || undefined}
            />

            <AddColumnModal
              isOpen={addColumnModalOpen}
              onClose={() => setAddColumnModalOpen(false)}
              tableName={selectedTable || ""}
              onSuccess={async (result) => {
                toast.success("컬럼이 성공적으로 추가되었습니다!");
                // 테이블 목록 새로고침 (컬럼 수 업데이트)
                await loadTables();
                // 선택된 테이블의 컬럼 목록 새로고침 - 페이지 리셋
                if (selectedTable) {
                  setCurrentPage(1);
                  setColumns([]); // 기존 컬럼 목록 초기화
                  await loadColumnTypes(selectedTable, 1, pageSize);
                }
              }}
            />

            <DDLLogViewer isOpen={ddlLogViewerOpen} onClose={() => setDdlLogViewerOpen(false)} />

            {/* 테이블 로그 뷰어 */}
            <TableLogViewer tableName={logViewerTableName} open={logViewerOpen} onOpenChange={setLogViewerOpen} />

            {/* 테이블 삭제 확인 다이얼로그 */}
            <Dialog open={deleteDialogOpen} onOpenChange={setDeleteDialogOpen}>
              <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
                <DialogHeader>
                  <DialogTitle className="text-base sm:text-lg">
                    {selectedTableIds.size > 0 ? "테이블 일괄 삭제 확인" : "테이블 삭제 확인"}
                  </DialogTitle>
                  <DialogDescription className="text-xs sm:text-sm">
                    {selectedTableIds.size > 0 ? (
                      <>
                        선택된 <strong>{selectedTableIds.size}개</strong>의 테이블을 삭제하시겠습니까?
                        <br />이 작업은 되돌릴 수 없습니다.
                      </>
                    ) : (
                      <>정말로 테이블을 삭제하시겠습니까? 이 작업은 되돌릴 수 없습니다.</>
                    )}
                  </DialogDescription>
                </DialogHeader>

                {selectedTableIds.size === 0 && tableToDelete && (
                  <div className="space-y-3 sm:space-y-4">
                    <div className="border-destructive/50 bg-destructive/10 rounded-lg border p-4">
                      <p className="text-destructive text-sm font-semibold">경고</p>
                      <p className="text-destructive/80 mt-1.5 text-sm">
                        테이블 <span className="font-mono font-bold">{tableToDelete}</span>과 모든 데이터가 영구적으로
                        삭제됩니다.
                      </p>
                    </div>
                  </div>
                )}

                {selectedTableIds.size > 0 && (
                  <div className="space-y-3 sm:space-y-4">
                    <div className="border-destructive/50 bg-destructive/10 rounded-lg border p-4">
                      <p className="text-destructive text-sm font-semibold">경고</p>
                      <p className="text-destructive/80 mt-1.5 text-sm">
                        다음 테이블들과 모든 데이터가 영구적으로 삭제됩니다:
                      </p>
                      <ul className="text-destructive/80 mt-2 list-disc pl-5 text-sm">
                        {Array.from(selectedTableIds).map((tableName) => (
                          <li key={tableName} className="font-mono">
                            {tableName}
                          </li>
                        ))}
                      </ul>
                    </div>
                  </div>
                )}

                <DialogFooter className="gap-2 sm:gap-0">
                  <Button
                    variant="outline"
                    onClick={() => {
                      setDeleteDialogOpen(false);
                      setTableToDelete("");
                      setSelectedTableIds(new Set());
                    }}
                    disabled={isDeleting}
                    className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
                  >
                    취소
                  </Button>
                  <Button
                    variant="destructive"
                    onClick={selectedTableIds.size > 0 ? handleBulkDelete : handleDeleteTable}
                    disabled={isDeleting}
                    className="h-8 flex-1 gap-2 text-xs sm:h-10 sm:flex-none sm:text-sm"
                  >
                    {isDeleting ? (
                      <>
                        <RefreshCw className="h-4 w-4 animate-spin" />
                        삭제 중...
                      </>
                    ) : (
                      <>
                        <Trash2 className="h-4 w-4" />
                        삭제
                      </>
                    )}
                  </Button>
                </DialogFooter>
              </DialogContent>
            </Dialog>
          </>
        )}

        {/* PK 변경 확인 다이얼로그 */}
        <Dialog open={pkDialogOpen} onOpenChange={setPkDialogOpen}>
          <DialogContent className="max-w-[95vw] sm:max-w-[500px]">
            <DialogHeader>
              <DialogTitle className="text-base sm:text-lg">PK 변경 확인</DialogTitle>
              <DialogDescription className="text-xs sm:text-sm">
                PK를 변경하면 기존 제약조건이 삭제되고 새로 생성됩니다.
                <br />데이터 무결성에 영향을 줄 수 있습니다.
              </DialogDescription>
            </DialogHeader>

            <div className="space-y-3 sm:space-y-4">
              <div className="rounded-lg border p-4">
                <p className="text-sm font-medium">변경될 PK 컬럼:</p>
                {pendingPkColumns.length > 0 ? (
                  <div className="mt-2 flex flex-wrap gap-2">
                    {pendingPkColumns.map((col) => {
                      const colInfo = columns.find((c) => c.columnName === col);
                      return (
                        <Badge key={col} variant="secondary" className="text-xs">
                          {colInfo?.displayName && colInfo.displayName !== col
                            ? `${colInfo.displayName} (${col})`
                            : col}
                        </Badge>
                      );
                    })}
                  </div>
                ) : (
                  <p className="text-destructive mt-2 text-sm">PK가 모두 제거됩니다</p>
                )}
              </div>
            </div>

            <DialogFooter className="gap-2 sm:gap-0">
              <Button
                variant="outline"
                onClick={() => setPkDialogOpen(false)}
                className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
              >
                취소
              </Button>
              <Button
                onClick={handlePkConfirm}
                className="h-8 flex-1 text-xs sm:h-10 sm:flex-none sm:text-sm"
              >
                변경
              </Button>
            </DialogFooter>
          </DialogContent>
        </Dialog>

        {/* Scroll to Top 버튼 */}
        <ScrollToTop />
    </div>
  );
}
