import type { Column } from './components';
import type { ConfirmState } from './ConfirmDialog';
import type { SendTarget } from './SendDocumentDialog';
import type { Invoice } from './shared';
import { useState } from 'react';
import { Link } from 'react-router';
import { Copy, FileText, Filter, MoreHorizontal, Plus, Send, Trash2, Wallet } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Checkbox } from '@/components/ui/checkbox';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import {
  EmptyState,
  ErrorState,
  Pagination,
  SearchBox,
  SectionShell,
  SimpleTable,
  StatusBadge,
  StatusTabs,
} from './components';
import { ConfirmDialog } from './ConfirmDialog';
import { SendDocumentDialog } from './SendDocumentDialog';
import { PdfPane } from './PdfPane';
import { formatDate, formatMoney, relativeDue } from './format';
import { INVOICE_TABS, PAGE_SIZE, type Invoice as InvoiceType } from './shared';
import { useListFilters } from './useInvoicesSection';
import {
  useCurrency,
  useDocumentAction,
  useLookups,
  useResourceMutations,
  useResourceList,
} from './useInvoiceShelfData';

// The invoices list — upstream's InvoiceIndexView, with its column order, its four tabs and its filter set.
//
// Two deliberate departures from the map of the Vue app:
//
//  * "Convert to Estimate" is absent. That row exists in the 3.0 source, but this instance runs 2.4.2 and
//    has no invoices/{id}/convert-to-estimate route — the sidecar's allow-list reflects the live routes, so
//    offering it here would render a menu item that 404s.
//  * "Edit" and "Record Payment" open the editors in this app rather than routing to InvoiceShelf.
//
// `allow_edit` is honoured rather than ignored: once an invoice has payments against it, upstream locks
// editing, and letting a user open a form whose save will be rejected is worse than hiding the button.

type Props = { onEdit: (id: number | 'new') => void; recordPaymentHref: (invoiceId: number) => string };

