"use client";

/**
 * DataGrid — 하드코딩 페이지용 공통 데이터 테이블 컴포넌트
 *
 * 기능:
 * - 드래그로 컬럼 순서 변경 (@dnd-kit)
 * - 컬럼 헤더 클릭 정렬 (asc/desc)
 * - 컬럼 헤더 필터: 필터 아이콘 → Popover → 고유값 체크박스 다중 선택
 * - 셀 더블클릭 인라인 편집 (text/number/date/select)
 * - 천단위 구분자 (number 타입)
 * - 셀 값 truncate + tooltip
 */

import React, { useState, useEffect, useRef, useCallback, useMemo } from "react";
import {
  DndContext, closestCenter, PointerSensor, useSensor, useSensors, DragEndEvent,
} from "@dnd-kit/core";
import { SortableContext, horizontalListSortingStrategy, useSortable, arrayMove } from "@dnd-kit/sortable";
import { CSS } from "@dnd-kit/utilities";
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from "@/components/ui/table";
import { Checkbox } from "@/components/ui/checkbox";
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover";
import { Input } from "@/components/ui/input";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { Filter, Check, Search, ImageIcon, X, ChevronLeft, ChevronRight, ChevronsLeft, ChevronsRight, Folder, Paperclip, Settings, GripVertical, RotateCw, Download as DownloadIcon, BarChart3 } from "lucide-react";
import { DataGridChartPanel } from "./DataGridChartPanel";
import { cn } from "@/lib/utils";
import { toast } from "sonner";
import { apiClient } from "@/lib/api/client";

// --- 타입 ---

export interface DataGridColumn {
  key: string;
  label: string;
  width?: string;
  minWidth?: string;
  editable?: boolean;
  inputType?: "text" | "number" | "date" | "select";
  sortable?: boolean;
  filterable?: boolean;
  truncate?: boolean;
  align?: "left" | "center" | "right";
  formatNumber?: boolean;
  /** 금액 포맷: 천단위 콤마 + 소수점 2자리 고정 */
  formatMoney?: boolean;
  /** 이미지 타입 — 값을 /api/files/preview/{objid} 이미지로 렌더링 */
  renderType?: "image" | "folder" | "clip";
  selectOptions?: { value: string; label: string }[];
  /** 셀 클릭 핸들러 — folder/clip 등 인터랙션 컬럼에서 모달 오픈용. 행 클릭으로 전파되지 않음 */
  onClick?: (row: any) => void;
  /** 좌측 고정 컬럼 (가로 스크롤 시 sticky-left). 첫 컬럼에만 사용 권장 */
  frozen?: boolean;
}

export interface DataGridProps {
  columns: DataGridColumn[];
  data: any[];
  onRowClick?: (row: any, index: number) => void;
  onRowDoubleClick?: (row: any, index: number) => void;
  selectedId?: string | null;
  onSelect?: (id: string | null) => void;
  onCellEdit?: (rowId: string, columnKey: string, newValue: any, row: any) => void;
  tableName?: string;
  showRowNumber?: boolean;
  /** 체크박스 다중선택 모드 */
  showCheckbox?: boolean;
  /** 체크된 행 ID 배열 */
  checkedIds?: string[];
  /** 체크 변경 콜백 */
  onCheckedChange?: (ids: string[]) => void;
  emptyMessage?: string;
  loading?: boolean;
  onColumnOrderChange?: (columns: DataGridColumn[]) => void;
  gridId?: string;
  /** 페이지네이션 표시 여부 (기본: true) */
  showPagination?: boolean;
  /** 초기 페이지 크기 (기본: 50) */
  defaultPageSize?: number;
  /** 페이지네이션 라벨 포맷 — 'classic'(기본): "전체 N건", 'range': "1-N / 총 X건" */
  paginationStyle?: "classic" | "range";
  /** 페이지 크기 드롭다운 옵션. 지정 시 Input 대신 Select 렌더. 예: [10,15,20,50,100] */
  pageSizeOptions?: number[];
  /** 컬럼 표시/숨김 설정 드롭다운 활성화 (gear 아이콘) */
  showColumnSettings?: boolean;
  /** 시스템 컬럼으로 분리 표시할 key 배열. 표시 메뉴에서 '시스템 컬럼' 그룹으로 묶임 */
  systemColumnKeys?: string[];
  /** 하단 통계 행 — 평균/합계 등. footer에 좌측 배치 */
  summaryStats?: Array<{ label: string; value: string | number; suffix?: string }>;
  /** 재조회 콜백. 지정 시 그리드 상단 toolbar에 ⟳ 아이콘 표시 */
  onRefresh?: () => void;
  /** 다운로드 콜백 (Excel/CSV 등). 지정 시 그리드 상단 toolbar에 ⬇ 아이콘 표시 */
  onDownload?: () => void;
  /** 차트 분석 패널 활성화. 지정 시 toolbar에 📊 토글 + 그리드 하단에 패널 노출 */
  showChart?: boolean;
  /** 서버 페이지네이션 모드. true면 page/pageSize/totalItems 를 props로 받고 변경 시 콜백 호출 */
  serverPaging?: boolean;
  /** 서버 페이지네이션 현재 페이지 (1-based, serverPaging=true일 때) */
  serverPage?: number;
  /** 서버 페이지네이션 페이지 크기 (serverPaging=true일 때) */
  serverPageSize?: number;
  /** 서버 페이지네이션 총 건수 (serverPaging=true일 때) */
  serverTotalItems?: number;
  /** 페이지 변경 콜백 — 서버 페이지네이션 시 API 재호출용 */
  onPageChange?: (page: number) => void;
  /** 페이지 크기 변경 콜백 — 서버 페이지네이션 시 API 재호출용 */
  onPageSizeChange?: (pageSize: number) => void;
}

const fmtNum = (val: any) => {
  if (val == null || val === "") return "";
  const n = Number(String(val).replace(/,/g, ""));
  if (isNaN(n)) return String(val);
  // 정수: 천단위 콤마만 (수량 등)
  return n.toLocaleString();
};

const fmtMoney = (val: any) => {
  if (val == null || val === "") return "";
  const n = Number(String(val).replace(/,/g, ""));
  if (isNaN(n)) return String(val);
  // 금액: 천단위 콤마 + 소수점 2자리 고정
  return n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
};

