import type { Column } from './components';
import type { ConfirmState } from './ConfirmDialog';
import type { Address, Customer } from './shared';
import { useState } from 'react';
import { Link } from 'react-router';
import { Filter, MoreHorizontal, Plus, Trash2, Users, X } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { Input } from '@/components/ui/input';
import {
  DropdownMenu,
  DropdownMenuContent,
  DropdownMenuItem,
  DropdownMenuSeparator,
  DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { EmptyState, ErrorState, Field, Pagination, SearchBox, SectionShell, SimpleTable } from './components';
import { ConfirmDialog } from './ConfirmDialog';
import { formatDate, formatMoney } from './format';
import { invoicesCustomerPath, PAGE_SIZE } from './shared';
import { useListFilters } from './useInvoicesSection';
import { useCurrency, useCustomerStats, useResourceList, useResourceMutations } from './useInvoiceShelfData';

// Customers. Upstream splits the search into three separate fields rather than one box — display name,
// contact name and phone are distinct API filters — so the toolbar search maps to display name and the
// other two live behind the filter row, which is where upstream puts them too.

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

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

  const { rows, meta, isLoading, error } = useResourceList<Customer>('customers', {
    page: filters.page,
    limit: PAGE_SIZE,
    display_name: filters.search || undefined,
    // `status` and `from` carry contact name and phone here — one query-string slot per filter, and
    // customers have no status or date range to compete for them.
    contact_name: filters.status || undefined,
    phone: filters.fromDate || undefined,
    orderByField: 'created_at',
    orderBy: 'desc',
  });

  const { remove, removeMany } = useResourceMutations('customers');
  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<Customer>[] = [
    {
      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: 'name',
      label: 'Name',
      width: 'minmax(150px, 2fr)',
      render: (row) => (
        <div className="min-w-0">
          <div className="truncate font-medium">{row.name}</div>
          {row.contact_name && <div className="truncate text-[10px] text-muted-foreground">{row.contact_name}</div>}
        </div>
      ),
    },
    {
      key: 'email',
      label: 'Email',
      width: 'minmax(120px, 1.4fr)',
      render: (row) => <span className="truncate text-muted-foreground">{row.email ?? '—'}</span>,
    },
    {
      key: 'phone',
      label: 'Phone',
      width: 'minmax(100px, 1fr)',
      render: (row) => row.phone ?? '—',
    },
    {
      key: 'due_amount',
      label: 'Amount due',
      width: 'minmax(100px, 1fr)',
      align: 'right',
      render: (row) => formatMoney(row.due_amount, currency),
    },
    {
      key: 'created_at',
      label: 'Added',
      width: 'minmax(90px, 0.9fr)',
      render: (row) => formatDate(row.created_at, row.formatted_created_at),
    },
  ];

  const rowMenu = (row: Customer) => (
    <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">
        <DropdownMenuItem onSelect={() => onEdit(row.id)}>Edit</DropdownMenuItem>
        <DropdownMenuItem onSelect={() => select(row.id)}>View</DropdownMenuItem>
        <DropdownMenuSeparator />
        {/* Both go somewhere and change nothing, so they are anchors wearing a menu item — `asChild` hands
            Radix's item semantics to the `<Link>` rather than nesting one inside the other. Middle-click
            opens the filtered list in a tab, which is the point of the filter living in the URL. */}
        <DropdownMenuItem asChild>
          <Link to={invoicesCustomerPath('invoices', row.id)}>Their invoices</Link>
        </DropdownMenuItem>
        <DropdownMenuItem asChild>
          <Link to={invoicesCustomerPath('payments', row.id)}>Their payments</Link>
        </DropdownMenuItem>
        <DropdownMenuSeparator />
        <DropdownMenuItem
          className="text-red-600"
          onSelect={() =>
            setConfirm({
              title: `Delete ${row.name}?`,
              description:
                'InvoiceShelf refuses this while the customer still has invoices, estimates or payments — delete those first.',
              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)))}
      />
      <SearchBox value={filters.search} onChange={(v) => patch({ q: v })} placeholder="Display name…" />
      <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} customers?`,
                description: 'Any that still have documents against them are refused.',
                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 customer
        </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">
                  Contact name
                  <Input
                    value={filters.status ?? ''}
                    onChange={(e) => patch({ status: e.target.value || null })}
                    className="h-8 w-40 text-xs"
                  />
                </label>
                <label className="flex flex-col gap-1 text-[10px] text-muted-foreground">
                  Phone
                  <Input
                    value={filters.fromDate ?? ''}
                    onChange={(e) => patch({ from: e.target.value || null })}
                    className="h-8 w-40 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={Users} title="Loading…" />
                ) : (
                  <EmptyState
                    icon={Users}
                    title={filters.isFiltered ? 'No customers match' : 'No customers yet'}
                    hint={filters.isFiltered ? 'Try clearing the filters.' : 'Every invoice needs one — add the first.'}
                  />
                )
              }
            />
          </SectionShell>
        </div>

        {selected && (
          <div className="hidden w-[38%] min-w-[320px] shrink-0 lg:block">
            <CustomerDetail customer={selected} onEdit={() => onEdit(selected.id)} onClose={() => select(null)} />
          </div>
        )}
      </div>

      <ConfirmDialog state={confirm} onClose={() => setConfirm(null)} />
    </>
  );
};

const CustomerDetail = ({
  customer,
  onEdit,
  onClose,
}: {
  customer: Customer;
  onEdit: () => void;
  onClose: () => void;
}) => {
  const currency = useCurrency();
  const { stats } = useCustomerStats(customer.id);
  const chart = stats?.meta?.chartData;

  return (
    <div className="flex h-full min-h-0 w-full flex-col border-l border-border bg-background">
      <div className="flex shrink-0 items-start gap-2 border-b border-border px-3 py-2">
        <div className="min-w-0 flex-1">
          <div className="truncate text-xs font-semibold">{customer.name}</div>
          {customer.email && <div className="truncate text-[10px] text-muted-foreground">{customer.email}</div>}
        </div>
        <Button variant="ghost" size="sm" className="h-7 px-2 text-xs" onClick={onEdit}>
          Edit
        </Button>
        <Button variant="ghost" size="sm" className="h-7 px-2" onClick={onClose} title="Close">
          <X className="h-3.5 w-3.5" />
        </Button>
      </div>

      <div className="min-h-0 flex-1 overflow-y-auto p-3">
        {chart && (
          <div className="grid grid-cols-2 gap-2">
            <Totals label="Sales" value={formatMoney(chart.salesTotal, currency)} />
            <Totals label="Receipts" value={formatMoney(chart.totalReceipts, currency)} />
            <Totals label="Expenses" value={formatMoney(chart.totalExpenses, currency)} />
            <Totals label="Net profit" value={formatMoney(chart.netProfit, currency)} />
          </div>
        )}

        <div className="mt-3 rounded-lg border border-border px-3 py-1">
          <Field label="Amount due">{formatMoney(customer.due_amount, currency)}</Field>
          {customer.contact_name && <Field label="Contact">{customer.contact_name}</Field>}
          {customer.phone && <Field label="Phone">{customer.phone}</Field>}
          {customer.website && <Field label="Website">{customer.website}</Field>}
          {customer.tax_id && <Field label="Tax ID">{customer.tax_id}</Field>}
          <Field label="Customer since">{formatDate(customer.created_at, customer.formatted_created_at)}</Field>
        </div>

        <AddressCard title="Billing address" address={customer.billing} />
        <AddressCard title="Shipping address" address={customer.shipping} />
      </div>
    </div>
  );
};

const Totals = ({ label, value }: { label: string; value: string }) => (
  <div className="rounded-lg border border-border p-2">
    <div className="text-[10px] text-muted-foreground">{label}</div>
    <div className="truncate text-sm font-semibold tabular-nums" title={value}>
      {value}
    </div>
  </div>
);

const AddressCard = ({ title, address }: { title: string; address?: Address | null }) => {
  const lines = [
    address?.address_street_1,
    address?.address_street_2,
    [address?.city, address?.state, address?.zip].filter(Boolean).join(' '),
    address?.country?.name,
  ].filter((l): l is string => Boolean(l && l.trim()));

  if (!lines.length) return null;

  return (
    <div className="mt-3 rounded-lg border border-border p-3">
      <div className="mb-1 text-[11px] font-medium uppercase tracking-wide text-muted-foreground">{title}</div>
      <div className="whitespace-pre-line text-xs">{lines.join('\n')}</div>
    </div>
  );
};
