import { Group, Tabs } from "@mantine/core";
import { useMutation, useQuery } from "@tanstack/react-query";
import { CreditCard, FileText, LayoutGrid } from "lucide-react";
import { useState } from "react";
import { useNavigate } from "react-router-dom";

import { api } from "@/services/api";
import { useFileViewer } from "@/hooks/useFileViewer";
import { invoicesService } from "@/services/invoices.service";
import { paymentsService, type PaymentMethod } from "@/services/payments.service";
import { isPayable } from "@/pages/billing/invoice-ui";
import type { Freight } from "@edr/types";

import { ApproveDeliveryButton } from "../delivery/ApproveDeliveryButton";
import { ActivityCard } from "./components/ActivityCard";
import { ClearanceCard } from "./components/ClearanceCard";
import { DocumentsTab } from "./components/DocumentsTab";
import { CompanyInfoCard } from "./components/CompanyInfoCard";
import { ContainersCard } from "./components/ContainersCard";
import { ContractCard } from "./components/ContractCard";
import { ContractInfoCard } from "./components/ContractInfoCard";
import { CustomerTruckAssignmentCard } from "./components/CustomerTruckAssignmentCard";
import { KeyFactsStrip } from "./components/KeyFactsStrip";
import { MileSummaryCard } from "./components/MileSummaryCard";
import { BodyGrid, PageShell } from "./components/layout";
import {
  CancelledBanner,
  ConsolidationPairedNotice,
  ConsolidationWaitingBanner,
} from "./components/Notices";
import { BookingPaymentPanel } from "./components/BookingPaymentPanel";
import { HeaderButton, PageHeader } from "./components/PageHeader";
import { PaymentMethodModal } from "./components/PaymentMethodModal";
import { ScheduleCard } from "./components/ScheduleCard";
import { WarehousePaymentsSection } from "./components/WarehousePaymentsSection";
import { WarehouseLocationCard } from "./components/WarehouseLocationCard";
import { ShipmentDetailsCard } from "./components/ShipmentDetailsCard";
import { ShipmentTrackingCard } from "./components/ShipmentTrackingCard";
import { StatusHero } from "./components/StatusHero";
import { SupportCard } from "./components/SupportCard";
import { fmtDate, isNegative, priceTotal } from "./utils";
import { useScrollToHash } from "@/hooks/useScrollToHash";

