import {
    ColumnDef,
    flexRender,
    getCoreRowModel,
    SortingState,
    useReactTable,
} from '@tanstack/react-table';
import { useTranslation } from 'react-i18next';
import { ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react';
import { Skeleton } from '@/components/ui/skeleton';
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { TablePaginationBar } from '@/components/explore/TablePaginationBar';
import { DEFAULT_TABLE_PAGE_SIZE } from '@/utils/tablePagination';

export interface ServerTableParams {
    offset?: number;
    limit?: number;
    sort?: string;
    order?: 'asc' | 'desc';
}

interface DataTableProps<TData, TParams extends ServerTableParams> {
    columns: ColumnDef<TData, unknown>[];
    data: TData[];
    total?: number;
    isLoading?: boolean;
    tableKey: string;
    params: TParams;
    onParamsChange: (params: TParams) => void;
    emptyMessage?: string;
}

export function DataTable<TData, TParams extends ServerTableParams>({
    columns,
    data,
    total,
    isLoading,
    tableKey,
    params,
    onParamsChange,
    emptyMessage,
}: DataTableProps<TData, TParams>) {
    const { t } = useTranslation();
    const empty = emptyMessage ?? t('common.noData');
    const sorting: SortingState =
        params.sort && params.order ? [{ id: params.sort, desc: params.order === 'desc' }] : [];

    const table = useReactTable({
        data,
        columns,
        pageCount: total != null ? Math.ceil(total / (params.limit || DEFAULT_TABLE_PAGE_SIZE)) : -1,
        state: {
            sorting,
            pagination: {
                pageIndex: Math.floor((params.offset || 0) / (params.limit || DEFAULT_TABLE_PAGE_SIZE)),
                pageSize: params.limit || DEFAULT_TABLE_PAGE_SIZE,
            },
        },
        manualPagination: true,
        manualSorting: true,
        getCoreRowModel: getCoreRowModel(),
        onSortingChange: (updater) => {
            const next = typeof updater === 'function' ? updater(sorting) : updater;
            const first = next[0];
            onParamsChange({
                ...params,
                sort: first?.id ?? params.sort,
                order: first ? (first.desc ? 'desc' : 'asc') : params.order,
                offset: 0,
            });
        },
    });

    return (
        <div className="space-y-3">
            <div className="rounded-md border">
                <Table>
                    <TableHeader>
                        {table.getHeaderGroups().map((headerGroup) => (
                            <TableRow key={headerGroup.id}>
                                {headerGroup.headers.map((header) => {
                                    const canSort = header.column.getCanSort();
                                    const sorted = header.column.getIsSorted();
                                    return (
                                        <TableHead key={header.id} style={{ width: header.getSize() || undefined }}>
                                            {header.isPlaceholder ? null : canSort ? (
                                                <button
                                                    type="button"
                                                    className="inline-flex items-center gap-1 font-medium hover:text-foreground"
                                                    onClick={header.column.getToggleSortingHandler()}
                                                >
                                                    {flexRender(header.column.columnDef.header, header.getContext())}
                                                    {sorted === 'asc' ? (
                                                        <ArrowUp className="h-3.5 w-3.5" />
                                                    ) : sorted === 'desc' ? (
                                                        <ArrowDown className="h-3.5 w-3.5" />
                                                    ) : (
                                                        <ArrowUpDown className="h-3.5 w-3.5 opacity-40" />
                                                    )}
                                                </button>
                                            ) : (
                                                flexRender(header.column.columnDef.header, header.getContext())
                                            )}
                                        </TableHead>
                                    );
                                })}
                            </TableRow>
                        ))}
                    </TableHeader>
                    <TableBody>
                        {isLoading ? (
                            Array.from({ length: 5 }).map((_, i) => (
                                <TableRow key={`sk-${i}`}>
                                    {columns.map((_, j) => (
                                        <TableCell key={j}>
                                            <Skeleton className="h-4 w-full" />
                                        </TableCell>
                                    ))}
                                </TableRow>
                            ))
                        ) : table.getRowModel().rows.length ? (
                            table.getRowModel().rows.map((row) => (
                                <TableRow key={row.id}>
                                    {row.getVisibleCells().map((cell) => (
                                        <TableCell key={cell.id}>
                                            {flexRender(cell.column.columnDef.cell, cell.getContext())}
                                        </TableCell>
                                    ))}
                                </TableRow>
                            ))
                        ) : (
                            <TableRow>
                                <TableCell colSpan={columns.length} className="h-24 text-center text-muted-foreground">
                                    {empty}
                                </TableCell>
                            </TableRow>
                        )}
                    </TableBody>
                </Table>
            </div>

            <TablePaginationBar
                tableKey={tableKey}
                params={params}
                total={total}
                dataLength={data.length}
                onParamsChange={onParamsChange}
            />
        </div>
    );
}
