import {
    flexRender,
    getCoreRowModel,
    getFilteredRowModel,
    getPaginationRowModel,
    getSortedRowModel,
    createColumnHelper,
    useReactTable,
} from '@tanstack/react-table';
import { ArrowDown, ArrowUp, ArrowUpDown } from 'lucide-react';
import { useEffect, useMemo, useState } from 'react';
import { Button } from '@/components/ui/button';
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,
    formatPurchaseCurrencyLabel,
    formatPurchaseMoneyOrDash,
} from '@/lib/dates';

const columnHelper = createColumnHelper();

function SortButton({ column, children }) {
    const sorted = column.getIsSorted();

    return (
        <Button
            type="button"
            variant="ghost"
            size="sm"
            className="-ms-2 h-8 font-medium"
            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 saleNumberForRow(row) {
    if (isLoanPayment(row)) {
        return null;
    }

    return row.sale_number ?? row.purchase_bill_number;
}

function loanNumberForRow(row) {
    if (! isLoanPayment(row)) {
        return null;
    }

    return row.loan_number ?? row.sale_number ?? row.purchase_bill_number;
}

function saleIdForRow(row) {
    if (isLoanPayment(row)) {
        return null;
    }

    return row.sale_id ?? row.purchase_id;
}

function isLoanPayment(row) {
    return row?.payment_type === 'loan' || row?.source === 'loan_repayment';
}

function documentLabelForRow(row, labels) {
    if (isLoanPayment(row)) {
        return loanNumberForRow(row);
    }

    return saleNumberForRow(row);
}

export function CustomerPaymentsDataTable({
    payments,
    labels,
    locale = 'en',
    paymentGroup = 'date',
    showCustomerColumn = false,
    showPaymentTypeColumn = false,
    onOpenSaleById,
    searchInputId = 'customer-payments-search',
    pageSizeInputId = 'customer-payments-page-size',
}) {
    const isGroupedPayments = paymentGroup !== 'date';
    const [sorting, setSorting] = useState([
        { id: isGroupedPayments ? 'period_label' : 'paid_at', desc: true },
    ]);
    const [globalFilter, setGlobalFilter] = useState('');
    const [pagination, setPagination] = useState({
        pageIndex: 0,
        pageSize: 10,
    });

    useEffect(() => {
        setSorting([{ id: isGroupedPayments ? 'period_label' : 'paid_at', desc: true }]);
        setGlobalFilter('');
        setPagination((prev) => ({ ...prev, pageIndex: 0 }));
    }, [isGroupedPayments, paymentGroup]);

    useEffect(() => {
        setPagination((prev) => ({ ...prev, pageIndex: 0 }));
    }, [globalFilter, sorting]);

    const columns = useMemo(() => {
        const cols = [
            columnHelper.display({
                id: 'serial',
                header: labels.colSerial,
                cell: ({ row, table }) => {
                    const { pageIndex, pageSize } = table.getState().pagination;
                    return (
                        <span className="text-muted-foreground tabular-nums">
                            {pageIndex * pageSize + row.index + 1}
                        </span>
                    );
                },
                enableSorting: false,
                enableGlobalFilter: false,
            }),
        ];

        if (isGroupedPayments) {
            cols.push(
                columnHelper.accessor('period_label', {
                    header:
                        paymentGroup === 'sale'
                            ? (labels.colSaleOrLoanNumber ?? labels.colSaleNumber)
                            : labels.colPeriod,
                    cell: ({ row }) => {
                        const r = row.original;
                        const saleId = saleIdForRow(r);

                        if (paymentGroup === 'sale' && saleId) {
                            return (
                                <button
                                    type="button"
                                    onClick={() => onOpenSaleById?.(saleId)}
                                    className="text-primary text-start font-medium underline-offset-4 hover:underline"
                                >
                                    {r.period_label}
                                </button>
                            );
                        }

                        if (paymentGroup === 'sale' && isLoanPayment(r)) {
                            return (
                                <span className="font-medium">
                                    <span className="text-muted-foreground">
                                        {labels.documentTypeLoan ??
                                            labels.paymentTypeLoan ??
                                            'Loan'}
                                        :{' '}
                                    </span>
                                    {r.period_label}
                                </span>
                            );
                        }

                        return r.period_label ?? '—';
                    },
                }),
            );

            if (showCustomerColumn && paymentGroup === 'sale') {
                cols.push(
                    columnHelper.accessor('customer_name', {
                        header: labels.colCustomer,
                        cell: (info) => info.getValue() ?? '—',
                    }),
                );
            }

            cols.push(
                columnHelper.accessor('payment_count', {
                    header: labels.colPaymentCount,
                    cell: (info) => (
                        <span className="text-end tabular-nums">{info.getValue()}</span>
                    ),
                }),
                columnHelper.display({
                    id: 'date_range',
                    header: labels.colDateRange,
                    cell: ({ row }) => {
                        const r = row.original;
                        const from = formatAppDateOrDash(r.paid_from, locale);
                        const to = formatAppDateOrDash(r.paid_to, locale);

                        if (r.paid_to && r.paid_to !== r.paid_from) {
                            return (
                                <span className="tabular-nums">
                                    {from} – {to}
                                </span>
                            );
                        }

                        return <span className="tabular-nums">{from}</span>;
                    },
                    enableSorting: false,
                }),
                columnHelper.accessor('bill_amount', {
                    header: labels.colAmount,
                    cell: (info) => (
                        <span className="text-end tabular-nums">
                            {formatMoneyAmountOrDash(info.getValue(), locale)}
                        </span>
                    ),
                }),
            );

            return cols;
        }

        if (showCustomerColumn) {
            cols.push(
                columnHelper.accessor('customer_name', {
                    header: ({ column }) => (
                        <SortButton column={column}>{labels.colCustomer}</SortButton>
                    ),
                    cell: (info) => info.getValue() ?? '—',
                }),
            );
        }

        cols.push(
            columnHelper.accessor('paid_at', {
                id: 'paid_at',
                header: ({ column }) => (
                    <SortButton column={column}>
                        {labels.colPaidAt ?? labels.colDate}
                    </SortButton>
                ),
                cell: (info) => formatAppDateOrDash(info.getValue(), locale),
            }),
        );

        if (showPaymentTypeColumn) {
            cols.push(
                columnHelper.accessor('payment_type', {
                    header: labels.colPaymentType,
                    cell: (info) => {
                        const value = info.getValue();

                        if (value === 'overall') {
                            return labels.paymentTypeOverall;
                        }

                        if (value === 'loan') {
                            return labels.paymentTypeLoan ?? labels.loanOutstanding ?? 'Loan';
                        }

                        return labels.paymentTypeSale;
                    },
                    enableSorting: false,
                }),
            );
        }

        cols.push(
            columnHelper.accessor((row) => documentLabelForRow(row, labels), {
                id: 'sale_number',
                header: ({ column }) => (
                    <SortButton column={column}>
                        {labels.colSaleOrLoanNumber ??
                            labels.colSaleNumber ??
                            labels.colBillNumber}
                    </SortButton>
                ),
                cell: ({ row }) => {
                    const r = row.original;
                    const saleId = saleIdForRow(r);
                    const saleNumber = saleNumberForRow(r);
                    const loanNumber = loanNumberForRow(r);

                    if (saleId && saleNumber) {
                        return (
                            <button
                                type="button"
                                onClick={() => onOpenSaleById?.(saleId)}
                                className="text-primary text-start font-medium underline-offset-4 hover:underline"
                            >
                                <span className="text-muted-foreground font-normal">
                                    {labels.documentTypeSale ??
                                        labels.paymentTypeSale ??
                                        'Sale'}
                                    :{' '}
                                </span>
                                {saleNumber}
                            </button>
                        );
                    }

                    if (loanNumber) {
                        return (
                            <span className="font-medium">
                                <span className="text-muted-foreground font-normal">
                                    {labels.documentTypeLoan ??
                                        labels.paymentTypeLoan ??
                                        'Loan'}
                                    :{' '}
                                </span>
                                {loanNumber}
                            </span>
                        );
                    }

                    return '—';
                },
            }),
        );

        if (showPaymentTypeColumn) {
            cols.push(
                columnHelper.accessor('currency', {
                    header: ({ column }) => (
                        <SortButton column={column}>{labels.colCurrency}</SortButton>
                    ),
                    cell: (info) => formatPurchaseCurrencyLabel(info.getValue(), locale),
                }),
            );
        } else {
            cols.push(
                columnHelper.accessor('payment_method', {
                    header: labels.colMethod,
                    cell: (info) => info.getValue() ?? '—',
                    enableSorting: false,
                }),
                columnHelper.accessor('reference', {
                    header: labels.colReference,
                    cell: (info) => info.getValue() ?? '—',
                    enableSorting: false,
                }),
            );
        }

        if (showPaymentTypeColumn) {
            cols.push(
                columnHelper.display({
                    id: 'amount',
                    header: labels.colAmount,
                    enableSorting: false,
                    cell: ({ row }) => {
                        const payment = row.original;
                        const crossCurrency = payment.currency !== payment.bill_currency;
                        const billAmount =
                            payment.display_amount ?? payment.bill_amount ?? payment.amount;

                        return (
                            <div className="space-y-0.5 text-end">
                                <span className="tabular-nums font-medium">
                                    {formatPurchaseMoneyOrDash(
                                        billAmount,
                                        payment.bill_currency,
                                        locale,
                                    )}
                                </span>
                                {crossCurrency ? (
                                    <span className="text-muted-foreground block text-xs tabular-nums">
                                        {labels.cashPaidLabel}:{' '}
                                        {formatPurchaseMoneyOrDash(
                                            payment.amount,
                                            payment.currency,
                                            locale,
                                        )}
                                    </span>
                                ) : null}
                            </div>
                        );
                    },
                }),
            );

            if (labels.colNotes) {
                cols.push(
                    columnHelper.accessor('notes', {
                        header: labels.colNotes,
                        cell: (info) => (
                            <span className="max-w-xs whitespace-normal text-sm">
                                {info.getValue() || '—'}
                            </span>
                        ),
                        enableSorting: false,
                    }),
                );
            }
        } else {
            cols.push(
                columnHelper.accessor('bill_amount', {
                    header: labels.colAmount,
                    cell: (info) => (
                        <span className="text-end tabular-nums">
                            {formatMoneyAmountOrDash(info.getValue(), locale)}
                        </span>
                    ),
                }),
            );
        }

        return cols;
    }, [
        isGroupedPayments,
        labels,
        locale,
        onOpenSaleById,
        paymentGroup,
        showCustomerColumn,
        showPaymentTypeColumn,
    ]);

    // eslint-disable-next-line react-hooks/incompatible-library -- TanStack Table API is not memoization-safe
    const table = useReactTable({
        data: payments,
        columns,
        state: { sorting, globalFilter, pagination },
        onSortingChange: setSorting,
        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 r = row.original;

            if (isGroupedPayments) {
                return [
                    r.period_label,
                    r.customer_name,
                    r.payment_count,
                    formatAppDateOrDash(r.paid_from, locale),
                    formatAppDateOrDash(r.paid_to, locale),
                ]
                    .filter(Boolean)
                    .some((field) => String(field).toLowerCase().includes(q));
            }

            const typeLabel =
                r.payment_type === 'overall'
                    ? labels.paymentTypeOverall
                    : r.payment_type === 'loan'
                      ? (labels.paymentTypeLoan ?? 'Loan')
                      : labels.paymentTypeSale;

            return [
                saleNumberForRow(r),
                loanNumberForRow(r),
                r.customer_name,
                r.currency,
                r.notes,
                r.payment_method,
                r.reference,
                showPaymentTypeColumn ? typeLabel : null,
                formatAppDateOrDash(r.paid_at, locale),
                formatPurchaseCurrencyLabel(r.currency, locale),
            ]
                .filter(Boolean)
                .some((field) => String(field).toLowerCase().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={searchInputId}
                    type="search"
                    value={globalFilter ?? ''}
                    onChange={(e) => setGlobalFilter(e.target.value)}
                    placeholder={labels.paymentsSearchPlaceholder}
                    className="h-9"
                />
            </div>

            <div className="overflow-x-auto rounded-md border">
                <Table>
                    <TableHeader>
                        {table.getHeaderGroups().map((headerGroup) => (
                            <TableRow key={headerGroup.id}>
                                {headerGroup.headers.map((header) => (
                                    <TableHead
                                        key={header.id}
                                        className={
                                            ['payment_count', 'bill_amount', 'amount'].includes(
                                                header.column.id,
                                            )
                                                ? 'text-end'
                                                : undefined
                                        }
                                    >
                                        {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.noPayments}
                                </TableCell>
                            </TableRow>
                        ) : (
                            table.getRowModel().rows.map((row) => (
                                <TableRow key={row.id}>
                                    {row.getVisibleCells().map((cell) => (
                                        <TableCell
                                            key={cell.id}
                                            className="whitespace-normal align-middle"
                                        >
                                            {flexRender(
                                                cell.column.columnDef.cell,
                                                cell.getContext(),
                                            )}
                                        </TableCell>
                                    ))}
                                </TableRow>
                            ))
                        )}
                    </TableBody>
                </Table>
            </div>

            {payments.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={pageSizeInputId}
                            className="text-muted-foreground whitespace-nowrap text-sm"
                        >
                            {labels.rowsPerPage}
                        </Label>
                        <select
                            id={pageSizeInputId}
                            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) => {
                                setPagination({
                                    pageIndex: 0,
                                    pageSize: Number(e.target.value),
                                });
                            }}
                        >
                            {[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>
    );
}
