import { ReactNode, useEffect, useState, useMemo, useRef } from 'react';
import { Table, TableBody, TableCell, TableHead, TableHeader, TableRow } from '@/components/ui/table';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { ChevronLeft, ChevronRight, ArrowUpDown, ArrowUp, ArrowDown, Search } from 'lucide-react';
import { EmptyState } from './EmptyState';
import { Skeleton } from '@/components/ui/skeleton';
import { Checkbox } from '@/components/ui/checkbox';
import { searchFieldClassName } from './searchFieldStyles';
import { computeTableMinWidth } from '@/lib/tableLayout';

export interface Column<T> {
  key: string;
  label: string;
  sortable?: boolean;
  truncate?: boolean;
  nowrap?: boolean;
  className?: string;
  defaultWidth?: number;
  render?: (value: unknown, row: T) => ReactNode;
}

interface DataTableProps<T> {
  columns: Column<T>[];
  data: T[];
  loading?: boolean;
  onRowClick?: (row: T) => void;
  rowKey?: (row: T) => string;
  searchValue?: string;
  onSearchChange?: (value: string) => void;
  searchPlaceholder?: string;
  selectable?: boolean;
  selectedKeys?: Set<string>;
  onSelectionChange?: (keys: Set<string>) => void;
  showRowIndex?: boolean;
  fillAvailableWidth?: boolean;
}

