import { useEffect, useState } from 'react';
import {
  ActionIcon,
  Badge,
  Button,
  Card,
  Divider,
  Group,
  Loader,
  Modal,
  NumberInput,
  Select,
  Stack,
  Table,
  Text,
  TextInput,
} from '@mantine/core';
import { Ban, CreditCard, DoorOpen, Download, ExternalLink, Eye, Receipt } from 'lucide-react';
import { useNavigate } from 'react-router-dom';
import { DataTable, type ColumnDef } from '@edr/ui-common';
import ListControls from '@/components/common/ListControls';
import { useListControls } from '@/hooks/useListControls';

import { PageContainer, PageHeader } from '@/components/page';
import { AccrualDashboard } from '@/components/warehouses';
import { useMutation, useQuery } from '@tanstack/react-query';

import { api } from '@/services/api';
import { bookingsService } from '@/services/bookings.service';
import { warehouseService } from '@/services/warehouse.service';
import { useToast } from '@/hooks/use-toast';
import {
  WAREHOUSE_INVOICE_STATUSES,
  type WarehouseFeeInvoice,
  type WarehouseGatewayPaymentMethod,
  type WarehouseInvoiceStatus,
} from '@/types/warehouse';
import { openPdfBlob } from '@/components/warehouses/pdf';
import { buildWarehouseExitPaperPdf } from '@/components/warehouses/warehousePdf';
import { extractErrorMessage } from '@/components/warehouses/options';

const STATUS_COLOR: Record<WarehouseInvoiceStatus, string> = {
  DRAFT: 'gray',
  ISSUED: 'orange',
  PARTIALLY_PAID: 'yellow',
  PAID: 'edr-green',
  CANCELLED: 'gray',
};

const fmt = (n: number, c: string) => `${Number(n).toLocaleString()} ${c === 'ETB' ? 'Birr (ETB)' : c}`;
const fmtDate = (d?: string | null) => (d ? new Date(d).toLocaleDateString() : '—');

export default function WarehouseInvoicesPage() {
  const [status, setStatus] = useState<WarehouseInvoiceStatus | null>(null);
  const [detailId, setDetailId] = useState<string | null>(null);

  const { data, isLoading } = useQuery(
    api.warehouses.invoices.queryOptions({
      input: { filter: status ? { status } : undefined },
    }),
  );
  const invoices = data ?? [];

  const controls = useListControls(invoices, {
    searchKeys: ['invoiceNumber', 'bookingReference', 'customerName', 'containerNumber'],
    dateKey: 'issuedAt',
  });

  const invoiceColumns: ColumnDef<WarehouseFeeInvoice>[] = [
    {
      id: 'invoiceNumber',
      header: 'Invoice No',
      cell: ({ row }) => (
        <Text fw={600} size="sm">
          {row.original.invoiceNumber}
        </Text>
      ),
    },
    { id: 'type', header: 'Type', cell: ({ row }) => row.original.invoiceType.replace(/_/g, ' ') },
    { id: 'total', header: 'Total', cell: ({ row }) => fmt(row.original.totalAmount, row.original.currency) },
    { id: 'paid', header: 'Paid', cell: ({ row }) => fmt(row.original.paidAmount, row.original.currency) },
    {
      id: 'balance',
      header: 'Balance',
      cell: ({ row }) => fmt(row.original.balanceAmount, row.original.currency),
    },
    {
      id: 'status',
      header: 'Status',
      cell: ({ row }) => (
        <Badge variant="light" color={STATUS_COLOR[row.original.status]}>
          {row.original.status.replace(/_/g, ' ')}
        </Badge>
      ),
    },
    {
      id: 'issued',
      header: 'Issued',
      cell: ({ row }) => <Text size="xs">{fmtDate(row.original.issuedAt)}</Text>,
    },
    {
      id: 'actions',
      header: '',
      cell: ({ row }) => (
        <Group justify="flex-end" onClick={(e) => e.stopPropagation()}>
          <ActionIcon
            variant="subtle"
            color="gray"
            onClick={() => setDetailId(row.original.id)}
            title="View"
          >
            <Eye size={16} />
          </ActionIcon>
        </Group>
      ),
    },
  ];

  return (
    <PageContainer>
      <PageHeader
        title="Warehouse Fee Invoices"
        subtitle="Demurrage & storage invoices generated from warehouse fee rules."
      />

      <Stack gap="xs">
        <Text fw={700} size="sm" tt="uppercase" c="dimmed">
          Accruing now
        </Text>
        <AccrualDashboard />
      </Stack>

      <Card>
        <ListControls
          search={controls.search}
          onSearchChange={controls.setSearch}
          searchPlaceholder="Search invoice no / booking / customer"
          dateFrom={controls.dateFrom}
          onDateFromChange={controls.setDateFrom}
          dateTo={controls.dateTo}
          onDateToChange={controls.setDateTo}
          dateLabel="Issued"
          hasFilters={controls.hasFilters}
          onReset={controls.reset}
        >
          <Select
            label="Status"
            placeholder="All statuses"
            data={WAREHOUSE_INVOICE_STATUSES.map((s) => ({ value: s, label: s.replace(/_/g, ' ') }))}
            value={status}
            onChange={(v) => setStatus((v as WarehouseInvoiceStatus) ?? null)}
            clearable
            w={200}
          />
        </ListControls>

        <DataTable
          columns={invoiceColumns}
          data={controls.pagedRows}
          status={isLoading ? 'loading' : 'success'}
          emptyMessage="No invoices found."
          containerClassName="border-0 shadow-none"
          {...controls.tableProps}
        />
      </Card>

      <InvoiceDetailModal id={detailId} onClose={() => setDetailId(null)} />
    </PageContainer>
  );
}

