import { Link } from '@inertiajs/react';
import {
    flexRender,
    getCoreRowModel,
    getFilteredRowModel,
    getPaginationRowModel,
    getSortedRowModel,
    createColumnHelper,
    useReactTable,
} from '@tanstack/react-table';
import { ArrowDown, ArrowUp, ArrowUpDown, Eye, MoreHorizontal, Pencil } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import {
    edit as currencyExchangeEdit,
    show as currencyExchangeShow,
} from '@/actions/App/Http/Controllers/CurrencyExchangeController';
import { Button } from '@/components/ui/button';
import {
    DropdownMenu,
    DropdownMenuContent,
    DropdownMenuItem,
    DropdownMenuSeparator,
    DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { Input } from '@/components/ui/input';
import { Label } from '@/components/ui/label';
import {
    Table,
    TableBody,
    TableCell,
    TableHead,
    TableHeader,
    TableRow,
} from '@/components/ui/table';
import { formatAppDateOrDash, formatMoneyAmountOrDash } from '@/lib/dates';
import { createHiddenIdColumn } from '@/lib/table-defaults';
import { cn } from '@/lib/utils';

const columnHelper = createColumnHelper();

function SortButton({ column, children, className }) {
    const sorted = column.getIsSorted();

    return (
        <Button
            type="button"
            variant="ghost"
            size="sm"
            className={cn('-ms-2 h-8 font-medium', className)}
            onClick={column.getToggleSortingHandler()}
        >
            {children}
            {sorted === 'asc' ? (
                <ArrowUp className="ms-1 size-4 opacity-70" />
            ) : sorted === 'desc' ? (
                <ArrowDown className="ms-1 size-4 opacity-70" />
            ) : (
                <ArrowUpDown className="text-muted-foreground ms-1 size-4 opacity-50" />
            )}
        </Button>
    );
}

function numericSort(rowA, rowB, columnId) {
    const a = Number(rowA.getValue(columnId)) || 0;
    const b = Number(rowB.getValue(columnId)) || 0;

    return a - b;
}

function MoneyCell({ amount, locale, maxDecimals = 2, currency, className }) {
    const formatted = formatMoneyAmountOrDash(amount, locale, maxDecimals);

    if (formatted === '—') {
        return <span className="text-muted-foreground">—</span>;
    }

    return (
        <div className="flex flex-col items-end gap-0.5">
            <span className={cn('font-medium tabular-nums', className)}>{formatted}</span>
            {currency ? (
                <span className="text-muted-foreground text-[10px] font-medium uppercase tracking-wide">
                    {currency}
                </span>
            ) : null}
        </div>
    );
}

/**
 * @param {object} props
 * @param {Array<object>} props.exchanges
 * @param {Record<string, string>} props.labels
 * @param {'en'|'fa'} [props.locale]
 * @param {boolean} [props.hideSarafColumn]
 * @param {boolean} [props.canView]
 * @param {boolean} [props.canUpdate]
 */
export function CurrencyExchangesDataTable({
    exchanges,
    labels,
    locale = 'en',
    hideSarafColumn = false,
    canView = true,
    canUpdate = false,
}) {
    const [sorting, setSorting] = useState([
        { id: 'exchange_date', desc: true },
        { id: 'id', desc: true },
    ]);
    const [columnVisibility, setColumnVisibility] = useState({ id: false });
    const [globalFilter, setGlobalFilter] = useState('');
    const [pagination, setPagination] = useState({
        pageIndex: 0,
        pageSize: 10,
    });

    useEffect(() => {
        setPagination((prev) => ({ ...prev, pageIndex: 0 }));
    }, [globalFilter, sorting]);

    const columns = useMemo(() => {
        const cols = [
            createHiddenIdColumn(columnHelper),
            columnHelper.display({
                id: 'serial',
                header: labels.colSerial,
                cell: ({ row, table }) => {
                    const { pageIndex, pageSize } = table.getState().pagination;
                    const serial = pageIndex * pageSize + row.index + 1;

                    return (
                        <span className="text-muted-foreground tabular-nums">{serial}</span>
                    );
                },
                enableSorting: false,
                enableGlobalFilter: false,
            }),
            columnHelper.accessor('exchange_date', {
                header: ({ column }) => (
                    <SortButton column={column}>{labels.colDate}</SortButton>
                ),
                cell: (info) => (
                    <span className="whitespace-nowrap font-medium">
                        {formatAppDateOrDash(info.getValue(), locale)}
                    </span>
                ),
                sortingFn: (rowA, rowB) => {
                    const dateCompare = String(rowA.original.exchange_date ?? '').localeCompare(
                        String(rowB.original.exchange_date ?? ''),
                    );

                    if (dateCompare !== 0) {
                        return dateCompare;
                    }

                    return (rowB.original.id ?? 0) - (rowA.original.id ?? 0);
                },
            }),
        ];

        if (!hideSarafColumn) {
            cols.push(
                columnHelper.accessor('saraf_name', {
                    header: ({ column }) => (
                        <SortButton column={column}>{labels.colSaraf}</SortButton>
                    ),
                    cell: (info) => (
                        <span className="font-medium">{info.getValue() || '—'}</span>
                    ),
                }),
            );
        }

        cols.push(
            columnHelper.accessor('total_afn', {
                header: ({ column }) => (
                    <div className="flex justify-end">
                        <SortButton column={column} className="me-0">
                            {labels.colTotalAfn}
                        </SortButton>
                    </div>
                ),
                cell: (info) => (
                    <MoneyCell
                        amount={info.getValue()}
                        locale={locale}
                        currency={labels.afnCurrencyLabel}
                    />
                ),
                sortingFn: numericSort,
            }),
            columnHelper.accessor('dollar_price', {
                header: ({ column }) => (
                    <div className="flex justify-end">
                        <SortButton column={column} className="me-0">
                            {labels.colDollarPrice}
                        </SortButton>
                    </div>
                ),
                cell: (info) => (
                    <MoneyCell
                        amount={info.getValue()}
                        locale={locale}
                        maxDecimals={4}
                        currency={labels.afnCurrencyLabel}
                    />
                ),
                sortingFn: numericSort,
            }),
            columnHelper.accessor('dollar_difference_price', {
                header: ({ column }) => (
                    <div className="flex justify-end">
                        <SortButton column={column} className="me-0">
                            {labels.colDollarDifference}
                        </SortButton>
                    </div>
                ),
                cell: (info) => {
                    const amount = info.getValue();
                    const numeric = Number(amount);

                    return (
                        <MoneyCell
                            amount={amount}
                            locale={locale}
                            maxDecimals={4}
                            currency={labels.afnCurrencyLabel}
                            className={cn(
                                Number.isFinite(numeric) && numeric < 0
                                    ? 'text-destructive'
                                    : Number.isFinite(numeric) && numeric > 0
                                      ? 'text-emerald-700 dark:text-emerald-400'
                                      : undefined,
                            )}
                        />
                    );
                },
                sortingFn: numericSort,
            }),
            columnHelper.accessor('total_dollar', {
                header: ({ column }) => (
                    <div className="flex justify-end">
                        <SortButton column={column} className="me-0">
                            {labels.colTotalDollar}
                        </SortButton>
                    </div>
                ),
                cell: (info) => (
                    <MoneyCell
                        amount={info.getValue()}
                        locale={locale}
                        currency={labels.usdCurrencyLabel}
                    />
                ),
                sortingFn: numericSort,
            }),
            columnHelper.accessor('receive_dollar', {
                header: ({ column }) => (
                    <div className="flex justify-end">
                        <SortButton column={column} className="me-0">
                            {labels.colReceiveDollar}
                        </SortButton>
                    </div>
                ),
                cell: (info) => (
                    <MoneyCell
                        amount={info.getValue()}
                        locale={locale}
                        currency={labels.usdCurrencyLabel}
                    />
                ),
                sortingFn: numericSort,
            }),
            columnHelper.accessor('remain_dollar_on_saraf', {
                header: ({ column }) => (
                    <div className="flex justify-end">
                        <SortButton column={column} className="me-0">
                            {labels.colRemainDollar}
                        </SortButton>
                    </div>
                ),
                cell: (info) => {
                    const amount = info.getValue();
                    const numeric = Number(amount);
                    const hasRemainder = Number.isFinite(numeric) && numeric > 0.001;
                    const formatted = formatMoneyAmountOrDash(amount, locale);

                    if (formatted === '—') {
                        return <span className="text-muted-foreground">—</span>;
                    }

                    return (
                        <div className="flex flex-col items-end gap-1">
                            <span
                                className={cn(
                                    'inline-flex rounded-full px-2 py-0.5 text-xs font-semibold tabular-nums',
                                    hasRemainder
                                        ? 'bg-amber-500/15 text-amber-800 dark:text-amber-300'
                                        : 'bg-muted/80 text-muted-foreground',
                                )}
                            >
                                {formatted}
                            </span>
                            <span className="text-muted-foreground text-[10px] font-medium uppercase tracking-wide">
                                {labels.usdCurrencyLabel}
                            </span>
                        </div>
                    );
                },
                sortingFn: numericSort,
            }),
        );

        if (canView || canUpdate) {
            cols.push(
                columnHelper.display({
                    id: 'action',
                    header: labels.colAction,
                    cell: ({ row }) => {
                        const exchange = row.original;

                        return (
                            <DropdownMenu>
                                <DropdownMenuTrigger asChild>
                                    <Button
                                        type="button"
                                        variant="ghost"
                                        size="icon"
                                        className="size-8"
                                        aria-label={labels.actionsMenuAria}
                                    >
                                        <MoreHorizontal className="size-4" />
                                    </Button>
                                </DropdownMenuTrigger>
                                <DropdownMenuContent align="end" className="min-w-44">
                                    {canView ? (
                                        <DropdownMenuItem asChild>
                                            <Link
                                                href={currencyExchangeShow.url(exchange.id)}
                                                prefetch
                                            >
                                                <Eye className="size-4" />
                                                {labels.viewDetail}
                                            </Link>
                                        </DropdownMenuItem>
                                    ) : null}
                                    {canView && canUpdate ? <DropdownMenuSeparator /> : null}
                                    {canUpdate ? (
                                        <DropdownMenuItem asChild>
                                            <Link
                                                href={currencyExchangeEdit.url(exchange.id)}
                                                prefetch
                                            >
                                                <Pencil className="size-4" />
                                                {labels.editExchange}
                                            </Link>
                                        </DropdownMenuItem>
                                    ) : null}
                                </DropdownMenuContent>
                            </DropdownMenu>
                        );
                    },
                    enableSorting: false,
                    enableGlobalFilter: false,
                }),
            );
        }

        return cols;
    }, [labels, locale, hideSarafColumn, canView, canUpdate]);

    // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table API is not memoization-safe
    const table = useReactTable({
        data: exchanges,
        columns,
        state: {
            sorting,
            columnVisibility,
            globalFilter,
            pagination,
        },
        onSortingChange: setSorting,
        onColumnVisibilityChange: setColumnVisibility,
        onGlobalFilterChange: setGlobalFilter,
        onPaginationChange: setPagination,
        getCoreRowModel: getCoreRowModel(),
        getSortedRowModel: getSortedRowModel(),
        getFilteredRowModel: getFilteredRowModel(),
        getPaginationRowModel: getPaginationRowModel(),
        globalFilterFn: (row, _columnId, filterValue) => {
            const q = String(filterValue ?? '').toLowerCase().trim();

            if (!q) {
                return true;
            }

            const saraf = String(row.original.saraf_name ?? '').toLowerCase();
            const date = String(row.original.exchange_date ?? '').toLowerCase();
            const formattedDate = formatAppDateOrDash(
                row.original.exchange_date,
                locale,
            ).toLowerCase();

            return saraf.includes(q) || date.includes(q) || formattedDate.includes(q);
        },
    });

    const pageCount = table.getPageCount();
    const pageIndex = table.getState().pagination.pageIndex;
    const pageSize = table.getState().pagination.pageSize;
    const summaryText = labels.paginationSummary
        .replace('{page}', String(pageIndex + 1))
        .replace('{pages}', String(Math.max(pageCount, 1)));

    return (
        <div className="space-y-4">
            <div className="flex max-w-sm flex-col gap-2">
                <Input
                    id="currency-exchanges-search"
                    type="search"
                    value={globalFilter ?? ''}
                    onChange={(e) => setGlobalFilter(e.target.value)}
                    placeholder={labels.searchPlaceholder}
                    className="h-9"
                />
            </div>

            <div className="overflow-x-auto rounded-lg border border-border/80">
                <Table>
                    <TableHeader>
                        {table.getHeaderGroups().map((headerGroup) => (
                            <TableRow key={headerGroup.id} className="bg-muted/40 hover:bg-muted/40">
                                {headerGroup.headers.map((header) => (
                                    <TableHead
                                        key={header.id}
                                        className={cn(
                                            header.column.id !== 'serial' &&
                                                header.column.id !== 'exchange_date' &&
                                                header.column.id !== 'saraf_name' &&
                                                header.column.id !== 'id' &&
                                                header.column.id !== 'action' &&
                                                'text-end',
                                        )}
                                    >
                                        {header.isPlaceholder
                                            ? null
                                            : flexRender(
                                                  header.column.columnDef.header,
                                                  header.getContext(),
                                              )}
                                    </TableHead>
                                ))}
                            </TableRow>
                        ))}
                    </TableHeader>
                    <TableBody>
                        {table.getRowModel().rows.length === 0 ? (
                            <TableRow>
                                <TableCell
                                    colSpan={columns.length}
                                    className="text-muted-foreground h-24 text-center"
                                >
                                    {labels.empty}
                                </TableCell>
                            </TableRow>
                        ) : (
                            table.getRowModel().rows.map((row) => (
                                <TableRow key={row.id} className="hover:bg-muted/25">
                                    {row.getVisibleCells().map((cell) => (
                                        <TableCell
                                            key={cell.id}
                                            className={cn(
                                                'whitespace-normal align-middle',
                                                cell.column.id !== 'serial' &&
                                                    cell.column.id !== 'exchange_date' &&
                                                    cell.column.id !== 'saraf_name' &&
                                                    cell.column.id !== 'id' &&
                                                    cell.column.id !== 'action' &&
                                                    'text-end',
                                            )}
                                        >
                                            {flexRender(
                                                cell.column.columnDef.cell,
                                                cell.getContext(),
                                            )}
                                        </TableCell>
                                    ))}
                                </TableRow>
                            ))
                        )}
                    </TableBody>
                </Table>
            </div>

            {exchanges.length > 0 ? (
                <div className="flex flex-col gap-4 border-t border-border pt-4 sm:flex-row sm:items-center sm:justify-between">
                    <div className="flex flex-wrap items-center gap-2">
                        <Label
                            htmlFor="currency-exchanges-page-size"
                            className="text-muted-foreground whitespace-nowrap text-sm"
                        >
                            {labels.rowsPerPage}
                        </Label>
                        <select
                            id="currency-exchanges-page-size"
                            className="border-input bg-background h-9 rounded-md border px-2 text-sm shadow-xs outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50"
                            value={pageSize}
                            onChange={(e) => {
                                const next = Number(e.target.value);
                                setPagination({
                                    pageIndex: 0,
                                    pageSize: next,
                                });
                            }}
                        >
                            {[5, 10, 25, 50].map((n) => (
                                <option key={n} value={n}>
                                    {n}
                                </option>
                            ))}
                        </select>
                    </div>
                    <div className="flex flex-wrap items-center gap-2">
                        <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            onClick={() => table.previousPage()}
                            disabled={!table.getCanPreviousPage()}
                        >
                            {labels.paginationPrevious}
                        </Button>
                        <span className="text-muted-foreground min-w-[8rem] text-center text-sm tabular-nums">
                            {summaryText}
                        </span>
                        <Button
                            type="button"
                            variant="outline"
                            size="sm"
                            onClick={() => table.nextPage()}
                            disabled={!table.getCanNextPage()}
                        >
                            {labels.paginationNext}
                        </Button>
                    </div>
                </div>
            ) : null}
        </div>
    );
}