export const InvoicesListView = ({ onEdit, recordPaymentHref }: Props) => {
  const { filters, patch, select, setPage, clearFilters } = useListFilters();
  const currency = useCurrency();
  const { customers } = useLookups();
  const [showFilters, setShowFilters] = useState(false);
  const [selection, setSelection] = useState<Set<number>>(new Set());
  const [confirm, setConfirm] = useState<ConfirmState>(null);
  const [sendTarget, setSendTarget] = useState<SendTarget | null>(null);

  const { rows, meta, isLoading, error } = useResourceList<InvoiceType>('invoices', {
    page: filters.page,
    limit: PAGE_SIZE,
    invoice_number: filters.search || undefined,
    status: filters.status || undefined,
    customer_id: filters.customerId || undefined,
    from_date: filters.fromDate || undefined,
    to_date: filters.toDate || undefined,
    orderByField: 'created_at',
    orderBy: 'desc',
  });

  const { removeMany, remove } = useResourceMutations('invoices');
  const action = useDocumentAction('invoices');

  const selected = rows.find((r) => r.id === filters.selected) ?? null;

  const toggleRow = (id: number) =>
    setSelection((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });

  const allChecked = rows.length > 0 && rows.every((r) => selection.has(r.id));

  const columns: Column<Invoice>[] = [
    {
      key: 'check',
      label: '',
      width: '36px',
      render: (row) => (
        <span onClick={(e) => e.stopPropagation()} className="flex items-center">
          <Checkbox checked={selection.has(row.id)} onCheckedChange={() => toggleRow(row.id)} />
        </span>
      ),
    },
    {
      key: 'invoice_date',
      label: 'Date',
      width: 'minmax(90px, 0.8fr)',
      render: (row) => formatDate(row.invoice_date, row.formatted_invoice_date),
    },
    {
      key: 'invoice_number',
      label: 'Number',
      width: 'minmax(90px, 0.8fr)',
      render: (row) => <span className="font-medium">{row.invoice_number}</span>,
    },
    {
      key: 'name',
      label: 'Customer',
      width: 'minmax(120px, 1.4fr)',
      render: (row) => <span className="truncate">{row.customer?.name ?? '—'}</span>,
    },
    {
      key: 'status',
      label: 'Status',
      width: 'minmax(90px, 0.9fr)',
      render: (row) => <StatusBadge value={row.status} />,
    },
    {
      key: 'due_amount',
      label: 'Amount due',
      width: 'minmax(120px, 1.1fr)',
      align: 'right',
      render: (row) => (
        <div className="flex items-center justify-end gap-1.5">
          {row.overdue && <StatusBadge value="OVERDUE" />}
          <StatusBadge value={row.paid_status} />
          <span>{formatMoney(row.due_amount, currency)}</span>
        </div>
      ),
    },
    {
      key: 'total',
      label: 'Total',
      width: 'minmax(90px, 0.9fr)',
      align: 'right',
      render: (row) => formatMoney(row.total, currency),
    },
  ];

  const rowMenu = (row: Invoice) => (
    <DropdownMenu>
      <DropdownMenuTrigger asChild>
        <Button variant="ghost" size="sm" className="h-6 w-6 p-0">
          <MoreHorizontal className="h-3.5 w-3.5" />
        </Button>
      </DropdownMenuTrigger>
      <DropdownMenuContent align="end" className="w-52">
        {row.allow_edit && <DropdownMenuItem onSelect={() => onEdit(row.id)}>Edit</DropdownMenuItem>}
        <DropdownMenuItem onSelect={() => select(row.id)}>View PDF</DropdownMenuItem>

        {row.status === 'DRAFT' && (
          <DropdownMenuItem
            onSelect={() =>
              setSendTarget({
                resource: 'invoices',
                id: row.id,
                number: row.invoice_number,
                customerName: row.customer?.name ?? '',
                customerEmail: row.customer?.email ?? null,
              })
            }
          >
            <Send className="mr-2 h-3.5 w-3.5" />
            Send invoice
          </DropdownMenuItem>
        )}
        {(row.status === 'SENT' || row.status === 'VIEWED') && (
          <DropdownMenuItem
            onSelect={() =>
              setSendTarget({
                resource: 'invoices',
                id: row.id,
                number: row.invoice_number,
                customerName: row.customer?.name ?? '',
                customerEmail: row.customer?.email ?? null,
                resend: true,
              })
            }
          >
            <Send className="mr-2 h-3.5 w-3.5" />
            Resend invoice
          </DropdownMenuItem>
        )}
        {/* Opening the payment editor is an address (`?edit=new&pay=<id>`), not a side effect — the editor
            prefills itself from those params — so it is an anchor, not a callback up to the parent and
            back down through `navigate`. */}
        {(row.status === 'SENT' || row.status === 'VIEWED') && (
          <DropdownMenuItem asChild>
            <Link to={recordPaymentHref(row.id)}>
              <Wallet className="mr-2 h-3.5 w-3.5" />
              Record payment
            </Link>
          </DropdownMenuItem>
        )}
        {row.status === 'DRAFT' && (
          <DropdownMenuItem
            onSelect={() =>
              setConfirm({
                title: `Mark ${row.invoice_number} as sent?`,
                // Worth spelling out — the wording is one word away from the action that does email it.
                description:
                  'This only changes the status to Sent. Nothing is emailed to the customer. Use “Send invoice” for that.',
                confirmLabel: 'Mark as sent',
                onConfirm: () => action.mutate({ id: row.id, action: 'status', payload: { status: 'SENT' } }),
              })
            }
          >
            Mark as sent
          </DropdownMenuItem>
        )}

        <DropdownMenuItem onSelect={() => action.mutate({ id: row.id, action: 'clone' })}>
          <Copy className="mr-2 h-3.5 w-3.5" />
          Clone invoice
        </DropdownMenuItem>

        <DropdownMenuSeparator />
        <DropdownMenuItem
          className="text-red-600"
          onSelect={() =>
            setConfirm({
              title: `Delete invoice ${row.invoice_number}?`,
              description: 'This permanently removes the invoice and any payments recorded against it.',
              confirmLabel: 'Delete',
              destructive: true,
              onConfirm: () => {
                remove.mutate(row.id);
                if (filters.selected === row.id) select(null);
              },
            })
          }
        >
          <Trash2 className="mr-2 h-3.5 w-3.5" />
          Delete
        </DropdownMenuItem>
      </DropdownMenuContent>
    </DropdownMenu>
  );

  if (error) return <ErrorState error={error} />;

  const toolbar = (
    <>
      <Checkbox
        checked={allChecked}
        onCheckedChange={() => setSelection(allChecked ? new Set() : new Set(rows.map((r) => r.id)))}
        title="Select all on this page"
      />
      <StatusTabs
        tabs={INVOICE_TABS}
        value={filters.status}
        onChange={(v) => {
          patch({ status: v });
          setSelection(new Set());
        }}
      />
      <SearchBox value={filters.search} onChange={(v) => patch({ q: v })} placeholder="Invoice number…" />
      <Button
        variant={showFilters || filters.isFiltered ? 'secondary' : 'ghost'}
        size="sm"
        className="h-8"
        onClick={() => setShowFilters((v) => !v)}
      >
        <Filter className="mr-1.5 h-3.5 w-3.5" />
        Filter
      </Button>
      <div className="ml-auto flex items-center gap-2">
        {selection.size > 0 && (
          <Button
            variant="ghost"
            size="sm"
            className="h-8 text-red-600"
            onClick={() =>
              setConfirm({
                title: `Delete ${selection.size} invoices?`,
                description: 'This permanently removes them and any payments recorded against them.',
                confirmLabel: 'Delete',
                destructive: true,
                onConfirm: () => {
                  removeMany.mutate([...selection]);
                  setSelection(new Set());
                },
              })
            }
          >
            <Trash2 className="mr-1.5 h-3.5 w-3.5" />
            Delete {selection.size}
          </Button>
        )}
        <Button size="sm" className="h-8" onClick={() => onEdit('new')}>
          <Plus className="mr-1.5 h-3.5 w-3.5" />
          New invoice
        </Button>
      </div>
    </>
  );

  return (
    <>
      <div className="flex h-full min-h-0">
        <div className="min-w-0 flex-1">
          <SectionShell toolbar={toolbar} footer={<Pagination meta={meta} onPage={setPage} />}>
            {showFilters && (
              <div className="flex flex-wrap items-end gap-3 border-b border-border bg-muted/20 px-3 py-2">
                <label className="flex flex-col gap-1 text-[10px] text-muted-foreground">
                  Customer
                  <select
                    value={filters.customerId ?? ''}
                    onChange={(e) => patch({ customer: e.target.value || null })}
                    className="h-8 rounded-md border border-input bg-background px-2 text-xs"
                  >
                    <option value="">All</option>
                    {customers.map((c) => (
                      <option key={c.id} value={c.id}>
                        {c.name}
                      </option>
                    ))}
                  </select>
                </label>
                <label className="flex flex-col gap-1 text-[10px] text-muted-foreground">
                  From
                  <Input
                    type="date"
                    value={filters.fromDate ?? ''}
                    onChange={(e) => patch({ from: e.target.value || null })}
                    className="h-8 w-36 text-xs"
                  />
                </label>
                <label className="flex flex-col gap-1 text-[10px] text-muted-foreground">
                  To
                  <Input
                    type="date"
                    value={filters.toDate ?? ''}
                    onChange={(e) => patch({ to: e.target.value || null })}
                    className="h-8 w-36 text-xs"
                  />
                </label>
                {filters.isFiltered && (
                  <Button variant="ghost" size="sm" className="h-8" onClick={clearFilters}>
                    Clear
                  </Button>
                )}
              </div>
            )}

            <SimpleTable
              rows={rows}
              columns={columns}
              rowKey={(r) => r.id}
              selectedKey={filters.selected}
              onRowClick={(r) => select(r.id === filters.selected ? null : r.id)}
              rowMenu={rowMenu}
              empty={
                isLoading ? (
                  <EmptyState icon={FileText} title="Loading…" />
                ) : (
                  <EmptyState
                    icon={FileText}
                    title={filters.isFiltered ? 'No invoices match' : 'No invoices yet'}
                    hint={filters.isFiltered ? 'Try clearing the filters.' : 'Create the first one to get started.'}
                    action={
                      <Button size="sm" onClick={() => onEdit('new')}>
                        <Plus className="mr-1.5 h-3.5 w-3.5" />
                        New invoice
                      </Button>
                    }
                  />
                )
              }
            />
          </SectionShell>
        </div>

        {selected && (
          <div className="hidden w-[46%] min-w-[380px] shrink-0 lg:block">
            <PdfPane
              resource="invoices"
              id={selected.id}
              title={`Invoice ${selected.invoice_number}`}
              subtitle={
                <>
                  {selected.customer?.name}
                  {selected.due_date && ` · ${relativeDue(selected.due_date)}`}
                </>
              }
              filename={`invoice-${selected.invoice_number}`}
              onClose={() => select(null)}
            />
          </div>
        )}
      </div>

      <ConfirmDialog state={confirm} onClose={() => setConfirm(null)} />
      <SendDocumentDialog target={sendTarget} currency={currency} onClose={() => setSendTarget(null)} />
    </>
  );
};