// --- Sortable Header Cell ---
function SortableHeaderCell({
  col, sortKey, sortDir, onSort,
  headerFilterValues, uniqueValues, onToggleFilter, onClearFilter,
  frozenLeftClass = "left-0",
  frozenLeftPx,
  widthPx, onResizeStart,
}: {
  col: DataGridColumn;
  sortKey: string | null;
  sortDir: "asc" | "desc";
  onSort: (key: string) => void;
  headerFilterValues: Set<string>;
  uniqueValues: string[];
  onToggleFilter: (colKey: string, value: string) => void;
  onClearFilter: (colKey: string) => void;
  frozenLeftClass?: string;
  /** 다중 frozen 누적 left 픽셀 (지정 시 frozenLeftClass 무시) */
  frozenLeftPx?: number;
  /** 사용자 리사이즈로 결정된 현재 너비(px). 없으면 col.width Tailwind 클래스 사용 */
  widthPx?: number;
  /** 리사이즈 핸들 mousedown 핸들러 */
  onResizeStart?: (e: React.MouseEvent, colKey: string, currentWidthPx: number) => void;
}) {
  const [filterSearch, setFilterSearch] = useState("");
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({ id: col.key });

  // frozen 컬럼은 CSS sticky 가 작동하도록 dnd-kit transform/transition 모두 제외
  // (transform 이 적용되면 sticky 의 containing block 이 변경돼 sticky 가 깨짐)
  const style: React.CSSProperties = col.frozen
    ? {}
    : {
        transform: CSS.Transform.toString(transform),
        transition,
        opacity: isDragging ? 0.5 : 1,
        cursor: "grab",
      };
  if (widthPx != null) {
    style.width = widthPx;
    style.minWidth = widthPx;
    style.maxWidth = widthPx;
  }
  if (col.frozen && frozenLeftPx != null) {
    style.left = frozenLeftPx;
  }

  const isSorted = sortKey === col.key;
  const hasFilter = headerFilterValues.size > 0;
  const effectiveWidthPx = widthPx ?? parseWidthClass(col.width) ?? 100;

  return (
    <TableHead
      ref={setNodeRef}
      style={style}
      className={cn(
        widthPx == null && col.width, widthPx == null && col.minWidth,
        "select-none relative group/th !px-1.5",
        col.frozen && cn("sticky z-20 bg-background", frozenLeftPx == null && frozenLeftClass),
      )}
    >
      <div className="inline-flex items-center gap-0.5 w-full">
        <GripVertical
          {...attributes}
          {...listeners}
          className="h-3 w-3 text-muted-foreground/50 shrink-0 cursor-grab active:cursor-grabbing"
          aria-label="컬럼 드래그"
        />
        <div
          className="flex items-center gap-0.5 cursor-pointer min-w-0 flex-1 overflow-hidden"
          onClick={(e) => {
            e.stopPropagation();
            if (col.sortable !== false) onSort(col.key);
          }}
        >
          <span className="text-xs font-medium truncate min-w-0" title={col.label}>{col.label}</span>
          {isSorted && (
            <span className="text-primary text-xs shrink-0">{sortDir === "asc" ? "↑" : "↓"}</span>
          )}
        </div>

        {/* 컬럼 필터 아이콘 → Popover */}
        {col.filterable !== false && uniqueValues.length > 0 && (
          <Popover>
            <PopoverTrigger asChild>
              <button
                onClick={(e) => e.stopPropagation()}
                className={cn(
                  "hover:bg-primary/20 rounded p-0.5 transition-colors shrink-0",
                  hasFilter && "text-primary bg-primary/10",
                )}
                title="필터"
              >
                <Filter className="h-3 w-3" />
              </button>
            </PopoverTrigger>
            <PopoverContent className="w-52 p-2" align="start" onClick={(e) => e.stopPropagation()}>
              <div className="space-y-2">
                <div className="flex items-center justify-between border-b pb-2">
                  <span className="text-xs font-medium">필터: {col.label}</span>
                  {hasFilter && (
                    <button onClick={() => onClearFilter(col.key)} className="text-destructive text-xs hover:underline">
                      초기화
                    </button>
                  )}
                </div>
                {/* 검색 */}
                <div className="relative">
                  <Search className="absolute left-2 top-1/2 -translate-y-1/2 h-3 w-3 text-muted-foreground" />
                  <Input
                    value={filterSearch}
                    onChange={(e) => setFilterSearch(e.target.value)}
                    placeholder="검색..."
                    className="h-7 text-xs pl-7"
                  />
                </div>
                <div className="max-h-48 space-y-1 overflow-y-auto">
                  {uniqueValues
                    .filter((v) => !filterSearch || v.toLowerCase().includes(filterSearch.toLowerCase()))
                    .slice(0, 50).map((val) => {
                    const isSelected = headerFilterValues.has(val);
                    return (
                      <div
                        key={val}
                        className={cn(
                          "hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-1 text-xs",
                          isSelected && "bg-primary/10",
                        )}
                        onClick={() => onToggleFilter(col.key, val)}
                      >
                        <div className={cn(
                          "flex h-4 w-4 items-center justify-center rounded border shrink-0",
                          isSelected ? "bg-primary border-primary" : "border-input",
                        )}>
                          {isSelected && <Check className="text-primary-foreground h-3 w-3" />}
                        </div>
                        <span className="truncate">{val || "(빈 값)"}</span>
                      </div>
                    );
                  })}
                  {uniqueValues.filter((v) => !filterSearch || v.toLowerCase().includes(filterSearch.toLowerCase())).length > 50 && (
                    <div className="text-muted-foreground px-2 py-1 text-xs">
                      ...외 {uniqueValues.filter((v) => !filterSearch || v.toLowerCase().includes(filterSearch.toLowerCase())).length - 50}개
                    </div>
                  )}
                </div>
              </div>
            </PopoverContent>
          </Popover>
        )}
      </div>

      {/* 리사이저 핸들 — 우측 가장자리 6px 영역에서 드래그하여 컬럼 너비 조정 */}
      {onResizeStart && (
        <div
          onMouseDown={(e) => onResizeStart(e, col.key, effectiveWidthPx)}
          onClick={(e) => e.stopPropagation()}
          className="absolute right-0 top-0 h-full w-1.5 cursor-col-resize hover:bg-primary/40 active:bg-primary/60 transition-colors z-10"
          aria-label="컬럼 너비 조정"
          title="드래그하여 컬럼 너비 조정"
        />
      )}
    </TableHead>
  );
}