export function DataTable<T extends object>({
  columns, data, loading, onRowClick, rowKey,
  searchValue, onSearchChange, searchPlaceholder = '搜索...',
  selectable, selectedKeys, onSelectionChange, showRowIndex, fillAvailableWidth,
}: DataTableProps<T>) {
  // 行内字段按 column.key 动态访问，需要 string-index 视图。
  const rowAsRecord = (row: T): Record<string, unknown> => row as Record<string, unknown>;
  const [sortKey, setSortKey] = useState<string | null>(null);
  const [sortDir, setSortDir] = useState<'asc' | 'desc'>('asc');
  const [page, setPage] = useState(1);
  const [pageSize, setPageSize] = useState(20);
  const [hoveredCol, setHoveredCol] = useState<string | null>(null);
  const [resizingCol, setResizingCol] = useState<string | null>(null);
  const [colWidths, setColWidths] = useState<Record<string, number>>(() =>
    Object.fromEntries(columns.map(col => [col.key, col.defaultWidth ?? 120]))
  );
  const resizingRef = useRef<{ key: string; startX: number; startWidth: number } | null>(null);
  const justResizedRef = useRef(false);

  useEffect(() => {
    setColWidths(prev => {
      const next = Object.fromEntries(columns.map(col => [col.key, prev[col.key] ?? col.defaultWidth ?? 120]));
      const prevKeys = Object.keys(prev);
      const nextKeys = Object.keys(next);

      if (prevKeys.length === nextKeys.length && nextKeys.every(key => prev[key] === next[key])) {
        return prev;
      }

      return next;
    });
  }, [columns]);

  const getSortableValue = (value: unknown) => {
    if (typeof value === 'number') return value;
    if (typeof value !== 'string') return value;

    const trimmed = value.trim();
    const numericCandidate = trimmed.replace(/[^\d.-]/g, '');

    if (numericCandidate && /^-?\d+(?:\.\d+)?$/.test(numericCandidate)) {
      return Number(numericCandidate);
    }

    return trimmed;
  };

  function beginResize(key: string, startX: number) {
    justResizedRef.current = false;
    setResizingCol(key);
    resizingRef.current = { key, startX, startWidth: colWidths[key] ?? 120 };
    const previousCursor = document.body.style.cursor;
    const previousUserSelect = document.body.style.userSelect;
    document.body.style.cursor = 'col-resize';
    document.body.style.userSelect = 'none';

    function onMouseMove(ev: MouseEvent) {
      if (!resizingRef.current) return;
      justResizedRef.current = true;
      const newWidth = Math.max(40, resizingRef.current.startWidth + ev.clientX - resizingRef.current.startX);
      setColWidths(prev => ({ ...prev, [resizingRef.current!.key]: newWidth }));
    }

    function onMouseUp() {
      resizingRef.current = null;
      setResizingCol(null);
      document.body.style.cursor = previousCursor;
      document.body.style.userSelect = previousUserSelect;
      document.removeEventListener('mousemove', onMouseMove);
      document.removeEventListener('mouseup', onMouseUp);
    }

    document.addEventListener('mousemove', onMouseMove);
    document.addEventListener('mouseup', onMouseUp);
  }

  function startResize(key: string, e: React.MouseEvent) {
    e.preventDefault();
    e.stopPropagation();
    beginResize(key, e.clientX);
  }

  function isResizeEdgeHit(element: HTMLElement, clientX: number) {
    const rect = element.getBoundingClientRect();
    return rect.right - clientX <= 12;
  }

  const sorted = useMemo(() => {
    if (!sortKey) return data;
    return [...data].sort((a, b) => {
      const va = getSortableValue(rowAsRecord(a)[sortKey]);
      const vb = getSortableValue(rowAsRecord(b)[sortKey]);
      if (va == null) return 1;
      if (vb == null) return -1;
      const cmp =
        typeof va === 'number' && typeof vb === 'number'
          ? va - vb
          : String(va).localeCompare(String(vb));
      return sortDir === 'asc' ? cmp : -cmp;
    });
  }, [data, sortKey, sortDir]);

  const totalPages = Math.max(1, Math.ceil(sorted.length / pageSize));
  const safePage = Math.min(page, totalPages);
  const paged = sorted.slice((safePage - 1) * pageSize, safePage * pageSize);

  const totalMinWidth = useMemo(() => {
    return computeTableMinWidth({
      columnKeys: columns.map(col => col.key),
      widths: colWidths,
      fallbackWidth: 120,
      fixedWidths: [selectable ? 40 : 0, showRowIndex ? 56 : 0, colWidths._actions ?? 80],
      ignoredKeys: ['_actions'],
    });
  }, [selectable, showRowIndex, columns, colWidths]);

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

  if (loading) {
    return (
      <div className="space-y-3">
        {Array.from({ length: 5 }).map((_, i) => (
          <Skeleton key={i} className="h-10 w-full" />
        ))}
      </div>
    );
  }

  return (
    <div className="h-full flex flex-col">
      {onSearchChange !== undefined && (
        <div className="mb-3 shrink-0">
          <div className="relative w-64">
            <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 h-4 w-4 text-muted-foreground pointer-events-none" />
            <Input
              placeholder={searchPlaceholder}
              value={searchValue ?? ''}
              onChange={e => onSearchChange(e.target.value)}
              className={`${searchFieldClassName} pl-8`}
            />
          </div>
        </div>
      )}
      {data.length === 0 ? (
        <div className="flex-1 flex items-center justify-center"><EmptyState /></div>
      ) : (
        <>
        <div className="flex-1 min-h-0 overflow-auto rounded-lg border border-border [&_th]:h-8 [&_th]:py-0 [&_th]:px-3 [&_td]:py-1.5 [&_td]:px-3">
        <Table className="w-max min-w-full" style={{ tableLayout: 'auto', minWidth: totalMinWidth }}>
          <TableHeader className="sticky top-0 z-10">
            <TableRow className="bg-gray-100 hover:bg-gray-100 border-b border-border">
              {selectable && (
                <TableHead style={{ width: 40 }} className="sticky left-0 z-20 bg-gray-100">
                  <Checkbox
                    checked={paged.length > 0 && paged.every(row => selectedKeys?.has(rowKey ? rowKey(row) : String(paged.indexOf(row))))}
                    onCheckedChange={checked => {
                      if (!onSelectionChange) return;
                      const next = new Set(selectedKeys);
                      paged.forEach((row, i) => {
                        const k = rowKey ? rowKey(row) : String((safePage - 1) * pageSize + i);
                        if (checked) {
                          next.add(k);
                        } else {
                          next.delete(k);
                        }
                      });
                      onSelectionChange(next);
                    }}
                    aria-label="全选当前页"
                  />
                </TableHead>
              )}
              {showRowIndex && (
                <TableHead style={selectable ? { width: 56, left: 40 } : { width: 56, left: 0 }} className="text-xs font-semibold text-center sticky z-20 bg-gray-100">序号</TableHead>
              )}
              {columns.filter(col => col.key !== '_actions').map(col => (
                <TableHead
                  key={col.key}
                  style={{ width: colWidths[col.key] }}
                  className={`text-xs font-semibold relative ${col.className || ''} ${col.sortable ? 'cursor-pointer select-none' : ''}`}
                  onClick={() => {
                    if (justResizedRef.current) {
                      justResizedRef.current = false;
                      return;
                    }

                    if (col.sortable) {
                      handleSort(col.key);
                    }
                  }}
                  onMouseDown={e => {
                    if (isResizeEdgeHit(e.currentTarget, e.clientX)) {
                      startResize(col.key, e);
                    }
                  }}
                  onMouseEnter={() => setHoveredCol(col.key)}
                  onMouseLeave={() => setHoveredCol(null)}
                >
                  <span className="flex items-center gap-1 overflow-hidden">
                    <span className="truncate whitespace-nowrap">{col.label}</span>
                    {col.sortable && (
                      sortKey === col.key
                        ? (sortDir === 'asc' ? <ArrowUp className="h-3 w-3 shrink-0" /> : <ArrowDown className="h-3 w-3 shrink-0" />)
                        : <ArrowUpDown className="h-3 w-3 opacity-30 shrink-0" />
                    )}
                  </span>
                  <div
                    role="separator"
                    aria-orientation="vertical"
                    aria-label={`调整${col.label}列宽`}
                    className="absolute right-0 top-0 z-30 flex h-full w-4 translate-x-1/2 items-center justify-center cursor-col-resize"
                    onMouseDown={e => startResize(col.key, e)}
                    onMouseEnter={() => setHoveredCol(col.key)}
                  >
                    <div className={`h-4 w-0.5 rounded-full transition-colors ${(hoveredCol === col.key || resizingCol === col.key) ? 'bg-primary' : 'bg-primary/0 hover:bg-primary/60'}`} />
                  </div>
                </TableHead>
              ))}
              {!fillAvailableWidth && (
                <TableHead style={{ width: 'auto' }} />
              )}
              {columns.find(col => col.key === '_actions') && (
                <TableHead
                  style={{ width: colWidths['_actions'] ?? 80, right: 0 }}
                  className="text-xs font-semibold sticky right-0 z-20 bg-gray-100 shadow-[-2px_0_4px_-1px_rgba(0,0,0,0.08)] text-center"
                >
                  <span className="truncate whitespace-nowrap">操作</span>
                </TableHead>
              )}
            </TableRow>
          </TableHeader>
          <TableBody>
            {paged.map((row, i) => {
              const rowId = rowKey ? rowKey(row) : String((safePage - 1) * pageSize + i);
              const isSelected = selectedKeys?.has(rowId) ?? false;
              const stickyCellBgClass = isSelected
                ? 'bg-blue-50 group-hover:bg-blue-100'
                : 'bg-white group-hover:bg-blue-100';
              return (
              <TableRow
                key={rowId}
                className={`group border-b border-border last:border-0 transition-colors hover:bg-blue-100 ${i % 2 === 1 ? 'bg-muted/20' : ''} ${onRowClick ? 'cursor-pointer' : ''} ${isSelected ? 'bg-blue-50' : ''}`}
                onClick={() => onRowClick?.(row)}
              >
                {selectable && (
                  <TableCell className={`w-10 sticky left-0 z-[5] ${stickyCellBgClass}`} onClick={e => e.stopPropagation()}>
                    <Checkbox
                      checked={isSelected}
                      onCheckedChange={checked => {
                        if (!onSelectionChange) return;
                        const next = new Set(selectedKeys);
                        if (checked) {
                          next.add(rowId);
                        } else {
                          next.delete(rowId);
                        }
                        onSelectionChange(next);
                      }}
                      aria-label="选择行"
                    />
                  </TableCell>
                )}
                {showRowIndex && (
                  <TableCell style={selectable ? { left: 40 } : { left: 0 }} className={`w-14 text-muted-foreground text-sm text-center sticky z-[4] ${stickyCellBgClass}`}>
                    {(safePage - 1) * pageSize + i + 1}
                  </TableCell>
                )}
                {columns.filter(col => col.key !== '_actions').map(col => {
                  const val = rowAsRecord(row)[col.key];
                  // col.render 已声明返回 ReactNode；无 render 时 val 是 unknown，
                  // 仅当其为 string/number/null/undefined 等可渲染原型才会进入 else 分支。
                  const rendered: ReactNode = col.render ? col.render(val, row) : (val as ReactNode);
                  let cell: ReactNode;
                  if (col.nowrap) {
                    cell = typeof rendered === 'string' || typeof rendered === 'number'
                      ? <span className="whitespace-nowrap">{rendered}</span>
                      : rendered;
                  } else if (col.truncate && typeof rendered === 'string' && rendered.length > 30) {
                    cell = (
                      <Tooltip>
                        <TooltipTrigger asChild>
                          <span className="block truncate whitespace-nowrap">{rendered}</span>
                        </TooltipTrigger>
                        <TooltipContent className="max-w-sm">
                          <p className="text-xs whitespace-pre-wrap">{rendered}</p>
                        </TooltipContent>
                      </Tooltip>
                    );
                  } else if (typeof rendered === 'string' || typeof rendered === 'number') {
                    cell = <span className="block truncate whitespace-nowrap">{rendered}</span>;
                  } else {
                    cell = rendered;
                  }
                  return (
                    <TableCell key={col.key} className={`text-sm ${col.nowrap ? 'whitespace-nowrap' : 'overflow-hidden max-w-0'} ${col.className || ''}`}>
                      {cell}
                    </TableCell>
                  );
                })}
                {!fillAvailableWidth && (
                  <TableCell style={{ padding: 0 }} />
                )}
                {(() => {
                  const actCol = columns.find(col => col.key === '_actions');
                  if (!actCol) return null;
                  const rendered = actCol.render ? actCol.render(rowAsRecord(row)['_actions'], row) : null;
                  return (
                    <TableCell
                      style={{ width: colWidths['_actions'] ?? 80, minWidth: colWidths['_actions'] ?? 80 }}
                      className={`sticky right-0 z-[2] ${stickyCellBgClass} shadow-[-2px_0_4px_-1px_rgba(0,0,0,0.08)] group-hover:shadow-[-8px_0_20px_rgba(0,0,0,0.14)] group-hover:z-[3] transition-shadow duration-200`}
                      onClick={e => e.stopPropagation()}
                    >
                      {rendered}
                    </TableCell>
                  );
                })()}
              </TableRow>
              );
            })}
          </TableBody>
        </Table>
      </div>
      <div className="shrink-0 flex items-center justify-between mt-3 text-sm text-muted-foreground">
        <div className="flex items-center gap-2">
          <span>每页</span>
          <Select value={String(pageSize)} onValueChange={v => { setPageSize(Number(v)); setPage(1); }}>
            <SelectTrigger className="w-[70px] h-8">
              <SelectValue />
            </SelectTrigger>
            <SelectContent>
              <SelectItem value="20">20</SelectItem>
              <SelectItem value="50">50</SelectItem>
              <SelectItem value="100">100</SelectItem>
            </SelectContent>
          </Select>
          <span>条，共 {sorted.length} 条</span>
        </div>
        <div className="flex items-center gap-1">
          <Button variant="outline" size="icon" className="h-8 w-8" disabled={safePage <= 1} onClick={() => setPage(safePage - 1)}>
            <ChevronLeft className="h-4 w-4" />
          </Button>
          <span className="px-2">{safePage} / {totalPages}</span>
          <Button variant="outline" size="icon" className="h-8 w-8" disabled={safePage >= totalPages} onClick={() => setPage(safePage + 1)}>
            <ChevronRight className="h-4 w-4" />
          </Button>
        </div>
      </div>
      </>
      )}
    </div>
  );
}
