import {
  type Column,
  type ColumnDef,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table"
import { Loader } from "lucide-react"
import { type CSSProperties, useCallback, useMemo } from "react"
import { Pagination, type PaginationProps } from "@/components/ui/pagination"
import {
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  Table as TableRoot,
  TableRow,
} from "@/components/ui/table"
import { cn } from "@/lib/utils"

export type DataTableProps<T> = {
  data: T[]
  status: "load" | "done" | "fail"
  columns: ColumnDef<T>[]
  pagination: PaginationProps
  classNames?: {
    root?: string
    headRow?: string
    dataRow?: string
  }
}

export function DataTable<T extends Record<string, unknown>>(
  props: DataTableProps<T>,
) {
  const table = useReactTable({
    data: props.data,
    columns: props.columns,
    getCoreRowModel: getCoreRowModel(),
    manualPagination: true,
    rowCount: props.pagination.total,
    state: {
      pagination: {
        pageIndex: props.pagination.page,
        pageSize: props.pagination.size,
      },
      columnFilters: [],
    },
    initialState: {
      columnPinning: {
        left: props.columns
          .map(column =>
            column.meta?.pin === "left"
              ? column.id || column.accessorKey
              : undefined,
          )
          .filter(Boolean),
        right: props.columns
          .map(column =>
            column.meta?.pin === "right"
              ? column.id || column.accessorKey
              : undefined,
          )
          .filter(Boolean),
      },
    },
  })

  const pinStyle = (column: Column<T>) => {
    const pinned = column.getIsPinned()
    if (!pinned) return {}
    return {
      position: pinned ? ("sticky" as const) : undefined,
      backgroundColor: "white",
      zIndex: 1,
      ...{
        left: {
          left: column.getStart(pinned),
          boxShadow: "inset 1px 0 var(--border)",
        },
        right: {
          right: column.getAfter(pinned),
          boxShadow: "inset 1px 0 var(--border)",
        },
      }[pinned],
    } as CSSProperties
  }

  return (
    <div className={cn("flex flex-col gap-3", props.classNames?.root)}>
      {/* 数据表 */}
      <div className="rounded-md relative bg-card">
        <TableRoot>
          <TableHeader>
            {table.getHeaderGroups().map(group => (
              <TableRow key={group.id}>
                {group.headers.map(header => (
                  <TableHead
                    key={header.id}
                    colSpan={header.colSpan}
                    style={pinStyle(header.column)}
                  >
                    {header.isPlaceholder
                      ? null
                      : flexRender(
                          header.column.columnDef.header,
                          header.getContext(),
                        )}
                  </TableHead>
                ))}
              </TableRow>
            ))}
          </TableHeader>
          <TableBody>
            {props.status === "fail" ? (
              <TableRow>
                <TableCell
                  colSpan={props.columns.length}
                  className="text-center text-fail"
                >
                  加载失败
                </TableCell>
              </TableRow>
            ) : !props.data?.length ? (
              <TableRow>
                <TableCell
                  colSpan={props.columns.length}
                  className="text-center"
                >
                  暂无数据
                </TableCell>
              </TableRow>
            ) : (
              table.getRowModel().rows.map(row => (
                <TableRow
                  key={row.id}
                  data-state={row.getIsSelected() && "selected"}
                  className={cn("h-14", props.classNames?.dataRow)}
                >
                  {row.getVisibleCells().map(cell => (
                    <TableCell key={cell.id} style={pinStyle(cell.column)}>
                      {flexRender(
                        cell.column.columnDef.cell,
                        cell.getContext(),
                      )}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            )}
          </TableBody>
        </TableRoot>
        {props.status === "load" && (
          <div className="absolute inset-0 bg-white/10 backdrop-blur-xs flex items-center justify-center gap-2 transition">
            <Loader className="animate-spin" />
            <span>加载中</span>
          </div>
        )}
      </div>

      {/* 分页器 */}
      <Pagination {...props.pagination} />
    </div>
  )
}
