"use client";

import React, { useState, useEffect, useMemo, useCallback, useRef } from "react";
import { TableListConfig, ColumnConfig } from "./types";
import { WebType } from "@/types/common";
import { tableTypeApi } from "@/lib/api/screen";
import { entityJoinApi } from "@/lib/api/entityJoin";
import { codeCache } from "@/lib/caching/codeCache";

// 전역 테이블 캐시
const tableColumnCache = new Map<string, { columns: any[]; timestamp: number }>();
const tableInfoCache = new Map<string, { tables: any[]; timestamp: number }>();
const TABLE_CACHE_TTL = 5 * 60 * 1000; // 5분

// 캐시 정리 함수
const cleanupTableCache = () => {
  const now = Date.now();

  // 컬럼 캐시 정리
  for (const [key, entry] of tableColumnCache.entries()) {
    if (now - entry.timestamp > TABLE_CACHE_TTL) {
      tableColumnCache.delete(key);
    }
  }

  // 테이블 정보 캐시 정리
  for (const [key, entry] of tableInfoCache.entries()) {
    if (now - entry.timestamp > TABLE_CACHE_TTL) {
      tableInfoCache.delete(key);
    }
  }
};

// 주기적으로 캐시 정리 (10분마다)
if (typeof window !== "undefined") {
  setInterval(cleanupTableCache, 10 * 60 * 1000);
}

// 요청 디바운싱을 위한 전역 타이머
const debounceTimers = new Map<string, NodeJS.Timeout>();

// 진행 중인 요청 추적 (중복 요청 방지)
const activeRequests = new Map<string, Promise<any>>();

// 디바운싱된 API 호출 함수 (중복 요청 방지 포함)
const debouncedApiCall = <T extends any[], R>(key: string, fn: (...args: T) => Promise<R>, delay: number = 300) => {
  return (...args: T): Promise<R> => {
    // 이미 진행 중인 동일한 요청이 있으면 그 결과를 반환
    const activeRequest = activeRequests.get(key);
    if (activeRequest) {
      console.log(`🔄 진행 중인 요청 재사용: ${key}`);
      return activeRequest as Promise<R>;
    }

    return new Promise((resolve, reject) => {
      // 기존 타이머 제거
      const existingTimer = debounceTimers.get(key);
      if (existingTimer) {
        clearTimeout(existingTimer);
      }

      // 새 타이머 설정
      const timer = setTimeout(async () => {
        try {
          // 요청 시작 시 활성 요청으로 등록
          const requestPromise = fn(...args);
          activeRequests.set(key, requestPromise);

          const result = await requestPromise;
          resolve(result);
        } catch (error) {
          reject(error);
        } finally {
          debounceTimers.delete(key);
          activeRequests.delete(key);
        }
      }, delay);

      debounceTimers.set(key, timer);
    });
  };
};
import { useEntityJoinOptimization } from "@/lib/hooks/useEntityJoinOptimization";
import { Button } from "@/components/ui/button";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import {
  ChevronLeft,
  ChevronRight,
  ChevronsLeft,
  ChevronsRight,
  RefreshCw,
  ArrowUpDown,
  ArrowUp,
  ArrowDown,
  TableIcon,
} from "lucide-react";
import { Checkbox } from "@/components/ui/checkbox";
import { cn } from "@/lib/utils";
import { AdvancedSearchFilters } from "@/components/screen/filters/AdvancedSearchFilters";
import { SingleTableWithSticky } from "./SingleTableWithSticky";
import { CardModeRenderer } from "./CardModeRenderer";

export interface TableListComponentProps {
  component: any;
  isDesignMode?: boolean;
  isSelected?: boolean;
  isInteractive?: boolean;
  onClick?: () => void;
  onDragStart?: (e: React.DragEvent) => void;
  onDragEnd?: (e: React.DragEvent) => void;
  className?: string;
  style?: React.CSSProperties;
  formData?: Record<string, any>;
  onFormDataChange?: (data: any) => void;
  config?: TableListConfig;

  // 추가 props (DOM에 전달되지 않음)
  size?: { width: number; height: number };
  position?: { x: number; y: number; z?: number };
  componentConfig?: any;
  selectedScreen?: any;
  onZoneComponentDrop?: any;
  onZoneClick?: any;
  tableName?: string;
  onRefresh?: () => void;
  onClose?: () => void;
  screenId?: string;

  // 선택된 행 정보 전달 핸들러
  onSelectedRowsChange?: (selectedRows: any[], selectedRowsData: any[]) => void;

  // 설정 변경 핸들러 (상세설정과 연동)
  onConfigChange?: (config: any) => void;

  // 테이블 새로고침 키
  refreshKey?: number;
}

/**
 * TableList 컴포넌트
 * 데이터베이스 테이블의 데이터를 목록으로 표시하는 컴포넌트
 */
