import {
  type AccessorKeyColumnDef,
  type Column,
  type ColumnDef,
  flexRender,
  getCoreRowModel,
  useReactTable,
} from "@tanstack/react-table"
import { Loader } from "lucide-react"
import type { CSSProperties } from "react"
import { Pagination, type PaginationProps } from "@/components/ui/pagination"
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  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
  }
  serial?: boolean
}

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

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

  return (
    <div
      className={cn("flex-auto flex flex-col gap-3", props.classNames?.root)}
    >
      {/* 数据表 */}
      <div className="flex-auto overflow-hidden relative">
        <Table className="max-w-full max-h-full">
          <TableHeader>
            {table.getHeaderGroups().map(group => (
              <TableRow key={group.id}>
                {group.headers.map(header => (
                  <TableHead
                    key={header.id}
                    colSpan={header.colSpan}
                    className="sticky top-0 bg-card z-20 shadow-[inset_0_-1px_var(--border)]"
                    style={pinStyle(header.column, true)}
                  >
                    {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}
                      className="sticky bg-card z-10"
                      style={pinStyle(cell.column)}
                    >
                      {flexRender(
                        cell.column.columnDef.cell,
                        cell.getContext(),
                      )}
                    </TableCell>
                  ))}
                </TableRow>
              ))
            )}
          </TableBody>
        </Table>
        {props.status === "load" && (
          <div className="absolute inset-0 bg-white/10 backdrop-blur-xs flex items-center justify-center gap-2 transition z-50">
            <Loader className="animate-spin" />
            <span>加载中</span>
          </div>
        )}
      </div>

      {/* 分页器 */}
      {props.pagination && (
        <Pagination {...props.pagination} className="flex-none self-center" />
      )}
    </div>
  )
}