export function ReadonlyBookingView({
  booking,
  onBookingUpdated,
}: {
  booking: Freight.IBooking;
  onBookingUpdated?: () => void;
}) {
  const navigate = useNavigate();
  // Deep-link support: e.g. /bookings/:id#warehouse-payments from an invoice.
  useScrollToHash();
  const status = booking.status as string;
  const [payModalOpen, setPayModalOpen] = useState(false);
  const { viewer } = useFileViewer();

  // Re-book opens the New Shipment Booking form for the same contract, not the
  // New Contract page. Fall back to /contracts/new only if the link is missing.
  const rebookTo = booking.contractId
    ? `/contracts/${booking.contractId}/bookings/new`
    : "/contracts/new";
  const onRebook = () => navigate(rebookTo);

  // Billing is invoice-centric — resolve the booking's currently payable
  // invoice (same query/key BookingPaymentPanel uses, so this shares its
  // cache) and pay it through the ownership-checked portal route.
  const { data: bookingInvoices = [] } = useQuery({
    queryKey: ["booking-invoices", booking.id],
    queryFn: () => invoicesService.listForSource("booking", booking.id),
  });
  const payableInvoiceId = bookingInvoices.find((inv) =>
    isPayable(inv.status),
  )?.id;

  // POST /billing/my-invoices/:id/pay creates the intent and returns the
  // provider's redirect URL (clientAction.url). Send the browser straight
  // there; fall back to the public /payments/checkout page if no redirect
  // URL came back.
  const payMutation = useMutation({
    mutationFn: (method: PaymentMethod) => {
      if (!payableInvoiceId) {
        throw new Error(
          "No payable invoice found for this booking yet. Please refresh or contact support.",
        );
      }
      return api.invoices.pay.call({
        id: payableInvoiceId,
        payload: { method, platform: "web" },
      });
    },
    onSuccess: (data, method) => {
      const redirectUrl =
        data?.clientAction?.type === "REDIRECT" && data.clientAction.url
          ? data.clientAction.url
          : paymentsService.checkoutUrlForInvoice({
              invoiceId: payableInvoiceId!,
              method,
            });
      window.location.href = redirectUrl;
    },
  });

  const pricing = booking.pricingBreakdown;
  // A general contract is paid once it's FULLY_EXECUTED (signed) — it never
  // enters batch selection. A one-time booking can only pay once it's been
  // SELECTED_FOR_BATCH (assigned a slot with a pay window).
  const isGeneralContract = booking.bookingType === "GENERAL_CONTRACT";
  const canPay =
    booking.paymentStatus !== "PAID" &&
    (isGeneralContract
      ? status === "FULLY_EXECUTED"
      : status === "SELECTED_FOR_BATCH");
  // Approve delivery tracks the handover lifecycle exactly: the button appears
  // the moment a handover is generated (truck arrival, or an operator's
  // signature request) and disappears the moment the customer signs it. The
  // backend flag counts only unsigned SELF_HAUL handovers, so no status
  // heuristics are needed here.
  const canApproveDelivery = Boolean(booking.handoverAwaitingSignature);
  const usesCustomerTruck =
    booking.tradeDirection === "IMPORT"
      ? !booking.lastMileDeliveryAddress
      : booking.tradeDirection === "EXPORT"
        ? !booking.firstMilePickupAddress
        : !booking.firstMilePickupAddress && !booking.lastMileDeliveryAddress;
  const canAssignCustomerTruck =
    booking.paymentStatus === "PAID" &&
    usesCustomerTruck &&
    (booking.tradeDirection === "IMPORT"
      ? // Import self-haul: pickup trucks are assigned only after the train has
        // arrived at the destination.
        status === "ARRIVED"
      : // Export / domestic self-haul: delivery trucks are assigned only before
        // the cargo is loaded onto the train (PAID / TRUCK_ASSIGNED). Once loaded
        // (IN_TRANSIT and beyond) assignment is closed.
        ["PAID", "TRUCK_ASSIGNED"].includes(status));
  const showCountdown = canPay && !!booking.paymentDeadline;
  const isExpired = status === "EXPIRED";
  // Customs (Path B) bookings are created AND rebooked by Global Logistics, not
  // the customer. Hide the customer's rebook everywhere and tell them GL will
  // handle it. Non-customs bookings stay self-service.
  const isCustoms = Boolean(booking.customsClearingEnabled);
  const canSelfRebook = !isCustoms;
  const isPendingConsolidation = status === "PENDING_CONSOLIDATION";
  const isClearance = [
    "AWAITING_DOCUMENTS",
    "DOCUMENTS_UNDER_REVIEW",
    "CLEARANCE_READY",
    "OPERATION_REQUESTED",
  ].includes(status);
  // Paired: a consolidation partner was found and the booking resumed the normal
  // flow. Surface the "partner found" reassurance only in the early stages,
  // before approval, so it doesn't linger for the rest of the booking's life.
  const showPairedNotice =
    !!booking.consolidationPartnerId &&
    ["SUBMITTED", "PENDING_APPROVAL", "CHANGES_REQUESTED"].includes(status);

  return (
    <PageShell>
      <PageHeader
        booking={booking}
        actions={
          (canApproveDelivery || (canPay && !showCountdown)) && (
            <Group gap={8} wrap="nowrap">
              {canApproveDelivery && (
                <ApproveDeliveryButton bookingId={booking.id} />
              )}
              {canPay && !showCountdown && (
                <HeaderButton
                  green
                  icon={<CreditCard size={16} />}
                  label="Pay now"
                  onClick={() => setPayModalOpen(true)}
                />
              )}
            </Group>
          )
        }
        menuActions={{
          onRebook: canSelfRebook ? onRebook : undefined,
          onSupport: () => navigate("/support"),
        }}
      />

      {isNegative(status) ? (
        <CancelledBanner
          pillLabel={status === "REJECTED" ? "Rejected" : "Cancelled"}
          title={`This booking was ${
            status === "REJECTED" ? "rejected" : "cancelled"
          } on ${fmtDate(booking.updatedAt)}.`}
          subtitle={
            status === "REJECTED"
              ? "This booking request has been rejected."
              : "This booking process has been terminated."
          }
          reason={booking.latestChangeRequestNote}
          onRebook={canSelfRebook ? onRebook : undefined}
        />
      ) : isExpired ? (
        <CancelledBanner
          pillLabel="Expired"
          title={`The payment window expired on ${fmtDate(booking.updatedAt)}.`}
          subtitle={
            isCustoms
              ? "Payment wasn't completed in time, so this booking lost its slot. Global Logistics will rebook this shipment for you — no action is needed on your side."
              : "Payment wasn't completed in time, so this booking lost its slot. Rebook to try another schedule."
          }
          onRebook={canSelfRebook ? onRebook : undefined}
        />
      ) : isPendingConsolidation ? (
        <ConsolidationWaitingBanner
          priceLabel={pricing ? priceTotal(pricing) : undefined}
        />
      ) : (
        <StatusHero booking={booking} />
      )}

      {showPairedNotice && <ConsolidationPairedNotice />}

      <KeyFactsStrip booking={booking} />

      <Tabs
        defaultValue="overview"
        keepMounted={false}
        styles={{
          list: { gap: 6, borderBottom: "1px solid #E6ECF2" },
          tab: { borderRadius: "10px 10px 0 0", fontWeight: 700, padding: "10px 16px" },
        }}
      >
        <Tabs.List mb="lg">
          <Tabs.Tab value="overview" leftSection={<LayoutGrid size={15} />}>
            Overview
          </Tabs.Tab>
          <Tabs.Tab value="documents" leftSection={<FileText size={15} />}>
            Documents
          </Tabs.Tab>
        </Tabs.List>

        <Tabs.Panel value="overview">
          <div className="flex flex-col gap-6">
            <ContractCard booking={booking} />

            {isClearance && <ClearanceCard booking={booking} />}

            <BodyGrid
              left={
                <>
                  <ShipmentDetailsCard booking={booking} />

                  <ContainersCard booking={booking} />

                  <WarehouseLocationCard bookingId={booking.id} />

                  <ContractInfoCard booking={booking} />

                  <ShipmentTrackingCard bookingId={booking.id} />

                  {canAssignCustomerTruck && (
                    <CustomerTruckAssignmentCard
                      booking={booking}
                      onAssigned={onBookingUpdated ?? (() => {})}
                    />
                  )}
                  <WarehousePaymentsSection bookingId={booking.id} />

                  <ActivityCard booking={booking} />

                  <MileSummaryCard booking={booking} />
                </>
              }
              right={
                <>
                  <BookingPaymentPanel
                    booking={booking}
                    pricing={pricing}
                    onPay={() => setPayModalOpen(true)}
                    paying={payMutation.isPending}
                    showCountdown={showCountdown}
                  />
                  <ScheduleCard
                    booking={booking}
                    title="Consignment & Schedule"
                    consignment
                  />
                  <CompanyInfoCard booking={booking} />
                  <SupportCard />
                </>
              }
            />
          </div>
        </Tabs.Panel>

        <Tabs.Panel value="documents">
          <DocumentsTab booking={booking} />
        </Tabs.Panel>
      </Tabs>

      <PaymentMethodModal
        opened={payModalOpen}
        onClose={() => {
          if (!payMutation.isPending) {
            setPayModalOpen(false);
            payMutation.reset();
          }
        }}
        amountLabel={pricing ? priceTotal(pricing) : undefined}
        currency={pricing?.currency ?? booking.paymentCurrency}
        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)}
      />
      {viewer}
    </PageShell>
  );
}
