import {
  forwardRef,
  useCallback,
  useMemo,
  useState,
  type HTMLAttributes,
  type ReactNode,
} from 'react'
import { cn } from '@/lib/utils'

// --- Types ---

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

export interface DataTableProps<T = Record<string, unknown>> extends Omit<HTMLAttributes<HTMLDivElement>, 'children'> {
  columns: DataTableColumn<T>[]
  data: T[]
  selectable?: boolean
  pagination?: boolean
  pageSize?: number
  pageSizeOptions?: number[]
  loading?: boolean
  emptyMessage?: string
  onSelectionChange?: (selected: T[]) => void
}

type SortState = { key: string; dir: 'asc' | 'desc' } | null

const ChevronUpIcon = () => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" className="size-4">
    <path d="m18 15-6-6-6 6" />
  </svg>
)

const ChevronDownIcon = () => (
  <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} strokeLinecap="round" strokeLinejoin="round" className="size-4">
    <path d="m6 9 6 6 6-6" />
  </svg>
)

// --- DataTable ---

function DataTableInner<T extends Record<string, unknown>>(
  {
    columns,
    data,
    selectable = false,
    pagination = true,
    pageSize: initialPageSize = 5,
    pageSizeOptions = [5, 10, 25],
    loading = false,
    emptyMessage = 'No data available',
    onSelectionChange,
    className,
    ...props
  }: DataTableProps<T>,
  ref: React.ForwardedRef<HTMLDivElement>,
) {
  const [sort, setSort] = useState<SortState>(null)
  const [page, setPage] = useState(0)
  const [pageSize, setPageSize] = useState(initialPageSize)
  const [selected, setSelected] = useState<Set<number>>(new Set())

  const sortedData = useMemo(() => {
    if (!sort) return data
    const { key, dir } = sort
    return [...data].sort((a, b) => {
      const va = a[key]
      const vb = b[key]
      if (va == null && vb == null) return 0
      if (va == null) return 1
      if (vb == null) return -1
      const cmp = String(va).localeCompare(String(vb), undefined, { numeric: true })
      return dir === 'asc' ? cmp : -cmp
    })
  }, [data, sort])

  const pageCount = pagination ? Math.max(1, Math.ceil(sortedData.length / pageSize)) : 1
  const pageData = pagination ? sortedData.slice(page * pageSize, (page + 1) * pageSize) : sortedData
  const rangeStart = page * pageSize + 1
  const rangeEnd = Math.min((page + 1) * pageSize, sortedData.length)

  const toggleSort = useCallback((key: string) => {
    setSort((prev) => {
      if (prev?.key === key) {
        return prev.dir === 'asc' ? { key, dir: 'desc' } : null
      }
      return { key, dir: 'asc' }
    })
  }, [])

  const toggleRow = useCallback(
    (index: number) => {
      setSelected((prev) => {
        const next = new Set(prev)
        if (next.has(index)) next.delete(index)
        else next.add(index)
        onSelectionChange?.(
          [...next].map((i) => sortedData[i]).filter(Boolean),
        )
        return next
      })
    },
    [sortedData, onSelectionChange],
  )

  const toggleAll = useCallback(() => {
    setSelected((prev) => {
      if (prev.size === sortedData.length) {
        onSelectionChange?.([])
        return new Set()
      }
      const all = new Set(sortedData.map((_, i) => i))
      onSelectionChange?.([...sortedData])
      return all
    })
  }, [sortedData, onSelectionChange])

  return (
    <div ref={ref} className={cn('overflow-hidden rounded-default bg-surface', className)} {...props}>
      <div className="overflow-x-auto">
        <table className="w-full text-left text-body">
          <thead>
            <tr className="border-b border-border">
              {selectable && (
                <th className="w-12 px-4 py-3">
                  <input
                    type="checkbox"
                    checked={selected.size === sortedData.length && sortedData.length > 0}
                    onChange={toggleAll}
                    className="accent-primary"
                  />
                </th>
              )}
              {columns.map((col) => (
                <th
                  key={col.key}
                  className={cn(
                    'px-4 py-3 font-normal text-primary',
                    col.sortable && 'cursor-pointer select-none hover:bg-text/[0.04]',
                    col.align === 'right' && 'text-right',
                    col.align === 'center' && 'text-center',
                  )}
                  onClick={col.sortable ? () => toggleSort(col.key) : undefined}
                >
                  <span className="inline-flex items-center gap-1">
                    {col.header}
                    {col.sortable && sort?.key === col.key && (
                      sort.dir === 'asc' ? <ChevronUpIcon /> : <ChevronDownIcon />
                    )}
                  </span>
                </th>
              ))}
            </tr>
          </thead>
          <tbody>
            {loading ? (
              <tr>
                <td colSpan={columns.length + (selectable ? 1 : 0)} className="px-4 py-8 text-center text-text-secondary">
                  Loading…
                </td>
              </tr>
            ) : pageData.length === 0 ? (
              <tr>
                <td colSpan={columns.length + (selectable ? 1 : 0)} className="px-4 py-8 text-center text-text-secondary">
                  {emptyMessage}
                </td>
              </tr>
            ) : (
              pageData.map((row, rowIdx) => {
                const globalIdx = page * pageSize + rowIdx
                return (
                  <tr
                    key={globalIdx}
                    className={cn(
                      'border-b border-border last:border-b-0 transition-colors',
                      selected.has(globalIdx) ? 'bg-info/5' : 'hover:bg-text/[0.02]',
                    )}
                  >
                    {selectable && (
                      <td className="w-12 px-4 py-3">
                        <input
                          type="checkbox"
                          checked={selected.has(globalIdx)}
                          onChange={() => toggleRow(globalIdx)}
                          className="accent-primary"
                        />
                      </td>
                    )}
                    {columns.map((col) => (
                      <td
                        key={col.key}
                        className={cn(
                          'px-4 py-3',
                          col.align === 'right' && 'text-right',
                          col.align === 'center' && 'text-center',
                        )}
                      >
                        {col.render
                          ? col.render(row[col.key], row, globalIdx)
                          : String(row[col.key] ?? '')}
                      </td>
                    ))}
                  </tr>
                )
              })
            )}
          </tbody>
        </table>
      </div>

      {pagination && sortedData.length > 0 && (
        <div className="flex items-center justify-end gap-4 border-t border-border px-4 py-2 text-small text-text-secondary">
          <label className="flex items-center gap-2">
            Rows per page:
            <select
              value={pageSize}
              onChange={(e) => {
                setPageSize(Number(e.target.value))
                setPage(0)
              }}
              className="rounded-sm border border-border bg-surface px-2 py-1 text-small text-text"
            >
              {pageSizeOptions.map((opt) => (
                <option key={opt} value={opt}>{opt}</option>
              ))}
            </select>
          </label>
          <span>{rangeStart}-{rangeEnd} of {sortedData.length}</span>
          <div className="flex gap-1">
            <button
              type="button"
              disabled={page === 0}
              onClick={() => setPage(0)}
              className="rounded-sm p-1 hover:bg-text/[0.04] disabled:opacity-40"
              aria-label="First page"
            >
              <svg viewBox="0 0 24 24" fill="currentColor" className="size-5"><path d="M18.41 16.59L13.82 12l4.59-4.59L17 6l-6 6 6 6zM6 6h2v12H6z" /></svg>
            </button>
            <button
              type="button"
              disabled={page === 0}
              onClick={() => setPage((p) => p - 1)}
              className="rounded-sm p-1 hover:bg-text/[0.04] disabled:opacity-40"
              aria-label="Previous page"
            >
              <svg viewBox="0 0 24 24" fill="currentColor" className="size-5"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z" /></svg>
            </button>
            <button
              type="button"
              disabled={page >= pageCount - 1}
              onClick={() => setPage((p) => p + 1)}
              className="rounded-sm p-1 hover:bg-text/[0.04] disabled:opacity-40"
              aria-label="Next page"
            >
              <svg viewBox="0 0 24 24" fill="currentColor" className="size-5"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z" /></svg>
            </button>
            <button
              type="button"
              disabled={page >= pageCount - 1}
              onClick={() => setPage(pageCount - 1)}
              className="rounded-sm p-1 hover:bg-text/[0.04] disabled:opacity-40"
              aria-label="Last page"
            >
              <svg viewBox="0 0 24 24" fill="currentColor" className="size-5"><path d="M5.59 7.41L10.18 12l-4.59 4.59L7 18l6-6-6-6zM16 6h2v12h-2z" /></svg>
            </button>
          </div>
        </div>
      )}
    </div>
  )
}

export const DataTable = forwardRef(DataTableInner) as <T extends Record<string, unknown>>(
  props: DataTableProps<T> & { ref?: React.Ref<HTMLDivElement> },
) => React.ReactElement | null
