"use client";

import type { ReactNode } from "react";
import { useState, useEffect, useCallback, useMemo } from "react";
import { cn } from "@/lib/utils";
import { numberWithCommas } from "@/lib/utils";
import { Pagination } from "@/components/ui/pagination";

// Tabulator 대응 - 데이터 그리드 컴포넌트
export interface GridColumn {
  title: string;
  field?: string;
  width?: number | string;
  hozAlign?: "left" | "center" | "right";
  headerHozAlign?: "left" | "center" | "right";
  formatter?: "money" | "link" | "checkbox" | "rowSelection" | ((cell: unknown, row: Record<string, unknown>) => ReactNode);
  formatterParams?: Record<string, unknown>;
  visible?: boolean;
  frozen?: boolean;
  editor?: boolean;
  cellClick?: (row: Record<string, unknown>) => void;
  // 그룹 헤더용 — columns가 있으면 field는 무시되고 하위 컬럼을 렌더
  columns?: GridColumn[];
}

interface DataGridProps {
  columns: GridColumn[];
  dataUrl?: string;
  data?: Record<string, unknown>[];
  formId?: string;
  showCheckbox?: boolean;
  height?: string;
  className?: string;
  onRowClick?: (row: Record<string, unknown>) => void;
  onSelectionChange?: (rows: Record<string, unknown>[]) => void;
  searchParams?: Record<string, string>;
  // 페이지네이션 (기본 활성, false 전달 시 비활성)
  pagination?: boolean;
  pageSize?: number;
  // 외부 로딩 상태 (data prop 모드일 때 fetchData 타이밍을 알리기 위해)
  loading?: boolean;
}

