import { useMemo, useState, type ReactNode } from 'react';
import { cn } from '../lib/cn';

export type SortDir = 'asc' | 'desc';

export interface DataTableColumn<T = Record<string, unknown>> {
  key: string;
  label: ReactNode;
  sortable?: boolean;
  align?: 'left' | 'right' | 'center';
  width?: string;
  render?: (row: T) => ReactNode;
}

export interface DataTableProps<T = Record<string, unknown>> {
  columns: DataTableColumn<T>[];
  data: T[];
  rowKey?: (row: T, index: number) => string;
  selectedKeys?: string[];
  onSelect?: (keys: string[]) => void;
  onSort?: (key: string, dir: SortDir) => void;
  pageSize?: number;
  className?: string;
  empty?: ReactNode;
}

export function DataTable<T extends Record<string, unknown>>({
  columns,
  data,
  rowKey,
  selectedKeys,
  onSelect,
  onSort,
  pageSize = 10,
  className,
  empty = 'No data',
}: DataTableProps<T>) {
  const [sort, setSort] = useState<{ key: string; dir: SortDir } | null>(null);
  const [page, setPage] = useState(1);

  const sorted = useMemo(() => {
    if (!sort) return data;
    const col = columns.find((c) => c.key === sort.key);
    if (!col) return data;
    const copy = [...data];
    copy.sort((a, b) => {
      const av = a[sort.key];
      const bv = b[sort.key];
      if (av === bv) return 0;
      const cmp = (av as number | string) > (bv as number | string) ? 1 : -1;
      return sort.dir === 'asc' ? cmp : -cmp;
    });
    return copy;
  }, [data, sort, columns]);

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

  const getKey = (row: T, i: number) =>
    rowKey ? rowKey(row, i) : String((row as Record<string, unknown>).id ?? i);

  const allSelected = selectedKeys && pageData.length > 0 &&
    pageData.every((row, i) => selectedKeys.includes(getKey(row, i)));

  const handleSort = (key: string) => {
    const col = columns.find((c) => c.key === key);
    if (!col?.sortable) return;
    const nextDir: SortDir = sort?.key === key && sort.dir === 'asc' ? 'desc' : 'asc';
    setSort({ key, dir: nextDir });
    onSort?.(key, nextDir);
  };

  const toggleRow = (k: string) => {
    if (!onSelect || !selectedKeys) return;
    onSelect(
      selectedKeys.includes(k)
        ? selectedKeys.filter((x) => x !== k)
        : [...selectedKeys, k]
    );
  };

  const toggleAll = () => {
    if (!onSelect || !selectedKeys) return;
    const pageKeys = pageData.map((row, i) => getKey(row, i));
    onSelect(allSelected ? selectedKeys.filter((k) => !pageKeys.includes(k)) : Array.from(new Set([...selectedKeys, ...pageKeys])));
  };

  return (
    <div className={cn('w-full', className)}>
      <div className="overflow-x-auto rounded-xl border border-border bg-surface">
        <table className="w-full text-sm">
          <thead className="bg-surface-2 border-b border-border">
            <tr>
              {selectedKeys && (
                <th className="w-10 px-4 py-3">
                  <input
                    type="checkbox"
                    aria-label="Select all"
                    checked={!!allSelected}
                    onChange={toggleAll}
                    className="h-4 w-4 rounded border-border accent-primary"
                  />
                </th>
              )}
              {columns.map((col) => {
                const isSorted = sort?.key === col.key;
                return (
                  <th
                    key={col.key}
                    style={{ width: col.width }}
                    className={cn(
                      'px-4 py-3 text-xs font-medium uppercase tracking-wider text-text-3',
                      col.align === 'right' && 'text-right',
                      col.align === 'center' && 'text-center',
                      col.align !== 'right' && col.align !== 'center' && 'text-left'
                    )}
                  >
                    {col.sortable ? (
                      <button
                        type="button"
                        onClick={() => handleSort(col.key)}
                        className="inline-flex items-center gap-1 hover:text-text-2 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-ring rounded"
                      >
                        {col.label}
                        <span className="text-text-3">
                          {isSorted ? (sort!.dir === 'asc' ? '↑' : '↓') : '↕'}
                        </span>
                      </button>
                    ) : (
                      col.label
                    )}
                  </th>
                );
              })}
            </tr>
          </thead>
          <tbody>
            {pageData.length === 0 ? (
              <tr>
                <td
                  colSpan={columns.length + (selectedKeys ? 1 : 0)}
                  className="px-4 py-12 text-center text-text-3"
                >
                  {empty}
                </td>
              </tr>
            ) : (
              pageData.map((row, i) => {
                const k = getKey(row, i);
                const isSelected = selectedKeys?.includes(k);
                return (
                  <tr
                    key={k}
                    className={cn(
                      'border-b border-border last:border-0 transition-colors',
                      isSelected ? 'bg-primary-soft' : 'hover:bg-surface-2'
                    )}
                  >
                    {selectedKeys && (
                      <td className="px-4 py-3">
                        <input
                          type="checkbox"
                          aria-label={`Select row ${i + 1}`}
                          checked={!!isSelected}
                          onChange={() => toggleRow(k)}
                          className="h-4 w-4 rounded border-border accent-primary"
                        />
                      </td>
                    )}
                    {columns.map((col) => (
                      <td
                        key={col.key}
                        className={cn(
                          'px-4 py-3 text-text-2',
                          col.align === 'right' && 'text-right tab-num',
                          col.align === 'center' && 'text-center'
                        )}
                      >
                        {col.render ? col.render(row) : (row[col.key] as ReactNode)}
                      </td>
                    ))}
                  </tr>
                );
              })
            )}
          </tbody>
        </table>
      </div>

      {sorted.length > pageSize && (
        <div className="mt-3 flex items-center justify-between text-sm text-text-3">
          <span>
            Showing {(currentPage - 1) * pageSize + 1}–{Math.min(currentPage * pageSize, sorted.length)} of {sorted.length}
          </span>
          <div className="flex items-center gap-2">
            <button
              type="button"
              onClick={() => setPage((p) => Math.max(1, p - 1))}
              disabled={currentPage <= 1}
              className="inline-flex h-8 px-3 items-center rounded-md border border-border bg-surface text-text-2 hover:bg-surface-2 disabled:opacity-40 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-ring"
            >
              Prev
            </button>
            <span className="tab-num">
              {currentPage} / {totalPages}
            </span>
            <button
              type="button"
              onClick={() => setPage((p) => Math.min(totalPages, p + 1))}
              disabled={currentPage >= totalPages}
              className="inline-flex h-8 px-3 items-center rounded-md border border-border bg-surface text-text-2 hover:bg-surface-2 disabled:opacity-40 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary-ring"
            >
              Next
            </button>
          </div>
        </div>
      )}
    </div>
  );
}
