import { ActionIcon, Box, Button, Group, Stack, Text } from "@mantine/core";
import { useQuery } from "@tanstack/react-query";
import {
  CheckCircle2,
  CreditCard,
  Download,
  FileText,
  Receipt,
  Timer,
} from "lucide-react";
import { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import toast from "react-hot-toast";

import type { Freight } from "@edr/types";

import { invoicesService, type PortalInvoice } from "@/services/invoices.service";
import { InvoiceStatusBadge, titleCase } from "@/pages/billing/invoice-ui";
import { paymentStatusLabel } from "@/pages/bookings/booking-display";
import { saveBlob } from "@/utils/download";

import { fmtDate, priceLineItems, priceTotal, type Pricing } from "../utils";
import { CardTitle, SectionCard } from "./layout";

const Divider = () => <Box my={16} h={1} w="100%" bg="#EEF2F6" />;

// ── Pay-window countdown ─────────────────────────────────────────────────────

interface Remaining {
  days: number;
  hours: number;
  minutes: number;
  seconds: number;
  expired: boolean;
}

function getRemaining(deadlineMs: number): Remaining {
  const diff = deadlineMs - Date.now();
  if (diff <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0, expired: true };
  const total = Math.floor(diff / 1000);
  return {
    days: Math.floor(total / 86400),
    hours: Math.floor((total % 86400) / 3600),
    minutes: Math.floor((total % 3600) / 60),
    seconds: total % 60,
    expired: false,
  };
}

function Segment({ value, label }: { value: number; label: string }) {
  return (
    <Stack gap={2} align="center" style={{ minWidth: 52 }}>
      <Text fz="26px" fw={800} c="#10202F" lh={1} style={{ fontVariantNumeric: "tabular-nums" }}>
        {String(value).padStart(2, "0")}
      </Text>
      <Text fz="10.5px" fw={700} c="#9AA8B5" tt="uppercase" style={{ letterSpacing: "0.6px" }}>
        {label}
      </Text>
    </Stack>
  );
}

function Countdown({
  deadline,
  onPay,
  paying,
}: {
  deadline: string;
  onPay?: () => void;
  paying?: boolean;
}) {
  const deadlineMs = new Date(deadline).getTime();
  const [remaining, setRemaining] = useState<Remaining>(() => getRemaining(deadlineMs));

  useEffect(() => {
    setRemaining(getRemaining(deadlineMs));
    const interval = setInterval(() => {
      const next = getRemaining(deadlineMs);
      setRemaining(next);
      if (next.expired) clearInterval(interval);
    }, 1000);
    return () => clearInterval(interval);
  }, [deadlineMs]);

  if (remaining.expired) {
    return (
      <Text fz="13.5px" c="#6B7C8E">
        The payment window has closed. Move this booking to another schedule or
        contact support.
      </Text>
    );
  }

  return (
    <>
      <Group justify="space-between" wrap="nowrap" px={4}>
        <Segment value={remaining.days} label="Days" />
        <Segment value={remaining.hours} label="Hrs" />
        <Segment value={remaining.minutes} label="Min" />
        <Segment value={remaining.seconds} label="Sec" />
      </Group>
      <Text mt={12} fz="12px" c="#9AA8B5">
        Deadline:{" "}
        {new Date(deadline).toLocaleString(undefined, {
          month: "short",
          day: "numeric",
          hour: "2-digit",
          minute: "2-digit",
        })}
      </Text>
      {onPay && (
        <Button
          fullWidth
          mt={14}
          radius={10}
          color="edr-green"
          leftSection={<CreditCard size={17} />}
          onClick={onPay}
          loading={paying}
          styles={{ root: { height: 46 }, label: { fontSize: 13.5, fontWeight: 700 } }}
        >
          Pay now
        </Button>
      )}
    </>
  );
}

// ── Partial-capacity batch offer ─────────────────────────────────────────────

/**
 * Present on the booking (status SELECTED_FOR_BATCH) when only part of it fit
 * the train. Paying accepts the split; not paying keeps the booking whole and
 * it expires for this train. Local extension — not yet in @edr/types.
 */
interface ActiveBatchOffer {
  offeredWagons: number;
  totalWagons: number;
  offeredAmount: number;
  paymentDeadline: string;
}

function PartialOfferNotice({ offer }: { offer: ActiveBatchOffer }) {
  const remaining = offer.totalWagons - offer.offeredWagons;
  return (
    <Box
      mt={14}
      p={14}
      style={{
        borderRadius: 10,
        backgroundColor: "#FEF6E6",
        border: "1px solid #F3E2B8",
      }}
    >
      <Text fz="13px" fw={800} c="#9A5B00">
        Partial allocation offer
      </Text>
      <Text mt={4} fz="12.5px" c="#7A5A1E" lh={1.55}>
        {offer.offeredWagons} of {offer.totalWagons} wagons fit this train.
        Paying accepts the split — the remaining {remaining} wagon
        {remaining === 1 ? "" : "s"} return to your contract to book in a later
        window. If you don&apos;t pay before the deadline, your booking stays
        whole and can be rebooked next window.
      </Text>
    </Box>
  );
}

// ── Merged payment panel ─────────────────────────────────────────────────────

/**
 * One card covering the whole payment story for a booking: the live pay-window
 * countdown (when open), the price breakdown, and the invoice(s) — each with a
 * link to its detail page and a download. Replaces the separate deadline +
 * breakdown cards.
 */
export function BookingPaymentPanel({
  booking,
  pricing,
  onPay,
  paying,
  showCountdown,
}: {
  booking: Freight.IBooking & { activeBatchOffer?: ActiveBatchOffer | null };
  pricing: Pricing;
  onPay?: () => void;
  paying?: boolean;
  showCountdown?: boolean;
}) {
  const navigate = useNavigate();
  const paid = booking.paymentStatus === "PAID";
  const isAdjusted =
    booking.adjustedTotalAmount !== null &&
    booking.adjustedTotalAmount !== undefined;
  const currency = pricing?.currency ?? booking.paymentCurrency;
  const total = isAdjusted
    ? `${Number(booking.adjustedTotalAmount).toLocaleString()} ${currency}`
    : priceTotal(pricing);
  const items = priceLineItems(pricing);

  // Consolidation: this shipment shares a wagon with a partner booking, and the
  // wagon is only scheduled once both partners have paid. Surface a note while
  // payment is still pending (pay-window open, or a deadline set and not paid).
  const showConsolidationNote =
    !paid &&
    Boolean(booking.consolidationPartnerId) &&
    (booking.status === "SELECTED_FOR_BATCH" ||
      Boolean(booking.paymentDeadline));

  const { data: invoices = [] } = useQuery({
    queryKey: ["booking-invoices", booking.id],
    queryFn: () => invoicesService.listForSource("booking", booking.id),
  });

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

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

  return (
    <SectionCard p={22}>
      <Group justify="space-between" align="center">
        <CardTitle>Payment</CardTitle>
        <Group
          component="span"
          gap={6}
          align="center"
          wrap="nowrap"
          style={{
            display: "inline-flex",
            borderRadius: 999,
            padding: "5px 11px",
            fontSize: 11.5,
            fontWeight: 700,
            backgroundColor: paid ? "#ECF6F1" : showCountdown ? "#FEF6E6" : "#FDF3E0",
            color: paid ? "#0A6F4D" : showCountdown ? "#B07D14" : "#9A5B00",
            border: paid ? "1px solid #CDEBDD" : undefined,
          }}
        >
          {paid ? <CheckCircle2 size={13} /> : showCountdown ? <Timer size={13} /> : null}
          {paid
            ? "Paid"
            : showCountdown
              ? "Pay window open"
              : paymentStatusLabel(booking.paymentStatus ?? "PENDING")}
        </Group>
      </Group>

      {!paid && booking.activeBatchOffer && (
        <PartialOfferNotice offer={booking.activeBatchOffer} />
      )}

      {showCountdown && booking.paymentDeadline && (
        <Box mt={16}>
          <Countdown
            deadline={booking.paymentDeadline}
            onPay={onPay}
            paying={paying}
          />
          {showConsolidationNote && (
            <Text mt={12} fz="12px" c="#9AA8B5" lh={1.5}>
              This shipment shares a wagon with a consolidation partner — both
              shipments must be paid for the wagon to be scheduled.
            </Text>
          )}
          <Divider />
        </Box>
      )}

      <Box mt={showCountdown ? 0 : 12}>
        <Text fz="26px" fw={800} c="#10202F">
          {total}
        </Text>
        {isAdjusted && (
          <Box
            component="span"
            mt={6}
            style={{
              display: "inline-block",
              borderRadius: 6,
              backgroundColor: "#EAF1FB",
              padding: "3px 8px",
              fontSize: 11,
              fontWeight: 700,
              color: "#2E5B96",
            }}
          >
            Adjusted by EDR
          </Box>
        )}
        {isAdjusted && booking.adjustmentReason && (
          <Text mt={6} fz="12.5px" c="#6B7C8E">
            {booking.adjustmentReason}
          </Text>
        )}
        {paid && (
          <Text mt={4} fz="12.5px" c="#9AA8B5">
            Paid · {fmtDate(booking.updatedAt)}
          </Text>
        )}
      </Box>

      {items.length > 0 && (
        <>
          <Divider />
          <Stack gap={11}>
            {items.map((it) => (
              <Group key={it.label} justify="space-between" wrap="nowrap">
                <Text fz="13px" c="#6B7C8E">
                  {it.label}
                </Text>
                <Text fz="13px" fw={600} c="#10202F">
                  {it.value}
                </Text>
              </Group>
            ))}
          </Stack>
          <Group
            justify="space-between"
            mt={12}
            pt={14}
            style={{ borderTop: "1px solid #EEF2F6" }}
          >
            <Text fz="14px" fw={800} c="#10202F">
              {isAdjusted ? "Adjusted total" : "Total"}
            </Text>
            <Text fz="15px" fw={800} c="#10202F">
              {total}
            </Text>
          </Group>
        </>
      )}

      {invoices.length > 0 && (
        <>
          <Divider />
          <Group justify="space-between" align="center" mb={10}>
            <CardTitle>Invoices</CardTitle>
            <Text fz="12px" c="#9AA8B5">
              {invoices.length}
            </Text>
          </Group>
          <Stack gap={10}>
            {invoices.map((inv) => (
              <Group key={inv.id} justify="space-between" wrap="nowrap">
                <Box style={{ minWidth: 0 }}>
                  <Text
                    fz="13px"
                    fw={700}
                    c="#10202F"
                    style={{ cursor: "pointer" }}
                    onClick={() => navigate(`/billing/${inv.id}`)}
                  >
                    {inv.invoiceNumber}
                  </Text>
                  <Text fz="12px" c="#9AA8B5">
                    {titleCase(inv.type)}
                  </Text>
                </Box>
                <Group gap={8} wrap="nowrap">
                  <InvoiceStatusBadge status={inv.status} />
                  {invoices.length > 1 && (
                    <>
                      <ActionIcon
                        variant="subtle"
                        color="gray"
                        aria-label="Download invoice"
                        onClick={() => downloadInvoice(inv)}
                      >
                        <Download size={16} />
                      </ActionIcon>
                      {Number(inv.paidAmount) > 0 && (
                        <ActionIcon
                          variant="subtle"
                          color="gray"
                          aria-label="Download receipt"
                          onClick={() => downloadReceipt(inv)}
                        >
                          <Receipt size={16} />
                        </ActionIcon>
                      )}
                    </>
                  )}
                </Group>
              </Group>
            ))}
          </Stack>

          {/* Single invoice: a prominent download instead of a lone row icon. */}
          {invoices.length === 1 && (
            <>
              <Button
                fullWidth
                mt={16}
                variant="default"
                radius={10}
                leftSection={<FileText size={17} color="#475569" />}
                onClick={() => downloadInvoice(invoices[0])}
                styles={{
                  root: { height: 46 },
                  label: { fontSize: 13.5, fontWeight: 700, color: "#10202F" },
                }}
              >
                Download invoice
              </Button>
              {Number(invoices[0].paidAmount) > 0 && (
                <Button
                  fullWidth
                  mt={8}
                  variant="subtle"
                  color="gray"
                  radius={10}
                  leftSection={<Receipt size={17} />}
                  onClick={() => downloadReceipt(invoices[0])}
                  styles={{ root: { height: 42 }, label: { fontSize: 13, fontWeight: 700 } }}
                >
                  Download receipt
                </Button>
              )}
            </>
          )}
        </>
      )}
    </SectionCard>
  );
}