export function DataGrid({
  columns,
  dataUrl,
  data: initialData,
  showCheckbox = false,
  height,
  className,
  onRowClick,
  onSelectionChange,
  searchParams = {},
  pagination = true,
  pageSize: initialPageSize = 20,
  loading: externalLoading,
}: DataGridProps) {
  const [data, setData] = useState<Record<string, unknown>[]>(initialData || []);
  const [selectedRows, setSelectedRows] = useState<Set<number>>(new Set());
  const [currentPage, setCurrentPage] = useState(1);
  const [pageSize, setPageSize] = useState(initialPageSize);
  const [sortField, setSortField] = useState<string>("");
  const [sortDir, setSortDir] = useState<"asc" | "desc">("asc");
  const [loading, setLoading] = useState(false);
  const [totalCount, setTotalCount] = useState(0);

  const fetchData = useCallback(async () => {
    if (!dataUrl) return;
    setLoading(true);
    try {
      const params = new URLSearchParams(searchParams);
      const res = await fetch(dataUrl, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify(Object.fromEntries(params)),
      });
      if (res.ok) {
        const json = await res.json();
        const list = json.RESULTLIST || json.data || json;
        setData(Array.isArray(list) ? list : []);
        setTotalCount(json.TOTAL_CNT || list.length || 0);
      }
    } catch (err) {
      console.error("Grid data fetch error:", err);
    } finally {
      setLoading(false);
    }
  }, [dataUrl, searchParams]);

  useEffect(() => {
    if (dataUrl) fetchData();
  }, [fetchData, dataUrl]);

  useEffect(() => {
    if (initialData) {
      setData(initialData);
      setCurrentPage(1); // 데이터가 갱신되면 1페이지로 리셋
    }
  }, [initialData]);

  // 현재 페이지 데이터 slice
  const pagedData = useMemo(() => {
    if (!pagination) return data;
    const start = (currentPage - 1) * pageSize;
    return data.slice(start, start + pageSize);
  }, [data, currentPage, pageSize, pagination]);

  const handleSort = (field: string) => {
    const newDir = sortField === field && sortDir === "asc" ? "desc" : "asc";
    setSortField(field);
    setSortDir(newDir);
    setData((prev) =>
      [...prev].sort((a, b) => {
        const aVal = String(a[field] || "");
        const bVal = String(b[field] || "");
        return newDir === "asc" ? aVal.localeCompare(bVal) : bVal.localeCompare(aVal);
      })
    );
  };

  const toggleRow = (idx: number) => {
    const next = new Set(selectedRows);
    if (next.has(idx)) next.delete(idx);
    else next.add(idx);
    setSelectedRows(next);
    onSelectionChange?.(data.filter((_, i) => next.has(i)));
  };

  const toggleAll = () => {
    if (selectedRows.size === data.length) {
      setSelectedRows(new Set());
      onSelectionChange?.([]);
    } else {
      const all = new Set(data.map((_, i) => i));
      setSelectedRows(all);
      onSelectionChange?.(data);
    }
  };

  const formatCell = (col: GridColumn, value: unknown, row: Record<string, unknown>): ReactNode => {
    if (typeof col.formatter === "function") {
      return col.formatter(value, row);
    }
    if (col.formatter === "money") {
      return numberWithCommas(Number(value) || 0);
    }
    return String(value ?? "");
  };

  const visibleColumns = columns.filter((c) => c.visible !== false);

  // 그룹 컬럼 → 리프(실제 데이터 컬럼)만 평탄화
  const flatten = (cols: GridColumn[]): GridColumn[] =>
    cols.flatMap((c) =>
      c.columns && c.columns.length > 0 ? flatten(c.columns.filter((sc) => sc.visible !== false)) : [c]
    );
  const leafColumns = flatten(visibleColumns);

  // 틀고정 컬럼 누적 left 오프셋 (좌측부터 연속된 frozen 가정)
  const CHECKBOX_WIDTH = 40;
  const frozenLefts = new Map<string, number>();
  {
    let offset = showCheckbox ? CHECKBOX_WIDTH : 0;
    for (const col of leafColumns) {
      if (col.frozen) {
        frozenLefts.set(col.field || col.title, offset);
        offset += typeof col.width === "number" ? col.width : 120;
      }
    }
  }
  const getFrozenLeft = (col: GridColumn): number | undefined =>
    col.frozen ? frozenLefts.get(col.field || col.title) : undefined;

  // 그룹 헤더 뎁스 계산 (최대 중첩 수)
  const depth = (cols: GridColumn[]): number =>
    cols.reduce((m, c) => Math.max(m, c.columns && c.columns.length > 0 ? 1 + depth(c.columns.filter((sc) => sc.visible !== false)) : 1), 0);
  const maxDepth = Math.max(1, depth(visibleColumns));

  // 뎁스별 헤더 행 생성
  const headerRows: GridColumn[][] = Array.from({ length: maxDepth }, () => []);
  const fill = (cols: GridColumn[], rowIdx: number) => {
    cols.forEach((c) => {
      if (c.columns && c.columns.length > 0) {
        headerRows[rowIdx].push(c);
        fill(c.columns.filter((sc) => sc.visible !== false), rowIdx + 1);
      } else {
        headerRows[rowIdx].push({ ...c, rowSpan: maxDepth - rowIdx } as GridColumn & { rowSpan: number });
      }
    });
  };
  fill(visibleColumns, 0);

  // 그룹 컬럼 span 계산 (리프 개수)
  const colSpan = (c: GridColumn): number => {
    if (!c.columns || c.columns.length === 0) return 1;
    return c.columns.filter((sc) => sc.visible !== false).reduce((s, sc) => s + colSpan(sc), 0);
  };

  const isLoading = loading || externalLoading;

  // height가 명시되지 않으면 부모의 flex 컬럼에서 남는 공간을 자동으로 채운다.
  const autoFill = !height;

  return (
    <div
      className={cn(
        "relative border border-gray-200 rounded bg-white",
        autoFill && "flex-1 min-h-0 flex flex-col",
        className,
      )}
    >
      {isLoading && (
        <div className="absolute inset-0 z-20 flex items-center justify-center bg-white/70 backdrop-blur-[1px]">
          <div className="flex flex-col items-center gap-3">
            <div className="w-12 h-12 border-4 border-gray-300 border-t-primary rounded-full animate-spin" />
            <span className="text-sm font-semibold text-gray-700">Loading...</span>
          </div>
        </div>
      )}

      {/* 테이블 */}
      <div
        className={cn("overflow-auto", autoFill && "flex-1 min-h-0")}
        style={autoFill ? undefined : { maxHeight: height }}
      >
        <table className="w-full text-sm border-collapse" style={{ minWidth: "max-content" }}>
          <thead className="sticky top-0 z-10 bg-gray-50">
            {headerRows.map((row, rIdx) => (
              <tr key={rIdx}>
                {rIdx === 0 && showCheckbox && (
                  <th
                    rowSpan={maxDepth}
                    className="w-10 border-b border-r border-gray-200 px-2 py-2 text-center bg-gray-50"
                    style={{ position: "sticky", left: 0, zIndex: 12 }}
                  >
                    <input
                      type="checkbox"
                      checked={selectedRows.size === data.length && data.length > 0}
                      onChange={toggleAll}
                      className="rounded"
                    />
                  </th>
                )}
                {row.map((col, cIdx) => {
                  const isGroup = !!(col.columns && col.columns.length > 0);
                  const span = isGroup ? colSpan(col) : 1;
                  const rSpan = (col as GridColumn & { rowSpan?: number }).rowSpan || 1;
                  const frozenLeft = getFrozenLeft(col);
                  const isFrozen = frozenLeft !== undefined;
                  return (
                    <th
                      key={`${rIdx}-${cIdx}-${col.field || col.title}`}
                      colSpan={span}
                      rowSpan={rSpan}
                      className={cn(
                        "border-b border-r border-gray-200 px-3 py-2 font-semibold text-gray-700 whitespace-nowrap",
                        !isGroup && col.field ? "cursor-pointer hover:bg-gray-100" : "bg-gray-100",
                        isFrozen && "bg-gray-50"
                      )}
                      style={{
                        width: col.width,
                        textAlign: col.headerHozAlign || "center",
                        ...(isFrozen ? { position: "sticky", left: frozenLeft, zIndex: 12 } : {}),
                      }}
                      onClick={() => !isGroup && col.field && handleSort(col.field)}
                    >
                      {col.title}
                      {!isGroup && col.field && sortField === col.field && (
                        <span className="ml-1 text-xs">{sortDir === "asc" ? "▲" : "▼"}</span>
                      )}
                    </th>
                  );
                })}
              </tr>
            ))}
          </thead>
          <tbody>
            {pagedData.length === 0 ? (
              <tr>
                <td
                  colSpan={leafColumns.length + (showCheckbox ? 1 : 0)}
                  className="text-center py-12 text-gray-400"
                >
                  데이터가 없습니다.
                </td>
              </tr>
            ) : (
              pagedData.map((row, relIdx) => {
                const idx = pagination ? (currentPage - 1) * pageSize + relIdx : relIdx;
                const rowBg = selectedRows.has(idx) ? "#EFF6FF" : "#FFFFFF";
                return (
                <tr
                  key={idx}
                  className={cn(
                    "border-b border-gray-100 hover:bg-blue-50/50 transition-colors cursor-pointer",
                    selectedRows.has(idx) && "bg-blue-50"
                  )}
                  onClick={() => onRowClick?.(row)}
                >
                  {showCheckbox && (
                    <td
                      className="px-2 py-2 text-center border-r border-gray-100"
                      style={{ position: "sticky", left: 0, zIndex: 2, background: rowBg }}
                      onClick={(e) => e.stopPropagation()}
                    >
                      <input
                        type="checkbox"
                        checked={selectedRows.has(idx)}
                        onChange={() => toggleRow(idx)}
                        className="rounded"
                      />
                    </td>
                  )}
                  {leafColumns.map((col, cIdx) => {
                    const frozenLeft = getFrozenLeft(col);
                    const isFrozen = frozenLeft !== undefined;
                    return (
                    <td
                      key={`${col.field || col.title}-${cIdx}`}
                      className="px-3 py-2 whitespace-nowrap border-r border-gray-100"
                      style={{
                        textAlign: col.hozAlign || "left",
                        ...(isFrozen ? { position: "sticky", left: frozenLeft, zIndex: 2, background: rowBg } : {}),
                      }}
                      onClick={(e) => {
                        if (col.cellClick) {
                          e.stopPropagation();
                          col.cellClick(row);
                        }
                      }}
                    >
                      {col.cellClick ? (
                        <span className="text-primary hover:underline cursor-pointer">
                          {formatCell(col, col.field ? row[col.field] : undefined, row)}
                        </span>
                      ) : (
                        formatCell(col, col.field ? row[col.field] : undefined, row)
                      )}
                    </td>
                    );
                  })}
                </tr>
              );
              })
            )}
          </tbody>
        </table>
      </div>
      {pagination && data.length > 0 && (
        <div className="border-t border-gray-200 bg-white">
          <Pagination
            currentPage={currentPage}
            totalCount={totalCount || data.length}
            pageSize={pageSize}
            onPageChange={setCurrentPage}
            onPageSizeChange={(s) => { setPageSize(s); setCurrentPage(1); }}
          />
        </div>
      )}
    </div>
  );
}

// 외부에서 데이터를 제어하기 위한 헬퍼
export function getSelectedData(
  data: Record<string, unknown>[],
  selectedIndices: Set<number>
): Record<string, unknown>[] {
  return data.filter((_, i) => selectedIndices.has(i));
}