function InvoiceDetailModal({ id, onClose }: { id: string | null; onClose: () => void }) {
  const { toast } = useToast();
  const navigate = useNavigate();
  const { data: inv, isLoading } = useQuery(
    api.warehouses.invoice.queryOptions({
      input: { id: id ?? '' },
      enabled: Boolean(id),
    }),
  );
  const pay = useMutation(api.warehouses.payInvoice.mutationOptions());
  const payOnline = useMutation(api.warehouses.payInvoiceOnline.mutationOptions());
  const cancel = useMutation(api.warehouses.cancelInvoice.mutationOptions());
  const gateClear = useMutation(api.warehouses.gateClearance.mutationOptions());
  const [payAmount, setPayAmount] = useState<number | ''>('');
  const [driverName, setDriverName] = useState('');
  const [driverPhone, setDriverPhone] = useState('');
  const [gatewayMethod, setGatewayMethod] = useState<WarehouseGatewayPaymentMethod>('TELEBIRR');
  const [payerAccount, setPayerAccount] = useState('');

  const canPay = inv && (inv.status === 'ISSUED' || inv.status === 'PARTIALLY_PAID');
  const canGateClear = inv?.status === 'PAID' && Boolean(inv.inventoryId);

  useEffect(() => {
    setGatewayMethod(inv?.currency === 'USD' ? 'WAAFI' : 'TELEBIRR');
    setPayerAccount('');
  }, [inv?.id, inv?.currency]);

  const downloadInvoicePdf = async (invoice: WarehouseFeeInvoice) => {
    const pdfWindow = window.open('', '_blank');
    try {
      const { data } = await warehouseService.downloadInvoiceDocument(invoice.id);
      openPdfBlob(data, `warehouse-invoice-${invoice.invoiceNumber}.pdf`, pdfWindow);
    } catch (error) {
      pdfWindow?.close();
      toast({
        variant: 'destructive',
        title: 'Download failed',
        description: extractErrorMessage(error),
      });
    }
  };

  const downloadReceiptPdf = async (invoice: WarehouseFeeInvoice) => {
    const pdfWindow = window.open('', '_blank');
    try {
      const { data } = await warehouseService.downloadInvoiceReceipt(invoice.id);
      openPdfBlob(data, `warehouse-receipt-${invoice.invoiceNumber}.pdf`, pdfWindow);
    } catch (error) {
      pdfWindow?.close();
      toast({
        variant: 'destructive',
        title: 'Download failed',
        description: extractErrorMessage(error),
      });
    }
  };

  const getExitPaperContext = async (invoice: WarehouseFeeInvoice) => {
    const [booking, inventoryRows] = await Promise.all([
      invoice.bookingId
        ? bookingsService.getById(invoice.bookingId).catch(() => null)
        : Promise.resolve(null),
      invoice.bookingId
        ? warehouseService.listInventory({ bookingId: invoice.bookingId }).then((response) => response.data).catch(() => [])
        : Promise.resolve([]),
    ]);
    const inventory = inventoryRows.find((item) => item.id === invoice.inventoryId) ?? inventoryRows[0] ?? undefined;
    return { booking, inventory };
  };

  const handleGateClearance = async (invoice: WarehouseFeeInvoice) => {
    if (!invoice.inventoryId) {
      toast({
        variant: 'destructive',
        title: 'Gate clearance failed',
        description: 'This invoice is not linked to an inventory item.',
      });
      return;
    }

    const pdfWindow = window.open('', '_blank');
    try {
      const releasedAt = new Date();
      const releasedItem = await gateClear.mutateAsync(invoice.inventoryId);
      let documentResponse: Awaited<ReturnType<typeof warehouseService.downloadReleaseDocument>>;
      try {
        documentResponse = await warehouseService.downloadReleaseDocument(invoice.inventoryId);
      } catch (documentError) {
        const context = await getExitPaperContext(invoice);
        const fallbackBlob = buildWarehouseExitPaperPdf({
          invoice,
          releasedItem,
          inventory: context.inventory,
          booking: context.booking,
          releasedAt,
        });
        const opened = openPdfBlob(
          fallbackBlob,
          `release-${releasedItem?.booking?.reference ?? releasedItem?.bookingId ?? invoice.inventoryId}.pdf`,
          pdfWindow,
        );
        toast({
          title: 'Gate clearance recorded',
          description: opened
            ? 'The API exit paper failed, so a sealed fallback PDF opened instead.'
            : `The API exit paper failed (${extractErrorMessage(documentError)}), so a sealed fallback PDF was downloaded.`,
        });
        onClose();
        return;
      }
      const filename = `release-${releasedItem?.booking?.reference ?? releasedItem?.bookingId ?? invoice.inventoryId}.pdf`;
      const opened = openPdfBlob(documentResponse.data, filename, pdfWindow);
      toast({
        title: 'Gate clearance recorded',
        description: opened
          ? 'The exit paper opened in a browser tab.'
          : 'The browser blocked the preview tab, so the exit paper was downloaded.',
      });
      onClose();
    } catch (e) {
      pdfWindow?.close();
      toast({
        variant: 'destructive',
        title: 'Gate clearance failed',
        description: extractErrorMessage(e),
      });
    }
  };

  const handlePay = async () => {
    if (!inv || !payAmount) return;
    try {
      const paidInvoice = await pay.mutateAsync({
        id: inv.id,
        payload: {
          amount: Number(payAmount),
          method: 'MANUAL',
          driverName: driverName.trim() || undefined,
          driverPhone: driverPhone.trim() || undefined,
        },
      });
      setPayAmount('');
      setDriverName('');
      setDriverPhone('');
      if (paidInvoice.status === 'PAID') {
        toast({ title: 'Payment recorded', description: 'Downloading receipt, then generating gate clearance and exit paper.' });
        await downloadReceiptPdf(paidInvoice);
        await handleGateClearance(paidInvoice);
      } else {
        toast({ title: 'Payment recorded' });
      }
    } catch (e) {
      toast({ variant: 'destructive', title: 'Payment failed', description: extractErrorMessage(e) });
    }
  };

  const handleOnlinePay = async () => {
    if (!inv) return;
    try {
      const currentUrl = window.location.href;
      const result = await payOnline.mutateAsync({
        id: inv.id,
        payload: {
          method: gatewayMethod,
          platform: 'web',
          payerAccount: payerAccount.trim() || undefined,
          returnUrl: currentUrl,
          failureUrl: currentUrl,
        },
      });
      const url = result.clientAction?.url;
      if (url) {
        window.location.href = url;
        return;
      }
      toast({
        title: 'Payment initiated',
        description: 'No redirect URL was returned by the payment provider.',
      });
    } catch (e) {
      toast({ variant: 'destructive', title: 'Payment failed', description: extractErrorMessage(e) });
    }
  };

  const handleCancel = async () => {
    if (!inv) return;
    try {
      await cancel.mutateAsync(inv.id);
      toast({ title: 'Invoice cancelled' });
      onClose();
    } catch (e) {
      toast({ variant: 'destructive', title: 'Cancel failed', description: extractErrorMessage(e) });
    }
  };

  return (
    <Modal opened={Boolean(id)} onClose={onClose} title="Fee invoice" centered size="lg">
      {isLoading || !inv ? (
        <Group justify="center" py="xl"><Loader /></Group>
      ) : (
        <Stack gap="sm">
          <Group justify="space-between">
            <Text fw={700} size="lg">{inv.invoiceNumber}</Text>
            <Badge variant="light" color={STATUS_COLOR[inv.status]} size="lg">{inv.status.replace(/_/g, ' ')}</Badge>
          </Group>

          <Table withRowBorders={false} verticalSpacing={4}>
            <Table.Tbody>
              {(inv.items ?? []).map((it) => (
                <Table.Tr key={it.id}>
                  <Table.Td>
                    <Text size="sm">{it.description}</Text>
                    <Text size="xs" c="dimmed">{it.feeType.replace(/_/g, ' ')} · {it.chargeableDays ?? 0} day(s) @ {fmt(it.unitRate, it.currency)}</Text>
                  </Table.Td>
                  <Table.Td ta="right"><Text fw={600}>{fmt(it.amount, it.currency)}</Text></Table.Td>
                </Table.Tr>
              ))}
            </Table.Tbody>
          </Table>

          <Divider />
          <Group justify="space-between"><Text size="sm" c="dimmed">Subtotal</Text><Text>{fmt(inv.subtotalAmount, inv.currency)}</Text></Group>
          <Group justify="space-between"><Text size="sm" c="dimmed">Tax</Text><Text>{fmt(inv.taxAmount, inv.currency)}</Text></Group>
          <Group justify="space-between"><Text fw={700}>Total</Text><Text fw={700}>{fmt(inv.totalAmount, inv.currency)}</Text></Group>
          <Group justify="space-between"><Text size="sm" c="dimmed">Paid</Text><Text>{fmt(inv.paidAmount, inv.currency)}</Text></Group>
          <Group justify="space-between"><Text fw={600}>Balance</Text><Text fw={600}>{fmt(inv.balanceAmount, inv.currency)}</Text></Group>

          {(inv.payments ?? []).length > 0 && (
            <>
              <Divider label="Payment history" labelPosition="left" />
              {(inv.payments ?? []).map((p, i) => (
                <Group key={i} justify="space-between">
                  <Text size="xs" c="dimmed">{fmtDate(p.paidAt)} · {p.method ?? '—'}{p.reference ? ` · ${p.reference}` : ''}</Text>
                  <Text size="sm">{fmt(p.amount, inv.currency)}</Text>
                </Group>
              ))}
            </>
          )}

          {canPay && (
            <>
              <Divider label="Online payment" labelPosition="left" />
              <Group align="flex-end">
                <Select
                  label="Provider"
                  value={gatewayMethod}
                  onChange={(v) => setGatewayMethod((v as WarehouseGatewayPaymentMethod) ?? 'TELEBIRR')}
                  data={[
                    { value: 'TELEBIRR', label: 'Telebirr' },
                    { value: 'WAAFI', label: 'Waafi' },
                  ]}
                  style={{ flex: 1 }}
                />
                <TextInput
                  label="Wallet phone / account"
                  value={payerAccount}
                  onChange={(e) => setPayerAccount(e.currentTarget.value)}
                  placeholder="Optional"
                  style={{ flex: 1 }}
                />
                <Button leftSection={<CreditCard size={16} />} loading={payOnline.isPending} onClick={handleOnlinePay}>
                  Pay with {gatewayMethod === 'WAAFI' ? 'Waafi' : 'Telebirr'}
                </Button>
              </Group>

              <Divider label="Record manual payment" labelPosition="left" />
              <Group align="flex-end">
                <NumberInput
                  label="Amount"
                  min={0}
                  value={payAmount}
                  onChange={(v) => setPayAmount(v === '' ? '' : Number(v))}
                  style={{ flex: 1 }}
                />
                <TextInput
                  label="Pickup driver"
                  value={driverName}
                  onChange={(e) => setDriverName(e.currentTarget.value)}
                  style={{ flex: 1 }}
                />
                <TextInput
                  label="Driver phone"
                  value={driverPhone}
                  onChange={(e) => setDriverPhone(e.currentTarget.value)}
                  style={{ flex: 1 }}
                />
                <Button leftSection={<CreditCard size={16} />} loading={pay.isPending} onClick={handlePay}>
                  Pay
                </Button>
              </Group>
            </>
          )}

          <Group justify="flex-end" mt="sm">
            {inv.bookingId && (
              <Button
                variant="subtle"
                color="gray"
                leftSection={<ExternalLink size={16} />}
                onClick={() =>
                  navigate(
                    `/dashboard/booking-requests/${inv.bookingId}#warehouse-payments`,
                  )
                }
              >
                View booking
              </Button>
            )}
            <Button
              variant="light"
              color="gray"
              leftSection={<Download size={16} />}
              onClick={() => downloadInvoicePdf(inv)}
            >
              Invoice PDF
            </Button>
            {Number(inv.paidAmount) > 0 && (
              <Button
                variant="light"
                color="teal"
                leftSection={<Receipt size={16} />}
                onClick={() => downloadReceiptPdf(inv)}
              >
                Receipt PDF
              </Button>
            )}
            {canGateClear && (
              <Button
                color="edr-green"
                leftSection={<DoorOpen size={16} />}
                loading={gateClear.isPending}
                onClick={() => handleGateClearance(inv)}
              >
                Gate clearance & exit paper
              </Button>
            )}
            {inv.status !== 'PAID' && inv.status !== 'CANCELLED' && (
              <Button variant="light" color="red" leftSection={<Ban size={16} />} loading={cancel.isPending} onClick={handleCancel}>
                Cancel invoice
              </Button>
            )}
          </Group>
        </Stack>
      )}
    </Modal>
  );
}