// w-[XXXpx] Tailwind 클래스에서 px 정수 추출. 없으면 undefined.
function parseWidthClass(cls?: string): number | undefined {
  if (!cls) return undefined;
  const m = cls.match(/w-\[(\d+)px\]/);
  return m ? Number(m[1]) : undefined;
}

// --- DataGrid ---

export function DataGrid({
  columns: initialColumns,
  data,
  onRowClick,
  onRowDoubleClick,
  selectedId,
  onSelect,
  onCellEdit,
  tableName,
  showRowNumber = true,
  showCheckbox = false,
  checkedIds = [],
  onCheckedChange,
  emptyMessage = "데이터가 없습니다",
  loading = false,
  onColumnOrderChange,
  gridId,
  showPagination = true,
  defaultPageSize = 50,
  paginationStyle = "classic",
  pageSizeOptions,
  showColumnSettings = false,
  systemColumnKeys,
  summaryStats,
  onRefresh,
  onDownload,
  showChart = false,
  serverPaging = false,
  serverPage,
  serverPageSize,
  serverTotalItems,
  onPageChange,
  onPageSizeChange,
}: DataGridProps) {
  const [columns, setColumns] = useState(initialColumns);
  useEffect(() => { setColumns(initialColumns); }, [initialColumns]);

  // 차트 패널 열림 상태 (gridId 있으면 localStorage 영속)
  const [chartPanelOpen, setChartPanelOpen] = useState(false);
  useEffect(() => {
    if (!gridId) return;
    const saved = localStorage.getItem(`datagrid_chart_open_${gridId}`);
    if (saved === "1") setChartPanelOpen(true);
  }, [gridId]);
  const toggleChartPanel = useCallback(() => {
    setChartPanelOpen((prev) => {
      const next = !prev;
      if (gridId) {
        try { localStorage.setItem(`datagrid_chart_open_${gridId}`, next ? "1" : "0"); } catch { /* skip */ }
      }
      return next;
    });
  }, [gridId]);

  // 컬럼 visibility — 숨겨진 컬럼 key Set. localStorage 영속(gridId 있을 때).
  const [hiddenColumns, setHiddenColumns] = useState<Set<string>>(new Set());
  useEffect(() => {
    if (!gridId) return;
    const saved = localStorage.getItem(`datagrid_col_hidden_${gridId}`);
    if (saved) {
      try { setHiddenColumns(new Set(JSON.parse(saved) as string[])); } catch { /* skip */ }
    }
  }, [gridId]);
  const toggleColumnVisibility = useCallback((key: string) => {
    setHiddenColumns((prev) => {
      const next = new Set(prev);
      if (next.has(key)) next.delete(key); else next.add(key);
      if (gridId) {
        try { localStorage.setItem(`datagrid_col_hidden_${gridId}`, JSON.stringify(Array.from(next))); } catch { /* skip */ }
      }
      return next;
    });
  }, [gridId]);
  const resetVisibility = useCallback(() => {
    setHiddenColumns(new Set());
    if (gridId) try { localStorage.removeItem(`datagrid_col_hidden_${gridId}`); } catch { /* skip */ }
  }, [gridId]);
  const resetOrder = useCallback(() => {
    setColumns(initialColumns);
    if (gridId) try { localStorage.removeItem(`datagrid_col_order_${gridId}`); } catch { /* skip */ }
  }, [gridId, initialColumns]);
  // resetWidthsAll은 setColumnWidths 선언 이후에 정의 (아래에서)

  // 정렬
  const [sortKey, setSortKey] = useState<string | null>(null);
  const [sortDir, setSortDir] = useState<"asc" | "desc">("asc");

  // 헤더 필터 (컬럼별 선택된 값 Set)
  const [headerFilters, setHeaderFilters] = useState<Record<string, Set<string>>>({});

  // 페이지네이션 — 서버 모드면 props 사용, 아니면 로컬 state
  const [localCurrentPage, setLocalCurrentPage] = useState(1);
  const [localPageSize, setLocalPageSize] = useState(defaultPageSize);
  const [pageSizeInput, setPageSizeInput] = useState(String(defaultPageSize));
  const currentPage = serverPaging ? (serverPage ?? 1) : localCurrentPage;
  const pageSize = serverPaging ? (serverPageSize ?? defaultPageSize) : localPageSize;
  const setCurrentPage = useCallback((p: number | ((prev: number) => number)) => {
    const next = typeof p === "function" ? (p as (n: number) => number)(currentPage) : p;
    if (serverPaging) { onPageChange?.(next); } else { setLocalCurrentPage(next); }
  }, [serverPaging, currentPage, onPageChange]);
  const setPageSize = useCallback((n: number) => {
    if (serverPaging) { onPageSizeChange?.(n); } else { setLocalPageSize(n); }
  }, [serverPaging, onPageSizeChange]);
  useEffect(() => {
    if (serverPaging && serverPageSize) setPageSizeInput(String(serverPageSize));
  }, [serverPaging, serverPageSize]);

  // 인라인 편집
  const [editingCell, setEditingCell] = useState<{ rowIdx: number; colKey: string } | null>(null);
  // 이미지 확대 모달
  const [previewImage, setPreviewImage] = useState<string | null>(null);
  const [editValue, setEditValue] = useState("");
  const editRef = useRef<HTMLInputElement>(null);

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 8 } })
  );

  // localStorage에서 컬럼 순서 복원
  useEffect(() => {
    if (!gridId) return;
    const saved = localStorage.getItem(`datagrid_col_order_${gridId}`);
    if (saved) {
      try {
        const order = JSON.parse(saved) as string[];
        const reordered = order
          .map((key) => initialColumns.find((c) => c.key === key))
          .filter(Boolean) as DataGridColumn[];
        const remaining = initialColumns.filter((c) => !order.includes(c.key));
        setColumns([...reordered, ...remaining]);
      } catch { /* skip */ }
    }
  }, [gridId]); // eslint-disable-line react-hooks/exhaustive-deps

  // 컬럼별 너비(px) — 사용자가 핸들로 드래그하면 갱신. localStorage에 영구 저장(gridId 있을 때).
  const [columnWidths, setColumnWidths] = useState<Record<string, number>>({});
  useEffect(() => {
    if (!gridId) return;
    const saved = localStorage.getItem(`datagrid_col_widths_${gridId}`);
    if (saved) {
      try { setColumnWidths(JSON.parse(saved)); } catch { /* skip */ }
    }
  }, [gridId]);
  const persistColumnWidths = useCallback((next: Record<string, number>) => {
    setColumnWidths(next);
    if (gridId) {
      try { localStorage.setItem(`datagrid_col_widths_${gridId}`, JSON.stringify(next)); } catch { /* skip */ }
    }
  }, [gridId]);
  const resetWidthsAll = useCallback(() => {
    setColumnWidths({});
    if (gridId) try { localStorage.removeItem(`datagrid_col_widths_${gridId}`); } catch { /* skip */ }
  }, [gridId]);

  // 가시 컬럼 — hiddenColumns 적용. 헤더/바디 렌더에 사용. DnD/순서 영속은 전체 columns 기준 유지.
  const visibleColumns = useMemo(
    () => columns.filter((c) => !hiddenColumns.has(c.key)),
    [columns, hiddenColumns],
  );

  // 리사이즈 드래그 핸들러 — 헤더 우측 핸들에서 mousedown 발생 시 호출.
  const startResize = useCallback((e: React.MouseEvent, colKey: string, currentWidthPx: number) => {
    e.preventDefault();
    e.stopPropagation();
    const startX = e.clientX;
    const startWidth = currentWidthPx;
    const onMove = (ev: MouseEvent) => {
      const delta = ev.clientX - startX;
      const next = Math.max(40, Math.round(startWidth + delta));
      setColumnWidths((prev) => ({ ...prev, [colKey]: next }));
    };
    const onUp = () => {
      document.removeEventListener("mousemove", onMove);
      document.removeEventListener("mouseup", onUp);
      document.body.style.cursor = "";
      document.body.style.userSelect = "";
      // 최종 값으로 영구 저장 (state 최신값 직접 읽기 위해 setter 형태로)
      setColumnWidths((latest) => {
        if (gridId) {
          try { localStorage.setItem(`datagrid_col_widths_${gridId}`, JSON.stringify(latest)); } catch { /* skip */ }
        }
        return latest;
      });
    };
    document.addEventListener("mousemove", onMove);
    document.addEventListener("mouseup", onUp);
    document.body.style.cursor = "col-resize";
    document.body.style.userSelect = "none";
  }, [gridId]);

  // 컬럼별 고유값 계산 (필터 팝오버용)
  const columnUniqueValues = useMemo(() => {
    const result: Record<string, string[]> = {};
    for (const col of columns) {
      const values = new Set<string>();
      data.forEach((row) => {
        const val = row[col.key];
        if (val !== null && val !== undefined && val !== "") {
          values.add(String(val));
        }
      });
      result[col.key] = Array.from(values).sort();
    }
    return result;
  }, [data, columns]);

  // 드래그 완료
  const handleDragEnd = (event: DragEndEvent) => {
    const { active, over } = event;
    if (!over || active.id === over.id) return;
    setColumns((prev) => {
      const oldIndex = prev.findIndex((c) => c.key === active.id);
      const newIndex = prev.findIndex((c) => c.key === over.id);
      const next = arrayMove(prev, oldIndex, newIndex);
      if (gridId) localStorage.setItem(`datagrid_col_order_${gridId}`, JSON.stringify(next.map((c) => c.key)));
      onColumnOrderChange?.(next);
      return next;
    });
  };

  // 정렬
  const handleSort = (key: string) => {
    if (sortKey === key) setSortDir((d) => (d === "asc" ? "desc" : "asc"));
    else { setSortKey(key); setSortDir("asc"); }
  };

  // 헤더 필터 토글
  const toggleHeaderFilter = (colKey: string, value: string) => {
    setHeaderFilters((prev) => {
      const next = { ...prev };
      const set = new Set(next[colKey] || []);
      if (set.has(value)) set.delete(value); else set.add(value);
      if (set.size === 0) delete next[colKey]; else next[colKey] = set;
      return next;
    });
  };

  const clearHeaderFilter = (colKey: string) => {
    setHeaderFilters((prev) => {
      const next = { ...prev };
      delete next[colKey];
      return next;
    });
  };

  // 필터 + 정렬 적용
  const processedData = useMemo(() => {
    let result = [...data];

    // 헤더 필터 적용
    if (Object.keys(headerFilters).length > 0) {
      result = result.filter((row) => {
        return Object.entries(headerFilters).every(([colKey, values]) => {
          if (values.size === 0) return true;
          const cellVal = row[colKey] != null ? String(row[colKey]) : "";
          return values.has(cellVal);
        });
      });
    }

    // 정렬
    if (sortKey) {
      result.sort((a, b) => {
        const av = a[sortKey] ?? "";
        const bv = b[sortKey] ?? "";
        const na = Number(av);
        const nb = Number(bv);
        if (!isNaN(na) && !isNaN(nb)) return sortDir === "asc" ? na - nb : nb - na;
        return sortDir === "asc" ? String(av).localeCompare(String(bv)) : String(bv).localeCompare(String(av));
      });
    }

    return result;
  }, [data, headerFilters, sortKey, sortDir]);

  // 필터/데이터 변경 시 1페이지로 리셋 — 서버 페이지네이션에서는 부모가 직접 page 관리하므로 스킵
  useEffect(() => {
    if (serverPaging) return;
    setLocalCurrentPage(1);
  }, [data, headerFilters, serverPaging]);

  // 페이지네이션 계산
  // 서버 모드: totalItems 는 prop, paginatedData 는 data 그대로(서버가 잘라준 한 페이지)
  // 클라이언트 모드: totalItems = processedData.length, paginatedData = client slice
  const totalItems = serverPaging ? (serverTotalItems ?? processedData.length) : processedData.length;
  const totalPages = Math.max(1, Math.ceil(totalItems / pageSize));
  const safePage = Math.min(currentPage, totalPages);

  useEffect(() => {
    if (!serverPaging && currentPage > totalPages) setCurrentPage(totalPages);
  }, [serverPaging, currentPage, totalPages, setCurrentPage]);

  const pageOffset = (safePage - 1) * pageSize;
  const paginatedData = serverPaging
    ? processedData
    : (showPagination ? processedData.slice(pageOffset, pageOffset + pageSize) : processedData);

  // 페이지 크기 입력 적용
  const applyPageSize = () => {
    const n = parseInt(pageSizeInput, 10);
    if (!isNaN(n) && n >= 1) {
      setPageSize(n);
      if (!serverPaging) setLocalCurrentPage(1);
      setPageSizeInput(String(n));
    } else {
      setPageSizeInput(String(pageSize));
    }
  };

  // 페이지 번호 배열 생성
  const getPageNumbers = () => {
    const delta = 2;
    let start = Math.max(1, safePage - delta);
    let end = Math.min(totalPages, safePage + delta);
    if (end - start < delta * 2) {
      if (start === 1) end = Math.min(totalPages, start + delta * 2);
      else if (end === totalPages) start = Math.max(1, end - delta * 2);
    }
    const pages: (number | "...")[] = [];
    if (start > 1) { pages.push(1); if (start > 2) pages.push("..."); }
    for (let i = start; i <= end; i++) pages.push(i);
    if (end < totalPages) { if (end < totalPages - 1) pages.push("..."); pages.push(totalPages); }
    return pages;
  };

  // 인라인 편집
  const startEdit = (rowIdx: number, colKey: string, currentVal: any) => {
    const col = columns.find((c) => c.key === colKey);
    if (!col?.editable) return;
    setEditingCell({ rowIdx, colKey });
    setEditValue(currentVal != null ? String(currentVal) : "");
  };

  const saveEdit = useCallback(async () => {
    if (!editingCell) return;
    const { rowIdx, colKey } = editingCell;
    const row = paginatedData[rowIdx];
    if (!row) { setEditingCell(null); return; }

    const originalVal = String(row[colKey] ?? "");
    if (originalVal === editValue) { setEditingCell(null); return; }

    if (tableName && row.id) {
      try {
        await apiClient.put(`/table-management/tables/${tableName}/edit`, {
          originalData: { id: row.id },
          updatedData: { [colKey]: editValue || null },
        });
        row[colKey] = editValue;
        toast.success("저장됨");
      } catch (err) {
        toast.error("저장에 실패했습니다.");
        setEditingCell(null);
        return;
      }
    }

    onCellEdit?.(row.id, colKey, editValue, row);
    setEditingCell(null);
  }, [editingCell, editValue, paginatedData, tableName, onCellEdit]);

  const cancelEdit = () => setEditingCell(null);

  const handleEditKeyDown = (e: React.KeyboardEvent) => {
    if (e.key === "Enter") { e.preventDefault(); saveEdit(); }
    else if (e.key === "Escape") { e.preventDefault(); cancelEdit(); }
    else if (e.key === "Tab") { e.preventDefault(); saveEdit(); }
  };

  useEffect(() => {
    if (editingCell && editRef.current) {
      editRef.current.focus();
      editRef.current.select();
    }
  }, [editingCell]);

  // 셀 렌더링
  const renderCell = (row: any, col: DataGridColumn, rowIdx: number) => {
    const isEditing = editingCell?.rowIdx === rowIdx && editingCell?.colKey === col.key;
    const val = row[col.key];

    if (isEditing) {
      if (col.inputType === "select" && col.selectOptions) {
        return (
          <select ref={editRef as any} value={editValue} onChange={(e) => setEditValue(e.target.value)}
            onKeyDown={handleEditKeyDown} onBlur={saveEdit}
            className="h-7 w-full rounded border border-primary bg-background px-1.5 text-xs focus:ring-1">
            <option value="">선택</option>
            {col.selectOptions.map((o) => <option key={o.value} value={o.value}>{o.label}</option>)}
          </select>
        );
      }
      return (
        <input ref={editRef} type={col.inputType === "date" ? "date" : "text"}
          value={editValue} onChange={(e) => setEditValue(e.target.value)}
          onKeyDown={handleEditKeyDown} onBlur={saveEdit}
          className={cn("h-7 w-full rounded border border-primary bg-background px-1.5 text-xs focus:ring-1",
            col.align === "right" && "text-right")} />
      );
    }

    // 이미지 타입
    if (col.renderType === "image" && val) {
      const src = (val.startsWith("http") || val.startsWith("/")) ? val : `/api/files/preview/${val}`;
      return (
        <img src={src} alt="" className="h-10 w-10 rounded object-cover cursor-pointer hover:ring-2 hover:ring-primary transition-all"
          onClick={(e) => { e.stopPropagation(); setPreviewImage(src); }} />
      );
    }
    if (col.renderType === "image" && !val) {
      return <div className="h-10 w-10 rounded bg-muted flex items-center justify-center"><ImageIcon className="h-4 w-4 text-muted-foreground/30" /></div>;
    }

    // 폴더 아이콘 (wace 견적현황 패턴) — 값이 0/빈값이면 흰색 폴더, >0이면 파란 폴더
    if (col.renderType === "folder") {
      const cnt = Number(val);
      const hasValue = !isNaN(cnt) && cnt > 0;
      const clickable = !!col.onClick;
      return (
        <span
          className={cn("inline-flex items-center justify-center w-full", clickable && "cursor-pointer")}
          onClick={clickable ? (e) => { e.stopPropagation(); col.onClick!(row); } : undefined}
        >
          <Folder
            className={cn("w-5 h-5", hasValue
              ? "fill-[#1a73e8] text-[#1a73e8]"
              : "fill-white text-muted-foreground/60",
              clickable && "hover:opacity-70")}
          />
        </span>
      );
    }

    // 클립 아이콘 + 카운트 (wace 추가견적 패턴) — >0이면 파란 클립+숫자, 아니면 회색 클립
    if (col.renderType === "clip") {
      const cnt = Number(val);
      const hasValue = !isNaN(cnt) && cnt > 0;
      const clickable = !!col.onClick;
      return (
        <span
          className={cn("inline-flex items-center justify-center gap-1 w-full", clickable && "cursor-pointer")}
          onClick={clickable ? (e) => { e.stopPropagation(); col.onClick!(row); } : undefined}
        >
          <Paperclip className={cn("w-4 h-4",
            hasValue ? "text-[#1a73e8]" : "text-muted-foreground/50",
            clickable && "hover:opacity-70")} />
          {hasValue && <span className="text-[#1a73e8] font-bold text-xs">{cnt}</span>}
        </span>
      );
    }

    let display = val ?? "";
    if (col.formatMoney) display = fmtMoney(val);
    else if (col.formatNumber || col.inputType === "number") display = fmtNum(val);
    const truncateClass = col.truncate !== false ? "block truncate" : "";
    // 숫자 컬럼은 무조건 우측 정렬 (정책)
    const isNumericCol = col.formatMoney || col.formatNumber || col.inputType === "number";
    const isRightAlign = col.align === "right" || isNumericCol;

    return (
      <span className={cn("text-xs leading-tight", truncateClass, isRightAlign && "text-right w-full inline-block")}
        title={String(val ?? "")}>
        {display}
      </span>
    );
  };

  // 좌측 고정 보조: NO/체크박스 컬럼은 40px(=left-10), 첫 frozen 컬럼은 그 다음 위치
  const hasFrozen = visibleColumns.some((c) => c.frozen);
  const hasFirstCol = showCheckbox || showRowNumber;
  const stickyFirstColClass = "sticky left-0 z-20 bg-background";
  const stickyFirstColBodyClass = "sticky left-0 z-[6]";
  const frozenLeftClass = hasFirstCol ? "left-10" : "left-0";

  // 다중 frozen 컬럼 누적 left 픽셀 (No/체크박스 다음 위치부터)
  const frozenLeftPxMap = useMemo(() => {
    const map: Record<string, number> = {};
    let cursor = hasFirstCol ? 40 : 0;
    for (const c of visibleColumns) {
      if (!c.frozen) continue;
      map[c.key] = cursor;
      const px = columnWidths[c.key] ?? parseWidthClass(c.width) ?? parseWidthClass(c.minWidth) ?? 100;
      cursor += px;
    }
    return map;
  }, [visibleColumns, columnWidths, hasFirstCol]);

  // 컬럼 settings dropdown — 데이터/시스템 그룹 분리. 시스템 키는 systemColumnKeys로 지정.
  const systemKeySet = useMemo(() => new Set(systemColumnKeys ?? []), [systemColumnKeys]);
  const dataCols = useMemo(() => columns.filter((c) => !systemKeySet.has(c.key)), [columns, systemKeySet]);
  const systemCols = useMemo(() => columns.filter((c) => systemKeySet.has(c.key)), [columns, systemKeySet]);

  const hasToolbar = showColumnSettings || onRefresh || onDownload || showChart;

  return (
    <div className="flex flex-col h-full flex-1 min-h-0">
      {hasToolbar && (
        <div className="flex items-center justify-end gap-0.5 border-b bg-muted/20 px-2 py-1 shrink-0">
          {onRefresh && (
            <button
              type="button"
              onClick={onRefresh}
              className="h-7 w-7 inline-flex items-center justify-center rounded hover:bg-muted text-muted-foreground"
              title="재조회"
            >
              <RotateCw className="h-4 w-4" />
            </button>
          )}
          {showChart && (
            <button
              type="button"
              onClick={toggleChartPanel}
              className={cn(
                "h-7 w-7 inline-flex items-center justify-center rounded hover:bg-muted",
                chartPanelOpen ? "text-primary bg-primary/10" : "text-muted-foreground",
              )}
              title="차트 분석"
            >
              <BarChart3 className="h-4 w-4" />
            </button>
          )}
          {onDownload && (
            <button
              type="button"
              onClick={onDownload}
              className="h-7 w-7 inline-flex items-center justify-center rounded hover:bg-muted text-muted-foreground"
              title="Excel 다운로드"
            >
              <DownloadIcon className="h-4 w-4" />
            </button>
          )}
          {showColumnSettings && (
          <Popover>
            <PopoverTrigger asChild>
              <button
                type="button"
                className="h-7 w-7 inline-flex items-center justify-center rounded hover:bg-muted text-muted-foreground"
                title="컬럼 표시 설정"
              >
                <Settings className="h-4 w-4" />
              </button>
            </PopoverTrigger>
            <PopoverContent className="w-64 p-0" align="end">
              <div className="px-3 py-2 border-b">
                <span className="text-sm font-semibold">표시할 컬럼 선택</span>
              </div>
              <div className="max-h-[60vh] overflow-y-auto px-2 py-2 space-y-3">
                {dataCols.length > 0 && (
                  <div>
                    <div className="text-[11px] font-medium text-muted-foreground px-1 mb-1">데이터 컬럼</div>
                    <div className="space-y-0.5">
                      {dataCols.map((col) => {
                        const checked = !hiddenColumns.has(col.key);
                        return (
                          <label
                            key={col.key}
                            className="flex items-center gap-2 px-1.5 py-1 rounded hover:bg-muted cursor-pointer text-sm"
                          >
                            <Checkbox checked={checked} onCheckedChange={() => toggleColumnVisibility(col.key)} />
                            <span className="truncate">{col.label}</span>
                          </label>
                        );
                      })}
                    </div>
                  </div>
                )}
                {systemCols.length > 0 && (
                  <div>
                    <div className="text-[11px] font-medium text-muted-foreground px-1 mb-1">시스템 컬럼</div>
                    <div className="space-y-0.5">
                      {systemCols.map((col) => {
                        const checked = !hiddenColumns.has(col.key);
                        return (
                          <label
                            key={col.key}
                            className="flex items-center gap-2 px-1.5 py-1 rounded hover:bg-muted cursor-pointer text-sm"
                          >
                            <Checkbox checked={checked} onCheckedChange={() => toggleColumnVisibility(col.key)} />
                            <span className="truncate">{col.label}</span>
                          </label>
                        );
                      })}
                    </div>
                  </div>
                )}
              </div>
              <div className="border-t px-2 py-1.5 flex flex-col items-start gap-0.5">
                <button onClick={resetVisibility} className="text-primary text-xs hover:underline px-1.5 py-0.5">
                  표시/숨김 초기화
                </button>
                <button onClick={resetOrder} className="text-primary text-xs hover:underline px-1.5 py-0.5">
                  순서 초기화
                </button>
                <button onClick={resetWidthsAll} className="text-primary text-xs hover:underline px-1.5 py-0.5">
                  컬럼 너비 초기화
                </button>
              </div>
            </PopoverContent>
          </Popover>
          )}
        </div>
      )}
      <div className="flex-1 min-h-0 overflow-auto">
      <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
        <Table noWrapper className="table-fixed">
          <TableHeader className="sticky top-0 bg-muted z-10 shadow-[0_1px_0_0_hsl(var(--border))] [&_th]:h-9 [&_th]:bg-muted">
            <SortableContext items={visibleColumns.map((c) => c.key)} strategy={horizontalListSortingStrategy}>
              <TableRow>
                {showCheckbox && (
                  <TableHead className={cn("w-[40px] text-center ", hasFrozen && stickyFirstColClass)}>
                    <Checkbox
                      checked={processedData.length > 0 && checkedIds.length === processedData.length}
                      onCheckedChange={(checked) => {
                        onCheckedChange?.(checked ? processedData.map((r) => r.id) : []);
                      }}
                    />
                  </TableHead>
                )}
                {showRowNumber && !showCheckbox && (
                  <TableHead className={cn("w-[40px] text-center text-xs ", hasFrozen && stickyFirstColClass)}>No</TableHead>
                )}
                {visibleColumns.map((col) => (
                  <SortableHeaderCell
                    key={col.key}
                    col={col}
                    sortKey={sortKey}
                    sortDir={sortDir}
                    onSort={handleSort}
                    headerFilterValues={headerFilters[col.key] || new Set()}
                    uniqueValues={columnUniqueValues[col.key] || []}
                    onToggleFilter={toggleHeaderFilter}
                    onClearFilter={clearHeaderFilter}
                    frozenLeftClass={frozenLeftClass}
                    frozenLeftPx={frozenLeftPxMap[col.key]}
                    widthPx={columnWidths[col.key]}
                    onResizeStart={startResize}
                  />
                ))}
              </TableRow>
            </SortableContext>
          </TableHeader>
          <TableBody className="[&_tr]:!h-7 [&_td]:!py-0 [&_td]:!h-7 [&_td]:!leading-none [&_td_*]:!leading-none [&_td_svg]:!h-3.5 [&_td_svg]:!w-3.5">
            {loading ? (
              <TableRow>
                <TableCell colSpan={visibleColumns.length + 1} className="text-center py-8 text-muted-foreground">
                  로딩 중...
                </TableCell>
              </TableRow>
            ) : paginatedData.length === 0 ? (
              <TableRow>
                <TableCell colSpan={visibleColumns.length + 1} className="text-center py-8 text-muted-foreground">
                  {emptyMessage}
                </TableCell>
              </TableRow>
            ) : paginatedData.map((row, rowIdx) => {
              // selectedId 또는 row.id 가 nullish 면 비교 결과를 무조건 false 로 — 둘 다 undefined 일 때 `undefined === undefined` 가 true 가 되어 모든 행이 selected 로 잡히는 함정 차단
              const isSelected =
                (selectedId != null && row.id != null && selectedId === row.id) ||
                (showCheckbox && row.id != null && checkedIds.includes(row.id));
              // sticky 셀에 alpha 없는 단색 배경 사용 (반투명이면 뒤 셀이 비침).
              // selected → bg-accent / hover(non-selected) → group-hover로 muted 적용 / 기본 → bg-background
              const stickyBgClass = isSelected ? "bg-accent" : "bg-background group-hover:bg-muted";
              return (
              <TableRow
                key={row.id || rowIdx}
                style={{ height: 28 }}
                className={cn("cursor-pointer group",
                  isSelected && "bg-accent text-accent-foreground",
                )}
                onClick={() => {
                  onSelect?.(row.id);
                  onRowClick?.(row, rowIdx);
                  // 체크박스 모드에서는 행 클릭으로 체크 토글
                  if (showCheckbox && onCheckedChange) {
                    const next = checkedIds.includes(row.id)
                      ? checkedIds.filter((id) => id !== row.id)
                      : [...checkedIds, row.id];
                    onCheckedChange(next);
                  }
                }}
                onDoubleClick={() => onRowDoubleClick?.(row, rowIdx)}
              >
                {showCheckbox && (
                  <TableCell
                    className={cn(
                      "text-center ",
                      isSelected && "bg-accent",
                      hasFrozen && cn(stickyFirstColBodyClass, stickyBgClass),
                    )}
                    onClick={(e) => e.stopPropagation()}
                  >
                    <Checkbox
                      checked={checkedIds.includes(row.id)}
                      onCheckedChange={(checked) => {
                        const next = checked
                          ? [...checkedIds, row.id]
                          : checkedIds.filter((id) => id !== row.id);
                        onCheckedChange?.(next);
                      }}
                    />
                  </TableCell>
                )}
                {showRowNumber && !showCheckbox && (
                  <TableCell className={cn(
                    "text-center text-[10px] text-muted-foreground ",
                    isSelected && "bg-accent",
                    hasFrozen && cn(stickyFirstColBodyClass, stickyBgClass),
                  )}>
                    {pageOffset + rowIdx + 1}
                  </TableCell>
                )}
                {visibleColumns.map((col) => {
                  const w = columnWidths[col.key];
                  const frozenLeft = col.frozen ? frozenLeftPxMap[col.key] : undefined;
                  const inlineStyle: React.CSSProperties = {};
                  if (w != null) { inlineStyle.width = w; inlineStyle.minWidth = w; inlineStyle.maxWidth = w; }
                  if (frozenLeft != null) { inlineStyle.left = frozenLeft; }
                  // 일반 텍스트 셀에 컬럼 단위 onClick 지원 (clip/folder 외)
                  const cellClickable = !!col.onClick && !col.editable;
                  return (
                  <TableCell
                    key={col.key}
                    style={Object.keys(inlineStyle).length > 0 ? inlineStyle : undefined}
                    className={cn(
                      w == null && col.width, w == null && col.minWidth, "py-1",
                      col.editable && "cursor-text",
                      cellClickable && "cursor-pointer hover:underline text-primary",
                      isSelected && "bg-accent",
                      col.frozen && cn("sticky z-[5]", frozenLeft == null && frozenLeftClass, stickyBgClass),
                    )}
                    onClick={cellClickable ? (e) => { e.stopPropagation(); col.onClick!(row); } : undefined}
                    onDoubleClick={(e) => {
                      if (col.editable) {
                        e.stopPropagation();
                        startEdit(rowIdx, col.key, row[col.key]);
                      }
                    }}
                  >
                    {renderCell(row, col, rowIdx)}
                  </TableCell>
                  );
                })}
              </TableRow>
            );})}
          </TableBody>
        </Table>
      </DndContext>
      </div>

      {/* 하단 통계 행 — summaryStats 지정 시. 페이지네이션 footer 위에 별도 띠로 노출. */}
      {summaryStats && summaryStats.length > 0 && (
        <div className="flex flex-wrap items-center gap-x-4 gap-y-1 border-t bg-muted/30 px-3 py-1.5 text-xs shrink-0">
          {summaryStats.map((s, i) => (
            <div key={`${s.label}-${i}`} className="inline-flex items-center gap-1.5">
              <span className="text-muted-foreground">{s.label}</span>
              <span className="font-semibold text-foreground tabular-nums">{s.value}{s.suffix ?? ""}</span>
            </div>
          ))}
        </div>
      )}

      {/* 페이지네이션 footer */}
      {showPagination && (
        <div className="flex items-center justify-between border-t px-3 py-2 text-xs text-muted-foreground shrink-0">
          {/* 좌측: 데이터 수량 + 페이지 크기 입력/Select */}
          <div className="flex items-center gap-3">
            <div className="flex items-center gap-1">
              {paginationStyle === "range" ? (
                <>
                  <span className="font-medium text-foreground tabular-nums">
                    {totalItems === 0 ? 0 : (pageOffset + 1).toLocaleString()}-{(pageOffset + paginatedData.length).toLocaleString()}
                  </span>
                  <span>/ 총</span>
                  <span className="font-medium text-foreground tabular-nums">{totalItems.toLocaleString()}</span>
                  <span>건</span>
                </>
              ) : (
                <>
                  <span>전체</span>
                  <span className="font-medium text-foreground">{totalItems.toLocaleString()}</span>
                  <span>건</span>
                </>
              )}
            </div>
            <div className="flex items-center gap-1.5">
              {pageSizeOptions && pageSizeOptions.length > 0 ? (
                <Select
                  value={String(pageSize)}
                  onValueChange={(v) => {
                    const n = Number(v);
                    if (!isNaN(n) && n >= 1) {
                      setPageSize(n);
                      setPageSizeInput(String(n));
                      // 서버 모드는 부모가 page 리셋(또는 페이지 유지)을 직접 결정
                      if (!serverPaging) setLocalCurrentPage(1);
                    }
                  }}
                >
                  <SelectTrigger className="h-7 w-[88px] text-xs">
                    <SelectValue />
                  </SelectTrigger>
                  <SelectContent>
                    {pageSizeOptions.map((n) => (
                      <SelectItem key={n} value={String(n)} className="text-xs">
                        {n} / 페이지
                      </SelectItem>
                    ))}
                  </SelectContent>
                </Select>
              ) : (
                <>
                  <Input
                    type="number"
                    min={1}
                    value={pageSizeInput}
                    onChange={(e) => setPageSizeInput(e.target.value)}
                    onBlur={applyPageSize}
                    onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); applyPageSize(); } }}
                    className="h-7 w-16 text-center text-xs"
                  />
                  <span>건씩 보기</span>
                </>
              )}
            </div>
          </div>

          {/* 중앙: 페이지 이동 버튼 */}
          <div className="flex items-center gap-0.5">
            <button onClick={() => setCurrentPage(1)} disabled={safePage === 1}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed" title="첫 페이지">
              <ChevronsLeft className="h-3.5 w-3.5" />
            </button>
            <button onClick={() => setCurrentPage((p) => Math.max(1, p - 1))} disabled={safePage === 1}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed" title="이전 페이지">
              <ChevronLeft className="h-3.5 w-3.5" />
            </button>
            {getPageNumbers().map((page, idx) =>
              page === "..." ? (
                <span key={`dot-${idx}`} className="h-7 w-7 flex items-center justify-center text-muted-foreground">...</span>
              ) : (
                <button key={page} onClick={() => setCurrentPage(page as number)}
                  className={cn("h-7 w-7 flex items-center justify-center rounded text-xs",
                    page === safePage ? "bg-primary text-primary-foreground font-medium" : "hover:bg-muted")}>
                  {page}
                </button>
              )
            )}
            <button onClick={() => setCurrentPage((p) => Math.min(totalPages, p + 1))} disabled={safePage === totalPages}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed" title="다음 페이지">
              <ChevronRight className="h-3.5 w-3.5" />
            </button>
            <button onClick={() => setCurrentPage(totalPages)} disabled={safePage === totalPages}
              className="h-7 w-7 flex items-center justify-center rounded hover:bg-muted disabled:opacity-30 disabled:cursor-not-allowed" title="마지막 페이지">
              <ChevronsRight className="h-3.5 w-3.5" />
            </button>
          </div>

          {/* 우측: 좌측과 균형용 빈 공간 */}
          <div className="flex items-center gap-3 invisible">
            <div className="flex items-center gap-1">
              <span>전체</span>
              <span>{totalItems.toLocaleString()}</span>
              <span>건</span>
            </div>
            <div className="flex items-center gap-1.5">
              <div className="h-7 w-16" />
              <span>건씩 보기</span>
            </div>
          </div>
        </div>
      )}

      {/* 차트 분석 패널 — showChart + chartPanelOpen 시 노출 */}
      {showChart && chartPanelOpen && (
        <DataGridChartPanel gridId={gridId} columns={columns} data={processedData} />
      )}

      {/* 이미지 확대 모달 */}
      {previewImage && (
        <div className="fixed inset-0 z-[9999] flex items-center justify-center bg-black/70"
          onClick={() => setPreviewImage(null)}>
          <div className="relative max-w-[90vw] max-h-[90vh]">
            <img src={previewImage} alt="" className="max-w-full max-h-[85vh] rounded-lg object-contain" />
            <button className="absolute -top-3 -right-3 bg-background rounded-full p-1 shadow-lg hover:bg-muted"
              onClick={() => setPreviewImage(null)}>
              <X className="h-5 w-5" />
            </button>
          </div>
        </div>
      )}
    </div>
  );
}