export const TableListComponent: React.FC<TableListComponentProps> = ({
  component,
  isDesignMode = false,
  isSelected = false,
  onClick,
  onDragStart,
  onDragEnd,
  config,
  className,
  style,
  onFormDataChange,
  componentConfig,
  onSelectedRowsChange,
  onConfigChange,
  refreshKey,
}) => {
  // 컴포넌트 설정
  const tableConfig = {
    ...config,
    ...component.config,
    ...componentConfig,
  } as TableListConfig;

  // 🎨 동적 색상 설정 (속성편집 모달의 "색상" 필드와 연동)
  const buttonColor = component.style?.labelColor || "#3b83f6"; // 기본 파란색
  const buttonTextColor = component.config?.buttonTextColor || "#ffffff";
  const buttonStyle = {
    backgroundColor: buttonColor,
    color: buttonTextColor,
    borderColor: buttonColor,
  };

  // 디버깅 로그 제거 (성능상 이유로)

  // 상태 관리
  const [data, setData] = useState<Record<string, any>[]>([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [currentPage, setCurrentPage] = useState(1);
  const [totalPages, setTotalPages] = useState(0);
  const [totalItems, setTotalItems] = useState(0);
  const [searchTerm, setSearchTerm] = useState("");
  const [sortColumn, setSortColumn] = useState<string | null>(null);
  const [sortDirection, setSortDirection] = useState<"asc" | "desc">("asc");
  const [columnLabels, setColumnLabels] = useState<Record<string, string>>({});
  const [tableLabel, setTableLabel] = useState<string>("");
  const [localPageSize, setLocalPageSize] = useState<number>(tableConfig.pagination?.pageSize || 20); // 로컬 페이지 크기 상태
  const [displayColumns, setDisplayColumns] = useState<ColumnConfig[]>([]); // 🎯 표시할 컬럼 (Entity 조인 적용됨)

  // 🎯 조인 컬럼 매핑 상태
  const [joinColumnMapping, setJoinColumnMapping] = useState<Record<string, string>>({});
  const [columnMeta, setColumnMeta] = useState<Record<string, { webType?: string; codeCategory?: string }>>({}); // 🎯 컬럼 메타정보 (웹타입, 코드카테고리)

  // 컬럼 정보 메모이제이션
  const memoizedColumnInfo = useMemo(() => {
    return {
      labels: columnLabels,
      meta: columnMeta,
      visibleColumns: (tableConfig.columns || []).filter((col) => col.visible !== false),
    };
  }, [columnLabels, columnMeta, tableConfig.columns]);

  // 고급 필터 관련 state
  const [searchValues, setSearchValues] = useState<Record<string, any>>({});

  // 체크박스 상태 관리
  const [selectedRows, setSelectedRows] = useState<Set<string>>(new Set());

  // 드래그 상태 관리
  const [isDragging, setIsDragging] = useState(false);
  const [draggedRowIndex, setDraggedRowIndex] = useState<number | null>(null); // 선택된 행들의 키 집합
  const [isAllSelected, setIsAllSelected] = useState(false); // 전체 선택 상태

  // 🎯 Entity 조인 최적화 훅 사용
  const { optimizedConvertCode } = useEntityJoinOptimization(columnMeta, {
    enableBatchLoading: true,
    preloadCommonCodes: true,
    maxBatchSize: 5,
  });

  // 높이 계산 함수 (메모이제이션)
  const optimalHeight = useMemo(() => {
    // 실제 데이터 개수에 맞춰서 높이 계산 (최소 5개, 최대 20개)
    const actualDataCount = data.length;
    const displayPageSize = Math.min(Math.max(actualDataCount, 5), 20);

    const headerHeight = 50; // 테이블 헤더
    const rowHeight = 42; // 각 행 높이
    const searchHeight = tableConfig.filter?.enabled ? 80 : 0; // 검색 영역
    const footerHeight = tableConfig.showFooter ? 60 : 0; // 페이지네이션
    const titleHeight = tableConfig.showHeader ? 60 : 0; // 제목 영역
    const padding = 40; // 여백

    const calculatedHeight =
      titleHeight + searchHeight + headerHeight + displayPageSize * rowHeight + footerHeight + padding;

    console.log("🔍 테이블 높이 계산:", {
      actualDataCount,
      localPageSize,
      displayPageSize,
      isDesignMode,
      titleHeight,
      searchHeight,
      headerHeight,
      rowHeight,
      footerHeight,
      padding,
      calculatedHeight,
      finalHeight: `${calculatedHeight}px`,
    });

    // 추가 디버깅: 실제 데이터 상황
    console.log("🔍 실제 데이터 상황:", {
      actualDataLength: data.length,
      localPageSize,
      currentPage,
      totalItems,
      totalPages,
    });

    return calculatedHeight;
  }, []);

  // 🎯 강제로 그리드 컬럼수에 맞는 크기 적용 (디자인 모드에서는 더 큰 크기 허용)
  const gridColumns = component.gridColumns || 1;
  let calculatedWidth: string;

  if (isDesignMode) {
    // 디자인 모드에서는 더 큰 최소 크기 적용
    if (gridColumns === 1) {
      calculatedWidth = "400px"; // 1컬럼일 때 400px (디자인 모드)
    } else if (gridColumns === 2) {
      calculatedWidth = "600px"; // 2컬럼일 때 600px (디자인 모드)
    } else if (gridColumns <= 6) {
      calculatedWidth = `${gridColumns * 250}px`; // 컬럼당 250px (디자인 모드)
    } else {
      calculatedWidth = "100%"; // 7컬럼 이상은 전체
    }
  } else {
    // 일반 모드는 기존 크기 유지
    if (gridColumns === 1) {
      calculatedWidth = "200px"; // 1컬럼일 때 200px 고정
    } else if (gridColumns === 2) {
      calculatedWidth = "400px"; // 2컬럼일 때 400px
    } else if (gridColumns <= 6) {
      calculatedWidth = `${gridColumns * 200}px`; // 컬럼당 200px
    } else {
      calculatedWidth = "100%"; // 7컬럼 이상은 전체
    }
  }

  // 디버깅 로그 제거 (성능상 이유로)

  // 스타일 계산 (컨테이너에 맞춤)
  const componentStyle: React.CSSProperties = {
    width: "100%", // 컨테이너 전체 너비 사용
    maxWidth: "100%", // 최대 너비 제한
    height: "auto", // 항상 자동 높이로 테이블 크기에 맞춤
    minHeight: isDesignMode ? "200px" : "300px", // 최소 높이만 보장
    maxHeight: isDesignMode ? "600px" : "800px", // 최대 높이 제한으로 스크롤 활성화
    ...component.style,
    ...style,
    display: "flex",
    flexDirection: "column",
    boxSizing: "border-box", // 패딩/보더 포함한 크기 계산
    // overflow는 CSS 클래스로 처리
  };

  // 🎯 tableContainerStyle 제거 - componentStyle만 사용

  // 디자인 모드 스타일
  if (isDesignMode) {
    componentStyle.border = "2px dashed #cbd5e1";
    componentStyle.borderColor = isSelected ? "#3b82f6" : "#cbd5e1";
    componentStyle.borderRadius = "8px";
    componentStyle.padding = "4px"; // 약간의 패딩으로 구분감 확보
    componentStyle.margin = "2px"; // 외부 여백으로 레이아웃과 구분
    // 🎯 컨테이너에 맞춤
    componentStyle.width = "calc(100% - 12px)"; // margin + padding 보정
    componentStyle.maxWidth = "calc(100% - 12px)";
    componentStyle.minWidth = "calc(100% - 12px)";
    componentStyle.overflow = "hidden !important"; // 넘치는 부분 숨김 (강제)
    componentStyle.boxSizing = "border-box"; // 패딩 포함 크기 계산
    componentStyle.position = "relative"; // 위치 고정
    // 자동 높이로 테이블 전체를 감쌈
  }

  // 컬럼 라벨 정보 가져오기 (캐싱 적용)
  const fetchColumnLabels = async () => {
    if (!tableConfig.selectedTable) return;

    // 캐시 확인
    const cacheKey = tableConfig.selectedTable;
    const cached = tableColumnCache.get(cacheKey);
    const now = Date.now();

    let columns: any[] = [];

    if (cached && now - cached.timestamp < TABLE_CACHE_TTL) {
      console.log(`🚀 테이블 컬럼 캐시 사용: ${cacheKey}`);
      columns = cached.columns;
    } else {
      try {
        console.log(`🔄 테이블 컬럼 API 호출: ${cacheKey}`);
        const response = await tableTypeApi.getColumns(tableConfig.selectedTable);
        // API 응답 구조 확인 및 컬럼 배열 추출
        columns = Array.isArray(response) ? response : (response as any).columns || [];

        // 캐시 저장
        tableColumnCache.set(cacheKey, { columns, timestamp: now });
        console.log(`✅ 테이블 컬럼 캐시 저장: ${cacheKey} (${columns.length}개 컬럼)`);
      } catch (error) {
        console.log("컬럼 라벨 정보를 가져올 수 없습니다:", error);
        return;
      }
    }

    const labels: Record<string, string> = {};
    const meta: Record<string, { webType?: string; codeCategory?: string }> = {};

    columns.forEach((column: any) => {
      // 🎯 Entity 조인된 컬럼의 경우 표시 컬럼명 사용
      let displayLabel = column.displayName || column.columnName;

      // Entity 타입인 경우
      if (column.webType === "entity") {
        // 우선 기준 테이블의 컬럼 라벨을 사용
        displayLabel = column.displayName || column.columnName;
        console.log(`🎯 Entity 조인 컬럼 라벨 설정: ${column.columnName} → "${displayLabel}" (기준 테이블 라벨 사용)`);
      }

      labels[column.columnName] = displayLabel;
      // 🎯 웹타입과 코드카테고리 정보 저장
      meta[column.columnName] = {
        webType: column.webType,
        codeCategory: column.codeCategory,
      };
    });

    setColumnLabels(labels);
    setColumnMeta(meta);
    console.log("🔍 컬럼 라벨 설정 완료:", labels);
    console.log("🔍 컬럼 메타정보 설정 완료:", meta);
  };

  // 🎯 전역 코드 캐시 사용으로 함수 제거 (codeCache.convertCodeToName 사용)

  // 테이블 라벨명 가져오기 (캐싱 적용)
  const fetchTableLabel = async () => {
    if (!tableConfig.selectedTable) return;

    // 캐시 확인
    const cacheKey = "all_tables";
    const cached = tableInfoCache.get(cacheKey);
    const now = Date.now();

    let tables: any[] = [];

    if (cached && now - cached.timestamp < TABLE_CACHE_TTL) {
      console.log(`🚀 테이블 정보 캐시 사용: ${cacheKey}`);
      tables = cached.tables;
    } else {
      try {
        console.log(`🔄 테이블 정보 API 호출: ${cacheKey}`);
        tables = await tableTypeApi.getTables();

        // 캐시 저장
        tableInfoCache.set(cacheKey, { tables, timestamp: now });
        console.log(`✅ 테이블 정보 캐시 저장: ${cacheKey} (${tables.length}개 테이블)`);
      } catch (error) {
        console.log("테이블 라벨 정보를 가져올 수 없습니다:", error);
        setTableLabel(tableConfig.selectedTable);
        return;
      }
    }

    const table = tables.find((t: any) => t.tableName === tableConfig.selectedTable);
    if (table && table.displayName && table.displayName !== table.tableName) {
      setTableLabel(table.displayName);
    } else {
      setTableLabel(tableConfig.selectedTable);
    }
  };

  // 디바운싱된 테이블 데이터 가져오기
  const fetchTableDataDebounced = useCallback(
    debouncedApiCall(
      `fetchTableData_${tableConfig.selectedTable}_${currentPage}_${localPageSize}`,
      async () => {
        return fetchTableDataInternal();
      },
      200, // 200ms 디바운스
    ),
    [tableConfig.selectedTable, currentPage, localPageSize, searchTerm, sortColumn, sortDirection, searchValues],
  );

  // 실제 테이블 데이터 가져오기 함수
  const fetchTableDataInternal = async () => {
    if (!tableConfig.selectedTable) {
      setData([]);
      return;
    }

    setLoading(true);
    setError(null);

    try {
      // 🎯 Entity 조인 API 사용 - Entity 조인이 포함된 데이터 조회
      console.log("🔗 Entity 조인 데이터 조회 시작:", tableConfig.selectedTable);

      // Entity 조인 컬럼 추출 (isEntityJoin === true인 컬럼들)
      const entityJoinColumns = tableConfig.columns?.filter((col) => col.isEntityJoin && col.entityJoinInfo) || [];

      // 🎯 조인 탭에서 추가한 컬럼들도 포함 (실제로 존재하는 컬럼만)
      const joinTabColumns =
        tableConfig.columns?.filter(
          (col) =>
            !col.isEntityJoin &&
            col.columnName.includes("_") &&
            (col.columnName.includes("dept_code_") ||
              col.columnName.includes("_dept_code") ||
              col.columnName.includes("_company_") ||
              col.columnName.includes("_user_")), // 조인 탭에서 추가한 컬럼 패턴들
        ) || [];

      console.log(
        "🔍 조인 탭 컬럼들:",
        joinTabColumns.map((c) => c.columnName),
      );

      const additionalJoinColumns = [
        ...entityJoinColumns.map((col) => ({
          sourceTable: col.entityJoinInfo!.sourceTable,
          sourceColumn: col.entityJoinInfo!.sourceColumn,
          joinAlias: col.entityJoinInfo!.joinAlias,
        })),
        // 🎯 조인 탭에서 추가한 컬럼들도 추가 (실제로 존재하는 컬럼만)
        ...joinTabColumns
          .filter((col) => {
            // 실제 API 응답에 존재하는 컬럼만 필터링
            const validJoinColumns = ["dept_code_name", "dept_name"];
            const isValid = validJoinColumns.includes(col.columnName);
            if (!isValid) {
              console.log(`🔍 조인 탭 컬럼 제외: ${col.columnName} (유효하지 않음)`);
            }
            return isValid;
          })
          .map((col) => {
            // 실제 존재하는 조인 컬럼만 처리
            let sourceTable = tableConfig.selectedTable;
            let sourceColumn = col.columnName;

            if (col.columnName === "dept_code_name" || col.columnName === "dept_name") {
              sourceTable = "dept_info";
              sourceColumn = "dept_code";
            }

            console.log(`🔍 조인 탭 컬럼 처리: ${col.columnName} -> ${sourceTable}.${sourceColumn}`);

            return {
              sourceTable: sourceTable || tableConfig.selectedTable || "",
              sourceColumn: sourceColumn,
              joinAlias: col.columnName,
            };
          }),
      ];

      // 🎯 화면별 엔티티 표시 설정 생성
      const screenEntityConfigs: Record<string, any> = {};
      entityJoinColumns.forEach((col) => {
        if (col.entityDisplayConfig) {
          const sourceColumn = col.entityJoinInfo!.sourceColumn;
          screenEntityConfigs[sourceColumn] = {
            displayColumns: col.entityDisplayConfig.displayColumns,
            separator: col.entityDisplayConfig.separator || " - ",
          };
        }
      });

      console.log("🔗 Entity 조인 컬럼:", entityJoinColumns);
      console.log("🔗 조인 탭 컬럼:", joinTabColumns);
      console.log("🔗 추가 Entity 조인 컬럼:", additionalJoinColumns);
      // console.log("🎯 화면별 엔티티 설정:", screenEntityConfigs);

      const result = await entityJoinApi.getTableDataWithJoins(tableConfig.selectedTable, {
        page: currentPage,
        size: localPageSize,
        search: (() => {
          // 고급 필터 값이 있으면 우선 사용
          const hasAdvancedFilters = Object.values(searchValues).some((value) => {
            if (typeof value === "string") return value.trim() !== "";
            if (typeof value === "object" && value !== null) {
              return Object.values(value).some((v) => v !== "" && v !== null && v !== undefined);
            }
            return value !== null && value !== undefined && value !== "";
          });

          if (hasAdvancedFilters) {
            console.log("🔍 고급 검색 필터 사용:", searchValues);
            console.log("🔍 고급 검색 필터 상세:", JSON.stringify(searchValues, null, 2));
            return searchValues;
          }

          // 고급 필터가 없으면 기존 단순 검색 사용
          if (searchTerm?.trim()) {
            // 스마트한 단일 컬럼 선택 로직 (서버가 OR 검색을 지원하지 않음)
            let searchColumn = sortColumn; // 정렬된 컬럼 우선

            if (!searchColumn) {
              // 1순위: name 관련 컬럼 (가장 검색에 적합)
              const nameColumns = visibleColumns.filter(
                (col) =>
                  col.columnName.toLowerCase().includes("name") ||
                  col.columnName.toLowerCase().includes("title") ||
                  col.columnName.toLowerCase().includes("subject"),
              );

              // 2순위: text/varchar 타입 컬럼
              const textColumns = visibleColumns.filter((col) => col.dataType === "text" || col.dataType === "varchar");

              // 3순위: description 관련 컬럼
              const descColumns = visibleColumns.filter(
                (col) =>
                  col.columnName.toLowerCase().includes("desc") ||
                  col.columnName.toLowerCase().includes("comment") ||
                  col.columnName.toLowerCase().includes("memo"),
              );

              // 우선순위에 따라 선택
              if (nameColumns.length > 0) {
                searchColumn = nameColumns[0].columnName;
              } else if (textColumns.length > 0) {
                searchColumn = textColumns[0].columnName;
              } else if (descColumns.length > 0) {
                searchColumn = descColumns[0].columnName;
              } else {
                // 마지막 대안: 첫 번째 컬럼
                searchColumn = visibleColumns[0]?.columnName || "id";
              }
            }

            console.log("🔍 기존 검색 방식 사용:", { [searchColumn]: searchTerm });
            return { [searchColumn]: searchTerm };
          }

          return undefined;
        })(),
        sortBy: sortColumn || undefined,
        sortOrder: sortDirection,
        enableEntityJoin: true, // 🎯 Entity 조인 활성화
        additionalJoinColumns: additionalJoinColumns.length > 0 ? additionalJoinColumns : undefined, // 추가 조인 컬럼
        screenEntityConfigs: Object.keys(screenEntityConfigs).length > 0 ? screenEntityConfigs : undefined, // 🎯 화면별 엔티티 설정
      });

      if (result) {
        // console.log("🎯 API 응답 결과:", result);
        // console.log("🎯 데이터 개수:", result.data?.length || 0);
        // console.log("🎯 전체 페이지:", result.totalPages);
        // console.log("🎯 총 아이템:", result.total);
        setData(result.data || []);
        setTotalPages(result.totalPages || 1);
        setTotalItems(result.total || 0);

        // 🎯 Entity 조인 정보 로깅
        if (result.entityJoinInfo) {
          console.log("🔗 Entity 조인 적용됨:", {
            strategy: result.entityJoinInfo.strategy,
            joinConfigs: result.entityJoinInfo.joinConfigs,
            performance: result.entityJoinInfo.performance,
          });
        } else {
          console.log("🔗 Entity 조인 없음");
        }

        // 🎯 코드 컬럼들의 캐시 미리 로드 (전역 캐시 사용)
        const codeColumns = Object.entries(columnMeta).filter(
          ([_, meta]) => meta.webType === "code" && meta.codeCategory,
        );

        if (codeColumns.length > 0) {
          console.log(
            "📋 코드 컬럼 감지:",
            codeColumns.map(([col, meta]) => `${col}(${meta.codeCategory})`),
          );

          // 필요한 코드 카테고리들을 추출하여 배치 로드 (중복 제거)
          const categoryList = [
            ...new Set(codeColumns.map(([, meta]) => meta.codeCategory).filter(Boolean)),
          ] as string[];

          // 이미 캐시된 카테고리는 제외
          const uncachedCategories = categoryList.filter((category) => !codeCache.getCodeSync(category));

          if (uncachedCategories.length > 0) {
            try {
              console.log(`📋 새로운 코드 카테고리 로딩: ${uncachedCategories.join(", ")}`);
              await codeCache.preloadCodes(uncachedCategories);
              console.log("📋 모든 코드 캐시 로드 완료 (전역 캐시)");
            } catch (error) {
              console.error("❌ 코드 캐시 로드 중 오류:", error);
            }
          } else {
            console.log("📋 모든 코드 카테고리가 이미 캐시됨");
          }
        }

        // 🎯 Entity 조인된 컬럼 처리 - 사용자가 설정한 컬럼들만 사용
        let processedColumns = [...(tableConfig.columns || [])];

        // 초기 컬럼이 있으면 먼저 설정
        if (processedColumns.length > 0) {
          console.log(
            "🔍 사용자 설정 컬럼들:",
            processedColumns.map((c) => c.columnName),
          );

          // 🎯 API 응답과 비교하여 존재하지 않는 컬럼 필터링
          if (result.data.length > 0) {
            const actualApiColumns = Object.keys(result.data[0]);
            console.log("🔍 API 응답의 실제 컬럼들:", actualApiColumns);

            // 🎯 조인 컬럼 매핑 테이블 (사용자 설정 → API 응답)
            // 실제 API 응답에 존재하는 컬럼만 매핑
            const newJoinColumnMapping: Record<string, string> = {
              dept_code_dept_code: "dept_code", // user_info.dept_code
              dept_code_status: "status", // user_info.status (dept_info.status가 조인되지 않음)
              dept_code_company_name: "dept_name", // dept_info.dept_name (company_name이 조인되지 않음)
              dept_code_name: "dept_code_name", // dept_info.dept_name
              dept_name: "dept_name", // dept_info.dept_name
              status: "status", // user_info.status
            };

            // 🎯 조인 컬럼 매핑 상태 업데이트
            setJoinColumnMapping(newJoinColumnMapping);

            console.log("🔍 조인 컬럼 매핑 테이블:", newJoinColumnMapping);
            console.log("🔍 실제 API 응답 컬럼들:", actualApiColumns);

            // 🎯 컬럼명 매핑 및 유효성 검사
            const validColumns = processedColumns
              .map((col) => {
                // 체크박스는 그대로 유지
                if (col.columnName === "__checkbox__") return col;

                // 조인 컬럼 매핑 적용
                const mappedColumnName = newJoinColumnMapping[col.columnName] || col.columnName;

                console.log(`🔍 컬럼 매핑 처리: ${col.columnName} → ${mappedColumnName}`);

                // API 응답에 존재하는지 확인
                const existsInApi = actualApiColumns.includes(mappedColumnName);

                if (!existsInApi) {
                  console.log(`🔍 제거될 컬럼: ${col.columnName} → ${mappedColumnName} (API에 존재하지 않음)`);
                  return null;
                }

                // 컬럼명이 변경된 경우 업데이트
                if (mappedColumnName !== col.columnName) {
                  console.log(`🔄 컬럼명 매핑: ${col.columnName} → ${mappedColumnName}`);
                  return {
                    ...col,
                    columnName: mappedColumnName,
                  };
                }

                console.log(`✅ 컬럼 유지: ${col.columnName}`);
                return col;
              })
              .filter((col) => col !== null) as ColumnConfig[];

            if (validColumns.length !== processedColumns.length) {
              console.log(
                "🔍 필터링된 컬럼들:",
                validColumns.map((c) => c.columnName),
              );
              console.log(
                "🔍 제거된 컬럼들:",
                processedColumns
                  .filter((col) => {
                    const mappedName = newJoinColumnMapping[col.columnName] || col.columnName;
                    return !actualApiColumns.includes(mappedName) && col.columnName !== "__checkbox__";
                  })
                  .map((c) => c.columnName),
              );
              processedColumns = validColumns;
            }
          }
        }
        if (result.entityJoinInfo?.joinConfigs) {
          result.entityJoinInfo.joinConfigs.forEach((joinConfig) => {
            // 원본 컬럼을 조인된 컬럼으로 교체
            const originalColumnIndex = processedColumns.findIndex((col) => col.columnName === joinConfig.sourceColumn);

            if (originalColumnIndex !== -1) {
              console.log(`🔄 컬럼 교체: ${joinConfig.sourceColumn} → ${joinConfig.aliasColumn}`);
              const originalColumn = processedColumns[originalColumnIndex];
              processedColumns[originalColumnIndex] = {
                ...originalColumn,
                columnName: joinConfig.aliasColumn, // dept_code → dept_code_name
                displayName:
                  columnLabels[originalColumn.columnName] || originalColumn.displayName || originalColumn.columnName, // 올바른 라벨 사용
                // isEntityJoined: true, // 🎯 임시 주석 처리 (타입 에러 해결 후 복원)
              } as ColumnConfig;
              console.log(
                `✅ 조인 컬럼 라벨 유지: ${joinConfig.sourceColumn} → "${columnLabels[originalColumn.columnName] || originalColumn.displayName || originalColumn.columnName}"`,
              );
            }
          });
        }

        // 🎯 컬럼 설정이 없으면 API 응답 기반으로 생성
        if ((!processedColumns || processedColumns.length === 0) && result.data.length > 0) {
          const autoColumns: ColumnConfig[] = Object.keys(result.data[0]).map((key, index) => ({
            columnName: key,
            displayName: columnLabels[key] || key,
            visible: true,
            sortable: true,
            searchable: true,
            align: "left",
            format: "text",
            order: index,
          }));

          console.log(
            "🎯 자동 생성된 컬럼들:",
            autoColumns.map((c) => c.columnName),
          );

          // 컴포넌트 설정 업데이트 (부모 컴포넌트에 알림)
          if (onFormDataChange) {
            onFormDataChange({
              ...component,
              config: {
                ...tableConfig,
                columns: autoColumns,
              },
            });
          }
          processedColumns = autoColumns;
        }

        // 🎯 표시할 컬럼 상태 업데이트
        setDisplayColumns(processedColumns);
        // console.log("🎯 displayColumns 업데이트됨:", processedColumns);
        // console.log("🎯 데이터 개수:", result.data?.length || 0);
        // console.log("🎯 전체 데이터:", result.data);
      }
    } catch (err) {
      console.error("테이블 데이터 로딩 오류:", err);
      setError(err instanceof Error ? err.message : "데이터를 불러오는 중 오류가 발생했습니다.");
      setData([]);
    } finally {
      setLoading(false);
    }
  };

  // 페이지 변경
  const handlePageChange = (newPage: number) => {
    setCurrentPage(newPage);

    // 상세설정에 현재 페이지 정보 알림 (필요한 경우)
    if (onConfigChange && tableConfig.pagination) {
      // console.log("📤 테이블에서 페이지 변경을 상세설정에 알림:", newPage);
      onConfigChange({
        ...tableConfig,
        pagination: {
          ...tableConfig.pagination,
          currentPage: newPage, // 현재 페이지 정보 추가
        },
      });
    } else if (!onConfigChange) {
      // console.warn("⚠️ onConfigChange가 정의되지 않음 - 페이지 변경 상세설정과 연동 불가");
    }
  };

  // 정렬 변경
  const handleSort = (column: string) => {
    if (sortColumn === column) {
      setSortDirection(sortDirection === "asc" ? "desc" : "asc");
    } else {
      setSortColumn(column);
      setSortDirection("asc");
    }
  };

  // 고급 필터 핸들러
  const handleSearchValueChange = (columnName: string, value: any) => {
    setSearchValues((prev) => ({
      ...prev,
      [columnName]: value,
    }));
  };

  const handleAdvancedSearch = () => {
    setCurrentPage(1);
    fetchTableDataDebounced();
  };

  const handleClearAdvancedFilters = () => {
    setSearchValues({});
    setCurrentPage(1);
    fetchTableDataDebounced();
  };

  // 새로고침
  const handleRefresh = () => {
    fetchTableDataDebounced();
  };

  // 체크박스 핸들러들
  const getRowKey = (row: any, index: number) => {
    // 기본키가 있으면 사용, 없으면 인덱스 사용
    return row.id || row.objid || row.pk || index.toString();
  };

  const handleRowSelection = (rowKey: string, checked: boolean) => {
    const newSelectedRows = new Set(selectedRows);
    if (checked) {
      newSelectedRows.add(rowKey);
    } else {
      newSelectedRows.delete(rowKey);
    }
    setSelectedRows(newSelectedRows);
    setIsAllSelected(newSelectedRows.size === data.length && data.length > 0);

    // 선택된 실제 데이터를 상위 컴포넌트로 전달
    const selectedKeys = Array.from(newSelectedRows);
    const selectedData = selectedKeys
      .map((key) => {
        // rowKey를 사용하여 데이터 찾기 (ID 기반 또는 인덱스 기반)
        return data.find((row, index) => {
          const currentRowKey = getRowKey(row, index);
          return currentRowKey === key;
        });
      })
      .filter(Boolean);

    console.log("🔍 handleRowSelection 디버그:", {
      rowKey,
      checked,
      selectedKeys,
      selectedData,
      dataCount: data.length,
    });

    onSelectedRowsChange?.(selectedKeys, selectedData);

    if (tableConfig.onSelectionChange) {
      tableConfig.onSelectionChange(selectedData);
    }
  };

  const handleSelectAll = (checked: boolean) => {
    if (checked) {
      const allKeys = data.map((row, index) => getRowKey(row, index));
      setSelectedRows(new Set(allKeys));
      setIsAllSelected(true);

      // 선택된 실제 데이터를 상위 컴포넌트로 전달
      onSelectedRowsChange?.(allKeys, data);

      if (tableConfig.onSelectionChange) {
        tableConfig.onSelectionChange(data);
      }
    } else {
      setSelectedRows(new Set());
      setIsAllSelected(false);

      // 빈 선택을 상위 컴포넌트로 전달
      onSelectedRowsChange?.([], []);

      if (tableConfig.onSelectionChange) {
        tableConfig.onSelectionChange([]);
      }
    }
  };

  // 효과
  useEffect(() => {
    if (tableConfig.selectedTable) {
      fetchColumnLabels();
      fetchTableLabel();
    }
  }, [tableConfig.selectedTable]);

  // 컬럼 라벨이 로드되면 기존 컬럼의 displayName을 업데이트
  useEffect(() => {
    if (Object.keys(columnLabels).length > 0 && tableConfig.columns && tableConfig.columns.length > 0) {
      const updatedColumns = tableConfig.columns.map((col) => ({
        ...col,
        displayName: columnLabels[col.columnName] || col.displayName,
      }));

      // 부모 컴포넌트에 업데이트된 컬럼 정보 전달
      if (onFormDataChange) {
        onFormDataChange({
          ...component,
          componentConfig: {
            ...tableConfig,
            columns: updatedColumns,
          },
        });
      }
    }
  }, [columnLabels]);

  useEffect(() => {
    if (tableConfig.autoLoad && !isDesignMode) {
      fetchTableDataDebounced();
    }
  }, [
    tableConfig.selectedTable,
    localPageSize,
    currentPage,
    searchTerm,
    sortColumn,
    sortDirection,
    columnLabels,
    searchValues,
  ]);

  // refreshKey 변경 시 테이블 데이터 새로고침
  useEffect(() => {
    if (refreshKey && refreshKey > 0 && !isDesignMode) {
      console.log("🔄 refreshKey 변경 감지, 테이블 데이터 새로고침:", refreshKey);
      // 선택된 행 상태 초기화
      setSelectedRows(new Set());
      setIsAllSelected(false);
      // 부모 컴포넌트에 빈 선택 상태 전달
      console.log("🔄 선택 상태 초기화 - 빈 배열 전달");
      onSelectedRowsChange?.([], []);
      // 테이블 데이터 새로고침
      fetchTableDataDebounced();
    }
  }, [refreshKey]);

  // 상세설정에서 페이지네이션 설정 변경 시 로컬 상태 동기화
  useEffect(() => {
    // 페이지 크기 동기화
    if (tableConfig.pagination?.pageSize && tableConfig.pagination.pageSize !== localPageSize) {
      // console.log("🔄 상세설정에서 페이지 크기 변경 감지:", tableConfig.pagination.pageSize);
      setLocalPageSize(tableConfig.pagination.pageSize);
      setCurrentPage(1); // 페이지를 1로 리셋
    }

    // 현재 페이지 동기화 (상세설정에서 페이지를 직접 변경한 경우)
    if (tableConfig.pagination?.currentPage && tableConfig.pagination.currentPage !== currentPage) {
      // console.log("🔄 상세설정에서 현재 페이지 변경 감지:", tableConfig.pagination.currentPage);
      setCurrentPage(tableConfig.pagination.currentPage);
    }
  }, [tableConfig.pagination?.pageSize, tableConfig.pagination?.currentPage]);

  // 표시할 컬럼 계산 (Entity 조인 적용됨 + 체크박스 컬럼 추가 + 숨김 기능)
  const visibleColumns = useMemo(() => {
    // 기본값 처리: checkbox 설정이 없으면 기본값 사용
    const checkboxConfig = tableConfig.checkbox || {
      enabled: true,
      multiple: true,
      position: "left",
      selectAll: true,
    };

    let columns: ColumnConfig[] = [];

    // displayColumns가 있으면 우선 사용 (Entity 조인 적용된 컬럼들)
    if (displayColumns && displayColumns.length > 0) {
      // 디버깅 로그 제거 (성능상 이유로)
      const filteredColumns = displayColumns.filter((col) => {
        // 디자인 모드에서는 숨김 컬럼도 표시 (연하게), 실제 화면에서는 완전히 숨김
        if (isDesignMode) {
          return col.visible; // 디자인 모드에서는 visible만 체크
        } else {
          return col.visible && !col.hidden; // 실제 화면에서는 visible이면서 hidden이 아닌 것만
        }
      });
      // 디버깅 로그 제거 (성능상 이유로)
      columns = filteredColumns.sort((a, b) => a.order - b.order);
    } else if (tableConfig.columns && tableConfig.columns.length > 0) {
      // displayColumns가 없으면 기본 컬럼 사용
      // 디버깅 로그 제거 (성능상 이유로)
      columns = tableConfig.columns
        .filter((col) => {
          // 디자인 모드에서는 숨김 컬럼도 표시 (연하게), 실제 화면에서는 완전히 숨김
          if (isDesignMode) {
            return col.visible; // 디자인 모드에서는 visible만 체크
          } else {
            return col.visible && !col.hidden; // 실제 화면에서는 visible이면서 hidden이 아닌 것만
          }
        })
        .sort((a, b) => a.order - b.order);
    } else {
      // console.log("🎯 사용할 컬럼이 없음");
      return [];
    }

    // 체크박스가 활성화되고 실제 데이터 컬럼이 있는 경우에만 체크박스 컬럼을 추가
    if (checkboxConfig.enabled && columns.length > 0) {
      const checkboxColumn: ColumnConfig = {
        columnName: "__checkbox__",
        displayName: "",
        visible: true,
        sortable: false,
        searchable: false,
        width: 50,
        align: "center",
        order: -1, // 가장 앞에 위치
        fixed: checkboxConfig.position === "left" ? "left" : false,
        fixedOrder: 0, // 가장 앞에 고정
      };

      // 체크박스 위치에 따라 추가
      if (checkboxConfig.position === "left") {
        columns.unshift(checkboxColumn);
      } else {
        columns.push(checkboxColumn);
      }
    }

    // 디버깅 로그 제거 (성능상 이유로)
    return columns;
  }, [displayColumns, tableConfig.columns, tableConfig.checkbox, isDesignMode]);

  // columnsByPosition은 SingleTableWithSticky에서 사용하지 않으므로 제거
  // 기존 테이블에서만 필요한 경우 다시 추가 가능

  // 가로 스크롤이 필요한지 계산
  const needsHorizontalScroll = useMemo(() => {
    if (!tableConfig.horizontalScroll?.enabled) {
      console.log("🚫 가로 스크롤 비활성화됨");
      return false;
    }

    const maxVisible = tableConfig.horizontalScroll.maxVisibleColumns || 8;
    const totalColumns = visibleColumns.length;
    const result = totalColumns > maxVisible;

    console.log(
      `🔍 가로 스크롤 계산: ${totalColumns}개 컬럼 > ${maxVisible}개 최대 = ${result ? "스크롤 필요" : "스크롤 불필요"}`,
    );
    console.log("📊 가로 스크롤 설정:", tableConfig.horizontalScroll);
    console.log(
      "📋 현재 컬럼들:",
      visibleColumns.map((c) => c.columnName),
    );

    return result;
  }, [visibleColumns.length, tableConfig.horizontalScroll]);

  // 컬럼 너비 계산 - 내용 길이에 맞게 자동 조정
  const getColumnWidth = (column: ColumnConfig) => {
    if (column.width) return column.width;

    // 체크박스 컬럼인 경우 고정 너비
    if (column.columnName === "__checkbox__") {
      return 50;
    }

    // 컬럼 헤더 텍스트 길이 기반으로 계산
    const headerText = columnLabels[column.columnName] || column.displayName || column.columnName;
    const headerLength = headerText.length;

    // 데이터 셀의 최대 길이 추정 (실제 데이터가 있다면 더 정확하게 계산 가능)
    const estimatedContentLength = Math.max(headerLength, 10); // 최소 10자

    // 문자당 약 8px 정도로 계산하고, 패딩 및 여백 고려
    const calculatedWidth = estimatedContentLength * 8 + 40; // 40px는 패딩과 여백

    // 최소 너비만 보장하고, 최대 너비 제한은 제거
    const minWidth = 80;

    return Math.max(minWidth, calculatedWidth);
  };

  // 체크박스 헤더 렌더링
  const renderCheckboxHeader = () => {
    // 기본값 처리: checkbox 설정이 없으면 기본값 사용
    const checkboxConfig = tableConfig.checkbox || {
      enabled: true,
      multiple: true,
      position: "left",
      selectAll: true,
    };

    if (!checkboxConfig.enabled || !checkboxConfig.selectAll) {
      return null;
    }

    return (
      <Checkbox
        checked={isAllSelected}
        onCheckedChange={handleSelectAll}
        aria-label="전체 선택"
        style={{ zIndex: 1 }}
      />
    );
  };

  // 체크박스 셀 렌더링
  const renderCheckboxCell = (row: any, index: number) => {
    // 기본값 처리: checkbox 설정이 없으면 기본값 사용
    const checkboxConfig = tableConfig.checkbox || {
      enabled: true,
      multiple: true,
      position: "left",
      selectAll: true,
    };

    if (!checkboxConfig.enabled) {
      return null;
    }

    const rowKey = getRowKey(row, index);
    const isSelected = selectedRows.has(rowKey);

    return (
      <Checkbox
        checked={isSelected}
        onCheckedChange={(checked) => handleRowSelection(rowKey, checked as boolean)}
        aria-label={`행 ${index + 1} 선택`}
        style={{ zIndex: 1 }}
      />
    );
  };

  // 🎯 값 포맷팅 (전역 코드 캐시 사용)
  const formatCellValue = useMemo(() => {
    return (value: any, format?: string, columnName?: string) => {
      if (value === null || value === undefined) return "";

      // 디버깅 로그 제거 (성능상 이유로)

      // 🎯 코드 컬럼인 경우 최적화된 코드명 변환 사용
      if (columnName && columnMeta[columnName]?.webType === "code" && columnMeta[columnName]?.codeCategory) {
        const categoryCode = columnMeta[columnName].codeCategory!;
        const convertedValue = optimizedConvertCode(categoryCode, String(value));

        // 코드 변환 로그 제거 (성능상 이유로)

        value = convertedValue;
      }

      switch (format) {
        case "number":
          return typeof value === "number" ? value.toLocaleString() : value;
        case "currency":
          return typeof value === "number" ? `₩${value.toLocaleString()}` : value;
        case "date":
          return value instanceof Date ? value.toLocaleDateString() : value;
        case "boolean":
          return value ? "예" : "아니오";
        default:
          return String(value);
      }
    };
  }, [columnMeta, optimizedConvertCode]); // 최적화된 변환 함수 의존성 추가

  // 이벤트 핸들러
  const handleClick = (e: React.MouseEvent) => {
    e.stopPropagation();
    onClick?.();
  };

  // 행 클릭 핸들러
  const handleRowClick = (row: any) => {
    if (tableConfig.onRowClick) {
      tableConfig.onRowClick(row);
    }
  };

  // 드래그 핸들러 (그리드 스냅 지원)
  const handleRowDragStart = (e: React.DragEvent, row: any, index: number) => {
    setIsDragging(true);
    setDraggedRowIndex(index);

    // 드래그 데이터에 그리드 정보 포함
    const dragData = {
      ...row,
      _dragType: "table-row",
      _gridSize: { width: 4, height: 1 }, // 기본 그리드 크기 (4칸 너비, 1칸 높이)
      _snapToGrid: true,
    };

    e.dataTransfer.setData("application/json", JSON.stringify(dragData));
    e.dataTransfer.effectAllowed = "copy"; // move 대신 copy로 변경

    // 드래그 이미지를 더 깔끔하게
    const dragElement = e.currentTarget as HTMLElement;

    // 커스텀 드래그 이미지 생성 (저장 버튼과 어울리는 스타일)
    const dragImage = document.createElement("div");
    dragImage.style.position = "absolute";
    dragImage.style.top = "-1000px";
    dragImage.style.left = "-1000px";
    dragImage.style.background = "linear-gradient(135deg, #3b82f6 0%, #1d4ed8 100%)";
    dragImage.style.color = "white";
    dragImage.style.padding = "12px 16px";
    dragImage.style.borderRadius = "8px";
    dragImage.style.fontSize = "14px";
    dragImage.style.fontWeight = "600";
    dragImage.style.boxShadow = "0 4px 12px rgba(59, 130, 246, 0.4)";
    dragImage.style.display = "flex";
    dragImage.style.alignItems = "center";
    dragImage.style.gap = "8px";
    dragImage.style.minWidth = "200px";
    dragImage.style.whiteSpace = "nowrap";

    // 아이콘과 텍스트 추가
    const firstValue = Object.values(row)[0] || "Row";
    dragImage.innerHTML = `
      <div style="
        width: 20px; 
        height: 20px; 
        background: rgba(255,255,255,0.2); 
        border-radius: 4px; 
        display: flex; 
        align-items: center; 
        justify-content: center;
        font-size: 12px;
      ">📋</div>
      <span>${firstValue}</span>
      <div style="
        background: rgba(255,255,255,0.2); 
        padding: 2px 6px; 
        border-radius: 4px; 
        font-size: 11px; 
        font-weight: 500;
      ">4×1</div>
    `;

    document.body.appendChild(dragImage);
    e.dataTransfer.setDragImage(dragImage, 20, 20);

    // 정리
    setTimeout(() => {
      if (document.body.contains(dragImage)) {
        document.body.removeChild(dragImage);
      }
    }, 0);
  };

  const handleRowDragEnd = (e: React.DragEvent) => {
    setIsDragging(false);
    setDraggedRowIndex(null);
  };

  // DOM에 전달할 수 있는 기본 props만 정의
  const domProps = {
    onClick: handleClick,
    onDragStart,
    onDragEnd,
  };

  // 디자인 모드에서의 플레이스홀더
  if (isDesignMode && !tableConfig.selectedTable) {
    return (
      <div style={componentStyle} className={className} {...domProps}>
        <div className="flex h-full items-center justify-center rounded-2xl border-2 border-dashed border-blue-200 bg-gradient-to-br from-blue-50/30 to-indigo-50/20">
          <div className="p-8 text-center">
            <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-blue-100 to-indigo-100 shadow-sm">
              <TableIcon className="h-8 w-8 text-blue-600" />
            </div>
            <div className="mb-2 text-lg font-semibold text-slate-700">테이블 리스트</div>
            <div className="rounded-full bg-white/60 px-4 py-2 text-sm text-slate-500">
              설정 패널에서 테이블을 선택해주세요
            </div>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div
      style={{ ...componentStyle, zIndex: 10 }} // 🎯 componentStyle + z-index 추가
      className={cn(
        "relative overflow-hidden",
        "bg-white border border-gray-200/60",
        "rounded-2xl shadow-sm",
        "backdrop-blur-sm",
        "transition-all duration-300 ease-out",
        isSelected && "ring-2 ring-blue-500/20 shadow-lg shadow-blue-500/10",
        className,
      )}
      {...domProps}
    >
      {/* 헤더 */}
      {tableConfig.showHeader && (
        <div
<<<<<<< HEAD
          className="flex items-center justify-between border-b border-gray-200 bg-gray-100 px-6 py-4"
=======
          className="flex items-center justify-between border-b border-gray-200/40 bg-gradient-to-r from-slate-50/80 to-gray-50/60 px-6 py-5"
>>>>>>> 8c19d57ced949bde4c9ffcce6544791d3e4b051f
          style={{
            width: "100%",
            maxWidth: "100%",
            boxSizing: "border-box",
          }}
        >
          <div className="flex items-center space-x-4">
            {(tableConfig.title || tableLabel) && (
              <h3 className="text-xl font-semibold text-gray-800 tracking-tight">{tableConfig.title || tableLabel}</h3>
            )}
          </div>

          <div className="flex items-center space-x-3">
            {/* 선택된 항목 정보 표시 */}
            {selectedRows.size > 0 && (
              <div className="flex items-center space-x-2 rounded-full bg-blue-50/80 px-4 py-2 backdrop-blur-sm">
                <span className="text-sm font-medium text-blue-700">{selectedRows.size}개 선택됨</span>
              </div>
            )}

            {/* 새로고침 */}
            <Button
              variant="outline"
              size="sm"
              onClick={handleRefresh}
              disabled={loading}
              className="group relative rounded-xl border-gray-200/60 bg-white/80 backdrop-blur-sm shadow-sm hover:shadow-md transition-all duration-200 hover:bg-gray-50/80"
            >
              <div className="flex items-center space-x-2">
                <div className="relative">
                  <RefreshCw className={cn("h-4 w-4 text-gray-600", loading && "animate-spin")} />
                  {loading && <div className="absolute -inset-1 animate-pulse rounded-full bg-blue-100/40"></div>}
                </div>
                <span className="text-sm font-medium text-gray-700">
                  {loading ? "새로고침 중..." : "새로고침"}
                </span>
              </div>
            </Button>
          </div>
        </div>
      )}

      {/* 고급 검색 필터 - 항상 표시 (컬럼 정보 기반 자동 생성) */}
      {tableConfig.filter?.enabled && visibleColumns && visibleColumns.length > 0 && (
        <>
          <div className="h-px bg-gradient-to-r from-transparent via-slate-200 to-transparent"></div>
          <div className="bg-white p-4">
            <AdvancedSearchFilters
              filters={tableConfig.filter?.filters || []} // 설정된 필터 사용, 없으면 자동 생성
              searchValues={searchValues}
              onSearchValueChange={handleSearchValueChange}
              onSearch={handleAdvancedSearch}
              onClearFilters={handleClearAdvancedFilters}
              tableColumns={visibleColumns.map((col) => ({
                columnName: col.columnName,
                widgetType: (columnMeta[col.columnName]?.webType || "text") as WebType,
                displayName: columnLabels[col.columnName] || col.displayName || col.columnName,
                codeCategory: columnMeta[col.columnName]?.codeCategory,
                isVisible: col.visible,
                // 추가 메타데이터 전달 (필터 자동 생성용)
                web_type: (columnMeta[col.columnName]?.webType || "text") as WebType,
                column_name: col.columnName,
                column_label: columnLabels[col.columnName] || col.displayName || col.columnName,
                code_category: columnMeta[col.columnName]?.codeCategory,
              }))}
              tableName={tableConfig.selectedTable}
            />
          </div>
        </>
      )}

      {/* 테이블 컨텐츠 */}
      <div
        className={`w-full overflow-auto flex-1`}
        style={{
          width: "100%",
          maxWidth: "100%",
          boxSizing: "border-box",
        }}
      >
        {loading ? (
          <div className="flex h-full items-center justify-center bg-gradient-to-br from-slate-50/50 to-blue-50/30">
            <div className="p-8 text-center">
              <div className="relative">
                <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-blue-100 to-indigo-100">
                  <RefreshCw className="h-8 w-8 animate-spin text-blue-600" />
                </div>
                <div className="absolute -top-1 -right-1 h-4 w-4 animate-pulse rounded-full bg-gradient-to-br from-blue-400 to-indigo-500"></div>
              </div>
              <div className="text-sm font-medium text-slate-700">데이터를 불러오는 중...</div>
              <div className="mt-1 text-xs text-slate-500">잠시만 기다려주세요</div>
            </div>
          </div>
        ) : error ? (
          <div className="flex h-full items-center justify-center bg-gradient-to-br from-red-50/50 to-orange-50/30">
            <div className="p-8 text-center">
              <div className="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-2xl bg-gradient-to-br from-red-100 to-orange-100">
                <div className="flex h-8 w-8 items-center justify-center rounded-full bg-gradient-to-br from-red-500 to-orange-500">
                  <span className="text-sm font-bold text-white">!</span>
                </div>
              </div>
              <div className="text-sm font-medium text-red-700">오류가 발생했습니다</div>
              <div className="mt-1 rounded-full bg-red-50 px-3 py-1 text-xs text-red-500">{error}</div>
            </div>
          </div>
        ) : tableConfig.displayMode === "card" ? (
          // 카드 모드 렌더링
          <div className="h-full w-full overflow-y-auto">
            <CardModeRenderer
              data={data}
              cardConfig={
                tableConfig.cardConfig || {
                  idColumn: "id",
                  titleColumn: "name",
                  cardsPerRow: 3,
                  cardSpacing: 16,
                  showActions: true,
                }
              }
              visibleColumns={visibleColumns}
              onRowClick={handleRowClick}
              onRowSelect={(row, selected) => {
                const rowIndex = data.findIndex((d) => d === row);
                const rowKey = getRowKey(row, rowIndex);
                handleRowSelection(rowKey, selected);
              }}
              selectedRows={Array.from(selectedRows)}
              showActions={tableConfig.actions?.showActions}
            />
          </div>
        ) : needsHorizontalScroll ? (
          // 가로 스크롤이 필요한 경우 - 단일 테이블에서 sticky 컬럼 사용
          <div className="w-full overflow-hidden">
            <SingleTableWithSticky
              visibleColumns={visibleColumns}
              data={data}
              columnLabels={columnLabels}
              sortColumn={sortColumn}
              sortDirection={sortDirection}
              tableConfig={tableConfig}
              isDesignMode={isDesignMode}
              isAllSelected={isAllSelected}
              handleSort={handleSort}
              handleSelectAll={handleSelectAll}
              handleRowClick={handleRowClick}
              renderCheckboxCell={renderCheckboxCell}
              formatCellValue={formatCellValue}
              getColumnWidth={getColumnWidth}
              containerWidth={calculatedWidth}
            />
          </div>
        ) : (
          // 기존 테이블 (가로 스크롤이 필요한 경우)
          <div className="w-full overflow-x-auto overflow-y-auto">
            <Table
              className="w-full"
              style={{
                width: "100%",
                minWidth: "100%",
                tableLayout: "auto", // 테이블 크기 자동 조정
              }}
            >
              <TableHeader
                className={cn(
                  tableConfig.stickyHeader ? "sticky top-0 z-20" : "",
                  "border-b border-gray-200/40 bg-gradient-to-r from-slate-50/90 to-gray-50/70 backdrop-blur-sm",
                )}
              >
                <TableRow
                  style={{
                    minHeight: "48px !important",
                    height: "48px !important",
                    lineHeight: "1",
                    width: "100%",
                    maxWidth: "100%",
                  }}
                  className="border-none"
                >
                  {visibleColumns.map((column, colIndex) => (
                    <TableHead
                      key={column.columnName}
                      style={{
                        width: column.width ? `${column.width}px` : "150px", // 기본 너비 설정
                        minWidth: "100px", // 최소 너비 보장
                        maxWidth: "300px", // 최대 너비 제한
                        minHeight: "48px !important",
                        height: "48px !important",
                        verticalAlign: "middle",
                        lineHeight: "1",
                        boxSizing: "border-box",
                        overflow: "hidden",
                        textOverflow: "ellipsis",
                        whiteSpace: "nowrap", // 텍스트 줄바꿈 방지
                      }}
                      className={cn(
                        "h-12 px-6 py-4 align-middle text-sm font-semibold text-gray-700",
                        "transition-colors duration-200 ease-out",
                        column.columnName === "__checkbox__"
                          ? "text-center"
                          : "cursor-pointer whitespace-nowrap select-none hover:text-gray-900",
                        `text-${column.align}`,
                        column.sortable && "hover:bg-orange-200/70",
                      )}
                      onClick={() => column.sortable && handleSort(column.columnName)}
                    >
                      {column.columnName === "__checkbox__" ? (
                        renderCheckboxHeader()
                      ) : (
                        <div className="flex items-center space-x-2">
                          <span>{columnLabels[column.columnName] || column.displayName}</span>
                          {column.sortable && sortColumn === column.columnName && (
                            <div className="flex flex-col">
                              {sortDirection === "asc" ? (
                                <ArrowUp className="h-3 w-3 text-blue-600" />
                              ) : (
                                <ArrowDown className="h-3 w-3 text-blue-600" />
                              )}
                            </div>
                          )}
                        </div>
                      )}
                    </TableHead>
                  ))}
                </TableRow>
              </TableHeader>
              <TableBody>
                {data.length === 0 ? (
                  <TableRow>
                    <TableCell colSpan={visibleColumns.length} className="py-12 text-center">
                      <div className="flex flex-col items-center space-y-3">
                        <div className="flex h-12 w-12 items-center justify-center rounded-2xl bg-gradient-to-br from-slate-100 to-slate-200">
                          <TableIcon className="h-6 w-6 text-slate-400" />
                        </div>
                        <div className="text-sm font-medium text-slate-600">데이터가 없습니다</div>
                        <div className="text-xs text-slate-400">조건을 변경하거나 새로운 데이터를 추가해보세요</div>
                      </div>
                    </TableCell>
                  </TableRow>
                ) : (
                  data.map((row, index) => (
                    <TableRow
                      key={index}
                      draggable={!isDesignMode}
                      onDragStart={(e) => handleRowDragStart(e, row, index)}
                      onDragEnd={handleRowDragEnd}
                      className={cn(
                        "group relative h-12 cursor-pointer border-b border-gray-100/60 transition-all duration-200",
                        // 기본 스타일
                        tableConfig.tableStyle?.hoverEffect &&
                          "hover:bg-gradient-to-r hover:from-orange-50/80 hover:to-orange-100/60 hover:shadow-sm",
                        tableConfig.tableStyle?.alternateRows && index % 2 === 1 && "bg-gray-50/40",
                        // 드래그 상태 스타일 (미묘하게)
                        draggedRowIndex === index &&
                          "border-blue-200/60 bg-gradient-to-r from-blue-50/60 to-indigo-50/40 shadow-sm",
                        isDragging && draggedRowIndex !== index && "opacity-70",
                        // 드래그 가능 표시
                        !isDesignMode && "hover:cursor-grab active:cursor-grabbing",
                      )}
                      style={{
                        minHeight: "48px",
                        height: "48px",
                        lineHeight: "1",
                        width: "100%",
                        maxWidth: "100%",
                      }}
                      onClick={() => handleRowClick(row)}
                    >
                      {visibleColumns.map((column, colIndex) => (
                        <TableCell
                          key={column.columnName}
                          className={cn(
                            "h-12 px-6 py-4 align-middle text-sm transition-all duration-200 text-gray-600",
                            `text-${column.align}`,
                          )}
                          style={{
                            minHeight: "48px",
                            height: "48px",
                            verticalAlign: "middle",
                            width: column.width ? `${column.width}px` : "150px", // 기본 너비 설정
                            minWidth: "100px", // 최소 너비 보장
                            maxWidth: "300px", // 최대 너비 제한
                            boxSizing: "border-box",
                            overflow: "hidden",
                            textOverflow: "ellipsis",
                            whiteSpace: "nowrap",
                          }}
                        >
                          {column.columnName === "__checkbox__"
                            ? renderCheckboxCell(row, index)
                            : (() => {
                                // 🎯 매핑된 컬럼명으로 데이터 찾기
                                const mappedColumnName = joinColumnMapping[column.columnName] || column.columnName;
                                const cellValue = row[mappedColumnName];
                                if (index === 0) {
                                  // 디버깅 로그 제거 (성능상 이유로)
                                }
                                const formattedValue =
                                  formatCellValue(cellValue, column.format, column.columnName) || "\u00A0";

                                // 첫 번째 컬럼에 드래그 핸들과 아바타 추가
                                const isFirstColumn =
                                  colIndex === (visibleColumns[0]?.columnName === "__checkbox__" ? 1 : 0);

                                return (
                                  <div className="flex items-center space-x-2">
                                    {isFirstColumn && !isDesignMode && (
                                      <div className="mr-1 cursor-grab opacity-60 active:cursor-grabbing">
                                        {/* 그리드 스냅 가이드 아이콘 */}
                                        <div className="flex space-x-0.5">
                                          <div className="flex flex-col space-y-0.5">
                                            <div className="h-0.5 w-0.5 rounded-full bg-gray-400"></div>
                                            <div className="h-0.5 w-0.5 rounded-full bg-gray-400"></div>
                                          </div>
                                          <div className="flex flex-col space-y-0.5">
                                            <div className="h-0.5 w-0.5 rounded-full bg-gray-400"></div>
                                            <div className="h-0.5 w-0.5 rounded-full bg-gray-400"></div>
                                          </div>
                                        </div>
                                      </div>
                                    )}
                                    <span className="font-medium text-gray-700">{formattedValue}</span>
                                  </div>
                                );
                              })()}
                        </TableCell>
                      ))}
                    </TableRow>
                  ))
                )}
              </TableBody>
            </Table>
          </div>
        )}
      </div>

      {/* 푸터/페이지네이션 */}
      {tableConfig.showFooter && tableConfig.pagination?.enabled && (
        <div
          className="flex flex-col items-center justify-center space-y-4 border-t border-gray-200 bg-gray-100/80 p-6"
          style={{
            width: "100%",
            maxWidth: "100%",
            boxSizing: "border-box",
          }}
        >
          {/* 페이지 정보 - 가운데 정렬 */}
          {tableConfig.pagination?.showPageInfo && (
            <div className="flex items-center justify-center space-x-2 text-sm text-slate-600">
              <div className="h-2 w-2 rounded-full bg-blue-500"></div>
              <span className="font-medium">
                전체 <span className="font-semibold text-blue-600">{totalItems.toLocaleString()}</span>건 중{" "}
                <span className="font-semibold text-slate-800">
                  {(currentPage - 1) * localPageSize + 1}-{Math.min(currentPage * localPageSize, totalItems)}
                </span>{" "}
                표시
              </span>
            </div>
          )}

          {/* 페이지 크기 선택과 페이지네이션 버튼 - 가운데 정렬 */}
          <div className="flex items-center justify-center space-x-4">
            {/* 페이지 크기 선택 - 임시로 항상 표시 (테스트용) */}
            {true && (
              <select
                value={localPageSize}
                onChange={(e) => {
                  // console.log("🚀 페이지 크기 드롭다운 변경 감지:", e.target.value);
                  const newPageSize = parseInt(e.target.value);

                  // console.log("🎯 페이지 크기 변경 이벤트:", {
                  //   from: localPageSize,
                  //   to: newPageSize,
                  //   hasOnConfigChange: !!onConfigChange,
                  //   onConfigChangeType: typeof onConfigChange
                  // });

                  // 로컬 상태 업데이트
                  setLocalPageSize(newPageSize);

                  // 페이지를 1로 리셋
                  setCurrentPage(1);

                  // 상세설정에 변경사항 알림 (pagination 설정 업데이트)
                  if (onConfigChange) {
                    // console.log("📤 테이블에서 페이지 크기 변경을 상세설정에 알림:", newPageSize);
                    onConfigChange({
                      ...tableConfig,
                      pagination: {
                        ...tableConfig.pagination,
                        pageSize: newPageSize,
                      },
                    });
                  } else {
                    // console.warn("⚠️ onConfigChange가 정의되지 않음 - 상세설정과 연동 불가");
                  }

                  // 데이터는 useEffect에서 자동으로 다시 로드됨
                }}
                className="rounded-xl border border-gray-200/60 bg-white/80 backdrop-blur-sm px-4 py-2 text-sm font-medium text-gray-700 shadow-sm transition-all duration-200 hover:border-gray-300/60 hover:bg-white hover:shadow-md"
              >
                {(tableConfig.pagination?.pageSizeOptions || [10, 20, 50, 100]).map((size) => (
                  <option key={size} value={size}>
                    {size}개씩
                  </option>
                ))}
              </select>
            )}

            {/* 페이지네이션 버튼 */}
            <div className="flex items-center space-x-2 rounded-xl border border-gray-200/60 bg-white/80 backdrop-blur-sm p-1 shadow-sm">
              <Button
                variant="outline"
                size="sm"
                onClick={() => handlePageChange(1)}
                disabled={currentPage === 1}
                className="h-8 w-8 p-0 rounded-lg border-gray-200/60 hover:border-gray-300/60 hover:bg-gray-50/80 hover:text-gray-700 disabled:opacity-50 transition-all duration-200"
              >
                <ChevronsLeft className="h-4 w-4" />
              </Button>
              <Button
                variant="outline"
                size="sm"
                onClick={() => handlePageChange(currentPage - 1)}
                disabled={currentPage === 1}
                className="h-8 w-8 p-0 rounded-lg border-gray-200/60 hover:border-gray-300/60 hover:bg-gray-50/80 hover:text-gray-700 disabled:opacity-50 transition-all duration-200"
              >
                <ChevronLeft className="h-4 w-4" />
              </Button>

              <div className="flex items-center rounded-lg border border-gray-200/40 bg-gradient-to-r from-gray-50/80 to-slate-50/60 px-4 py-2 backdrop-blur-sm">
                <span className="text-sm font-semibold text-gray-800">{currentPage}</span>
                <span className="mx-2 font-light text-gray-400">/</span>
                <span className="text-sm font-medium text-gray-600">{totalPages}</span>
              </div>

              <Button
                variant="outline"
                size="sm"
                onClick={() => handlePageChange(currentPage + 1)}
                disabled={currentPage === totalPages}
                className="h-8 w-8 p-0 rounded-lg border-gray-200/60 hover:border-gray-300/60 hover:bg-gray-50/80 hover:text-gray-700 disabled:opacity-50 transition-all duration-200"
              >
                <ChevronRight className="h-4 w-4" />
              </Button>
              <Button
                variant="outline"
                size="sm"
                onClick={() => handlePageChange(totalPages)}
                disabled={currentPage === totalPages}
                className="h-8 w-8 p-0 rounded-lg border-gray-200/60 hover:border-gray-300/60 hover:bg-gray-50/80 hover:text-gray-700 disabled:opacity-50 transition-all duration-200"
              >
                <ChevronsRight className="h-4 w-4" />
              </Button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
};

/**
 * TableList 래퍼 컴포넌트
 * 추가적인 로직이나 상태 관리가 필요한 경우 사용
 */
export const TableListWrapper: React.FC<TableListComponentProps> = (props) => {
  return <TableListComponent {...props} />;
};
