import { useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import { useMutation, useQuery } from "@tanstack/react-query";
import {
  Alert,
  Box,
  Button,
  Center,
  Divider,
  Group,
  Loader,
  Paper,
  SimpleGrid,
  Stack,
  Table,
  Text,
  Title,
} from "@mantine/core";
import {
  ArrowLeft,
  CreditCard,
  Download,
  ExternalLink,
  Receipt,
} from "lucide-react";
import toast from "react-hot-toast";

import { api } from "@/services/api";
import { invoicesService } from "@/services/invoices.service";
import {
  paymentsService,
  type PaymentMethod,
} from "@/services/payments.service";
import { warehouseInvoicesService } from "@/services/warehouse-invoices.service";
import { PaymentMethodModal } from "@/pages/bookings/BookingDetailPage/components/PaymentMethodModal";
import { saveBlob } from "@/utils/download";
import { formatCurrency } from "@/lib/currency";
import { BORDER, INK, MUTED } from "../contracts/contract-ui";
import {
  billedTo,
  fmtDate,
  InvoiceStatusBadge,
  isPayable,
  titleCase,
} from "./invoice-ui";

function MetaItem({ label, value }: { label: string; value: string }) {
  return (
    <Box>
      <Text
        fz={11}
        fw={700}
        c={MUTED}
        style={{ textTransform: "uppercase", letterSpacing: "0.05em" }}
      >
        {label}
      </Text>
      <Text fz={14} mt={4} style={{ color: INK }}>
        {value}
      </Text>
    </Box>
  );
}

export default function InvoiceDetailPage() {
  const { id = "" } = useParams();
  const navigate = useNavigate();
  const {
    data: invoice,
    isLoading,
    isError,
  } = useQuery(api.invoices.get.queryOptions({ input: { id } }));

  const [payModalOpen, setPayModalOpen] = useState(false);

  // Ownership-checked: POST /billing/my-invoices/:id/pay only ever charges
  // one of the signed-in customer's own invoices (unlike the admin-facing
  // /payments/initiate, which takes any invoiceId with no ownership check).
  const payMutation = useMutation({
    mutationFn: (method: PaymentMethod) =>
      api.invoices.pay.call({ id, payload: { method, platform: "web" } }),
    onSuccess: (data, method) => {
      const redirectUrl =
        data?.clientAction?.type === "REDIRECT" && data.clientAction.url
          ? data.clientAction.url
          : paymentsService.checkoutUrlForInvoice({ invoiceId: id, method });
      window.location.href = redirectUrl;
    },
  });

  if (isLoading) {
    return (
      <Center py={80}>
        <Loader color="edr-green" />
      </Center>
    );
  }

  if (isError || !invoice) {
    return (
      <Box style={{ padding: "28px 32px" }}>
        <Button
          variant="subtle"
          color="gray"
          leftSection={<ArrowLeft size={16} />}
          onClick={() => navigate("/billing")}
          mb="md"
        >
          Back to invoices
        </Button>
        <Alert color="red" title="Invoice not found">
          We couldn't load this invoice. It may not exist or you may not have
          access to it.
        </Alert>
      </Box>
    );
  }

  const payable = isPayable(invoice.status);
  const lines = invoice.lines ?? [];
  // The backend charges the outstanding balance, not the invoice total — a
  // partially-paid invoice must show the remaining amount on the pay button.
  const amountDue = Number(invoice.balanceAmount ?? invoice.totalAmount);

  const handlePay = () => {
    setPayModalOpen(true);
  };

  const hasReceipt = Number(invoice.paidAmount) > 0;
  const canViewSource =
    invoice.source === "booking" || invoice.source === "warehouse";

  const downloadInvoice = async () => {
    try {
      saveBlob(
        await invoicesService.downloadDocument(id),
        `invoice-${invoice.invoiceNumber}.pdf`,
      );
    } catch {
      toast.error("Invoice PDF isn't ready yet. Contact EDR if this persists.");
    }
  };

  const downloadReceipt = async () => {
    try {
      saveBlob(
        await invoicesService.downloadReceipt(id),
        `receipt-${invoice.invoiceNumber}.pdf`,
      );
    } catch {
      toast.error("Receipt isn't available yet.");
    }
  };

  // The source link: a booking invoice goes straight to the booking; a warehouse
  // fee invoice resolves its booking (via the warehouse view) and deep-links to
  // that booking's warehouse-payments section.
  const viewSource = async () => {
    if (invoice.source === "booking") {
      navigate(`/bookings/${invoice.sourceId}`);
      return;
    }
    if (invoice.source === "warehouse") {
      try {
        const wh = await warehouseInvoicesService.get(invoice.id);
        if (wh?.bookingId) {
          navigate(`/bookings/${wh.bookingId}#warehouse-payments`);
          return;
        }
      } catch {
        /* fall through to the toast below */
      }
      toast.error("This invoice's source isn't linked to a booking.");
    }
  };

  return (
    <Box style={{ padding: "28px 32px 32px" }}>
      <Stack gap="lg">
        <Button
          variant="subtle"
          color="gray"
          leftSection={<ArrowLeft size={16} />}
          onClick={() => navigate("/billing")}
          style={{ alignSelf: "flex-start" }}
          styles={{ root: { fontWeight: 600 } }}
        >
          Back to invoices
        </Button>

        {/* Header */}
        <Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
          <Group gap={12} align="center" wrap="wrap">
            <Title
              order={1}
              fw={800}
              fz={26}
              style={{ letterSpacing: "-0.01em" }}
            >
              {invoice.invoiceNumber}
            </Title>
            <InvoiceStatusBadge status={invoice.status} />
          </Group>
          <Group gap={8} wrap="wrap">
            {canViewSource && (
              <Button
                variant="default"
                radius="md"
                size="md"
                leftSection={<ExternalLink size={16} />}
                onClick={viewSource}
                styles={{
                  root: { fontWeight: 600, height: 42, paddingInline: 16 },
                }}
              >
                View source
              </Button>
            )}
            <Button
              variant="default"
              radius="md"
              size="md"
              leftSection={<Download size={16} />}
              onClick={downloadInvoice}
              styles={{
                root: { fontWeight: 600, height: 42, paddingInline: 16 },
              }}
            >
              Download invoice
            </Button>
            {hasReceipt && (
              <Button
                variant="subtle"
                color="gray"
                radius="md"
                size="md"
                leftSection={<Receipt size={16} />}
                onClick={downloadReceipt}
                styles={{
                  root: { fontWeight: 600, height: 42, paddingInline: 16 },
                }}
              >
                Receipt
              </Button>
            )}
            {payable && (
              <Button
                color="edr-green"
                radius="md"
                size="md"
                leftSection={<CreditCard size={16} />}
                loading={payMutation.isPending}
                onClick={handlePay}
                styles={{
                  root: { fontWeight: 600, height: 42, paddingInline: 18 },
                }}
              >
                Pay {formatCurrency(amountDue, invoice.currency)}
              </Button>
            )}
          </Group>
        </Group>

        {/* Summary */}
        <Paper withBorder radius="lg" p="lg" style={{ borderColor: BORDER }}>
          <SimpleGrid cols={{ base: 1, sm: 2, md: 4 }} spacing="lg">
            <MetaItem label="Billed To" value={billedTo(invoice)} />
            <MetaItem
              label="Source"
              value={`${titleCase(invoice.source)} · ${invoice.type}`}
            />
            <MetaItem label="Issued" value={fmtDate(invoice.issuedAt)} />
            <MetaItem label="Due" value={fmtDate(invoice.dueAt)} />
          </SimpleGrid>

          <Divider my="lg" color={BORDER} />

          <Group justify="space-between" align="center">
            <Text
              fz={14}
              fw={700}
              c={MUTED}
              style={{ textTransform: "uppercase", letterSpacing: "0.05em" }}
            >
              Total
            </Text>
            <Text fz={24} fw={800} style={{ color: INK }}>
              {formatCurrency(Number(invoice.totalAmount), invoice.currency)}
            </Text>
          </Group>
        </Paper>

        {/* Line items */}
        <Paper
          withBorder
          radius="lg"
          style={{ borderColor: BORDER, overflow: "hidden" }}
        >
          <Box px="lg" py="md" style={{ borderBottom: `1px solid ${BORDER}` }}>
            <Text fz={15} fw={700} style={{ color: INK }}>
              Line items
            </Text>
          </Box>
          <Box style={{ overflowX: "auto" }}>
            <Table
              verticalSpacing={12}
              horizontalSpacing={20}
              styles={{
                th: {
                  fontSize: 11,
                  fontWeight: 700,
                  letterSpacing: "0.05em",
                  textTransform: "uppercase",
                  color: MUTED,
                  background: "#F8FAFC",
                  borderBottom: `1px solid ${BORDER}`,
                  whiteSpace: "nowrap",
                },
                td: { borderBottom: `1px solid ${BORDER}` },
              }}
            >
              <Table.Thead>
                <Table.Tr>
                  <Table.Th>Charge</Table.Th>
                  <Table.Th ta="right">Qty</Table.Th>
                  <Table.Th ta="right">Unit Rate</Table.Th>
                  <Table.Th ta="right">Amount</Table.Th>
                </Table.Tr>
              </Table.Thead>
              <Table.Tbody>
                {lines.length === 0 && (
                  <Table.Tr>
                    <Table.Td colSpan={4}>
                      <Center py={28}>
                        <Text fz={13} c="dimmed">
                          No line items on this invoice.
                        </Text>
                      </Center>
                    </Table.Td>
                  </Table.Tr>
                )}
                {lines.map((line) => (
                  <Table.Tr key={line.id}>
                    <Table.Td>
                      <Text fz={14} fw={600} style={{ color: INK }}>
                        {titleCase(line.chargeType)}
                      </Text>
                      {line.description && (
                        <Text fz={12} c="dimmed">
                          {line.description}
                        </Text>
                      )}
                    </Table.Td>
                    <Table.Td ta="right">
                      <Text fz={13} style={{ color: INK }}>
                        {Number(line.quantity)}
                      </Text>
                    </Table.Td>
                    <Table.Td ta="right">
                      <Text fz={13} style={{ color: INK }}>
                        {formatCurrency(Number(line.unitRate), line.currency)}
                      </Text>
                    </Table.Td>
                    <Table.Td ta="right">
                      <Text fz={13} fw={700} style={{ color: INK }}>
                        {formatCurrency(Number(line.amount), line.currency)}
                      </Text>
                    </Table.Td>
                  </Table.Tr>
                ))}
              </Table.Tbody>
            </Table>
          </Box>
        </Paper>

        <PaymentMethodModal
          opened={payModalOpen}
          onClose={() => {
            if (!payMutation.isPending) {
              setPayModalOpen(false);
              payMutation.reset();
            }
          }}
          amountLabel={formatCurrency(amountDue, invoice.currency)}
          currency={invoice.currency}
          processing={payMutation.isPending}
          error={
            payMutation.isError
              ? payMutation.error instanceof Error
                ? payMutation.error.message
                : "Could not start payment. Please try again."
              : null
          }
          onConfirm={(method) => payMutation.mutate(method)}
        />
      </Stack>
    </Box>
  );
}
