import { type ReactNode, useMemo, useState } from "react";
import {
  ArrowRight,
  Eye,
  MoreHorizontal,
  Plus,
  Printer,
  Receipt,
  RefreshCw,
  Ruler,
  Trash,
  FileText,
  Truck,
  X,
} from "lucide-react";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { useNavigate } from "react-router-dom";
import type { ColumnDef } from "@edr/ui-common";
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";
import {
  ActionIcon,
  Alert,
  Badge,
  Box,
  Button,
  Card,
  Checkbox,
  Divider,
  Group,
  Menu,
  Modal,
  MultiSelect,
  NumberInput,
  ScrollArea,
  Select,
  SimpleGrid,
  Stack,
  Text,
  TextInput,
  Tooltip,
  UnstyledButton,
} from "@mantine/core";
import type { ArrivalQueueItem, ImportUnloadedItem, WarehouseInventoryItem } from "@/types/warehouse";
import { warehouseService } from "@/services/warehouse.service";
import { bookingsService } from "@/services/bookings.service";

import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { useToast } from "@/hooks/use-toast";
import {
  LAST_MILE_STATUSES,
  type LastMileApiStatus,
  type LastMileRecord,
  type LastMileVehicle,
  lastMileService,
} from "@/services/last-mile.service";
import { vehiclesService } from "@/services/vehicles.service";
import { driversService, type Driver } from "@/services/drivers.service";
import { ReleaseOrderModal, type ReleaseOrderTruckPrefill } from "@/components/warehouses/ReleaseOrderModal";
import { EdrTruckExitPapersModal } from "./EdrTruckExitPapersModal";
import { TruckDetentionModal } from "@/components/operations/TruckDetentionModal";
import { ProofOfDeliveryModal } from "@/components/operations/ProofOfDeliveryModal";
import { LastMileStepper, type LastMileStepState } from "@/components/operations/LastMileSteps";

const formatPrice = (amount: number | string | null | undefined, currency = "ETB") =>
  `${currency || "ETB"} ${(Number(amount) || 0).toLocaleString("en-US", {
    minimumFractionDigits: 2,
    maximumFractionDigits: 2,
  })}`;

const STATUS_META: Record<LastMileApiStatus, { label: string; color: string }> = {
  PAYMENT_PENDING: { label: "Payment Pending", color: "yellow" },
  READY_TO_TRANSIT: { label: "Ready to Transit", color: "blue" },
  IN_TRANSIT: { label: "In Transit", color: "indigo" },
  DELIVERED: { label: "Delivered", color: "green" },
};

// Middle-truncate a long invoice number for the table (full value on hover).
// "INV-20260704-00002" → "INV-2…02"
const shortInvoiceNo = (n: string) =>
  n && n.length > 9 ? `${n.slice(0, 5)}…${n.slice(-2)}` : n;

// Invoice payment state → badge color, keyed by upper-cased status.
const INVOICE_STATUS_META: Record<string, { label: string; color: string }> = {
  PAID: { label: "Paid", color: "green" },
  PARTIALLY_PAID: { label: "Partially Paid", color: "teal" },
  PENDING: { label: "Pending", color: "yellow" },
  UNPAID: { label: "Unpaid", color: "yellow" },
  OPEN: { label: "Open", color: "yellow" },
  ISSUED: { label: "Issued", color: "blue" },
  OVERDUE: { label: "Overdue", color: "red" },
  CANCELLED: { label: "Cancelled", color: "gray" },
  VOID: { label: "Void", color: "gray" },
};

const NEXT_STATUS: Partial<Record<LastMileApiStatus, LastMileApiStatus>> = {
  PAYMENT_PENDING: "READY_TO_TRANSIT",
  READY_TO_TRANSIT: "IN_TRANSIT",
  IN_TRANSIT: "DELIVERED",
};

type AssignmentStatus = "ASSIGNED" | "UNASSIGNED";
type StatusFilter = "ALL" | LastMileApiStatus | AssignmentStatus;

const FILTER_OPTIONS: { value: StatusFilter; label: string }[] = [
  { value: "ALL", label: "All" },
  ...LAST_MILE_STATUSES.filter((s) => s !== "PAYMENT_PENDING").map((s) => ({ value: s as StatusFilter, label: STATUS_META[s].label })),
  { value: "ASSIGNED", label: "Assigned" },
  { value: "UNASSIGNED", label: "Unassigned" },
];

const vehicleLabel = (record: LastMileRecord) => {
  if (!record.vehicle) return null;
  const v = record.vehicle;
  const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber];
  if (v.code) parts.unshift(v.code);
  const plates = [v.powerPlateNo, v.trailerPlateNo].filter(Boolean).join(" / ");
  if (plates) parts.push(plates);
  return parts.join(" · ");
};

/** One vehicle (with trailer) carries two containers. */
const CONTAINERS_PER_VEHICLE = 2;
const containerCount = (record: LastMileRecord) =>
  (record.booking?.bookingContainers ?? []).reduce(
    (sum, c) => sum + (Number(c.quantity) || 0),
    0,
  );
/**
 * Trucks needed for a booking, by container SIZE: a 40ft fills a truck (1 each),
 * two 20ft share one. Falls back to ceil(n / 2) when no size is recorded.
 * 0 when the booking has no container data (bulk).
 */
const requiredVehicles = (record: LastMileRecord) => {
  const lines = record.booking?.bookingContainers ?? [];
  if (!containerCount(record)) return 0;
  let forty = 0;
  let others = 0;
  for (const c of lines) {
    const qty = Number(c.quantity) || 0;
    if ((c.containerSize ?? '').includes('40')) forty += qty;
    else others += qty;
  }
  return forty + Math.ceil(others / CONTAINERS_PER_VEHICLE);
};

/** Real per-physical-container numbers on a booking, in order. Prefers each
 *  line's `units` (the actual numbers) over the line-level number (often a
 *  "TBD-…" placeholder). One entry per physical container, for per-truck prefill. */
const bookingContainerNumbers = (record: LastMileRecord): string[] => {
  const out: string[] = [];
  const real = (n?: string | null): n is string =>
    Boolean(n) && !/^TBD/i.test(n!.trim());
  for (const c of record.booking?.bookingContainers ?? []) {
    const units = [...(c.units ?? [])].sort(
      (a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0),
    );
    if (units.length) {
      for (const u of units) if (real(u.containerNumber)) out.push(u.containerNumber!);
    } else if (real(c.containerNumber)) {
      out.push(c.containerNumber!);
    }
  }
  return out;
};

/** Container badges for a booking: the container number when known, else the
 *  type × quantity. */
const containerLabels = (record: LastMileRecord): string[] => {
  const out: string[] = [];
  for (const c of record.booking?.bookingContainers ?? []) {
    const size = c.containerSize ? ` · ${c.containerSize}` : "";
    if (c.containerNumber) {
      out.push(`${c.containerNumber}${size}`);
    } else {
      const type =
        c.containerType?.code ??
        c.containerType?.label ??
        c.containerType?.name ??
        (c.containerSize || "Container");
      out.push(`${type} × ${c.quantity}`);
    }
  }
  return out;
};

const isAssigned = (record: LastMileRecord) => Boolean(record.vehicleId);

// Paid = record flag set OR its invoice reached PAID.
const isPaidRecord = (r: LastMileRecord) =>
  Boolean((r as { paid?: boolean }).paid) ||
  (r.invoice?.status ?? "").toUpperCase() === "PAID";
// Post payment pending = a post payment is owed but not yet paid.
const isPostPaymentPending = (r: LastMileRecord) =>
  Number(r.remainingPayment) > 0 && !isPaidRecord(r);

const fmtStamp = (iso?: string | null) => {
  if (!iso) return null;
  const d = new Date(iso);
  return Number.isNaN(d.getTime()) ? null : d.toLocaleString();
};

/**
 * Derive the 6-step last-mile workflow state for a record. Step completion is
 * read from the record + its pickup-ready (warehouse release) row:
 * assign→vehicleId, arrived→release order issued, leave→releaseDate,
 * in-transit/delivered→status, distance→exactKm.
 */
const computeLastMileSteps = (
  record: LastMileRecord,
  releaseRow?: ImportUnloadedItem,
): LastMileStepState[] => {
  const exactKm = (record as { exactKm?: number | null }).exactKm;
  // Truck arrival/leave live in the transient warehouse pickup-ready queue and
  // vanish once the item is released. So once the leg is IN_TRANSIT/DELIVERED,
  // treat both as done (the truck must have arrived + left to get there).
  const past = record.status === "IN_TRANSIT" || record.status === "DELIVERED";
  const flags = [
    record.status !== "PAYMENT_PENDING",
    Boolean(record.vehicleId),
    past || Boolean(releaseRow?.releaseOrderReference),
    past || Boolean(releaseRow?.releaseDate),
    past,
    exactKm != null,
    exactKm != null, // Generate Invoice — auto-generated when distance is saved
    record.status === "DELIVERED",
  ];
  // Current step = earliest incomplete one.
  const activeIdx = flags.findIndex((f) => !f);
  const labels = ["Ready to Transit", "Assign vehicle", "Truck arrived", "Truck leave", "In transit", "Add distance", "Generate Invoice", "Delivered"];
  const details: (string | null)[] = [
    null,
    record.vehicle?.plateNumber ?? null,
    releaseRow?.releaseOrderReference ?? null,
    fmtStamp(releaseRow?.releaseDate),
    null,
    exactKm != null ? `${exactKm} KM` : null,
    exactKm != null ? "Invoice ready" : null,
    fmtStamp(releaseRow?.deliveredAt),
  ];
  return labels.map((label, i) => ({
    label,
    done: flags[i],
    active: i === activeIdx,
    detail: details[i],
  }));
};

const bookingRef = (r: LastMileRecord) => r.booking?.reference ?? r.bookingId;
const currencyOf = (r: LastMileRecord) =>
  r.vehicle?.currency ??
  r.vehicleAssignments?.[0]?.vehicle?.currency ??
  r.booking?.paymentCurrency ??
  "ETB";

type LmAssignment = NonNullable<LastMileRecord["vehicleAssignments"]>[number];
const truckShort = (a: LmAssignment) =>
  a.vehicle ? [a.vehicle.code, a.vehicle.plateNumber].filter(Boolean).join(" · ") : a.vehicleId;
/** Billing problems on the trucks that have distance: zero price/km, mixed currency. */
const billingIssues = (r: LastMileRecord) => {
  const trucks = (r.vehicleAssignments ?? []).filter((a) => Number(a.distanceKm) > 0);
  const zeroPrice = trucks.filter((a) => !(Number(a.vehicle?.pricePerKm) > 0)).map(truckShort);
  const currencies = [
    ...new Set(trucks.map((a) => a.vehicle?.currency).filter((c): c is string => Boolean(c))),
  ];
  return { zeroPrice, mixedCurrency: currencies.length > 1, currencies };
};
/**
 * The mile bills as distance × pricePerKm in the vehicle's own currency, so a
 * vehicle missing either field cannot produce an invoice line. Returns the
 * human-readable gap, or null when the vehicle is billable.
 */
const pricingGap = (
  v?: { pricePerKm?: number | string | null; currency?: string | null } | null,
): string | null => {
  if (!v) return null;
  const missing: string[] = [];
  if (!(Number(v.pricePerKm) > 0)) missing.push("Price per KM");
  if (!String(v.currency ?? "").trim()) missing.push("Currency");
  return missing.length ? missing.join(" and ") : null;
};
const customerName = (r: LastMileRecord) => r.booking?.company?.name ?? "—";
const deliveryLocation = (r: LastMileRecord) => r.booking?.lastMileDeliveryAddress ?? "—";
const cargoDesc = (r: LastMileRecord) => {
  const parts = [r.booking?.cargoType?.cargoTypeName ?? r.booking?.cargoType?.label ?? r.booking?.cargoType?.name ?? r.booking?.cargoFreeText].filter(Boolean);
  if (r.booking?.cargoTotalWeightVgm) parts.push(`${r.booking.cargoTotalWeightVgm} t`);
  return parts.join(" · ") || "—";
};
const originYardName = (r: LastMileRecord) =>
  r.booking?.originYard?.label ?? r.booking?.originYard?.name ?? "—";
const contactPersonName = (r: LastMileRecord) =>
  r.booking?.company?.contactPersonName ?? "—";
const contactPhone = (r: LastMileRecord) =>
  r.booking?.company?.contactPersonPhone ?? r.booking?.company?.phone ?? "—";
const requestedDate = (r: LastMileRecord) => {
  const d = r.booking?.scheduledDate;
  return d ? new Date(d).toISOString().slice(0, 10) : "—";
};
const serviceTypeName = (r: LastMileRecord) =>
  r.booking?.serviceType?.label ?? r.booking?.serviceType?.name ?? "—";

const toReleaseInventoryItem = (row: ImportUnloadedItem): WarehouseInventoryItem =>
  ({
    id: row.id,
    bookingId: row.bookingId,
    quantity: 1,
    weight: Number(row.weight) || 0,
    grnNumber: row.grnNumber,
    status: row.currentStatus,
    arrivedAt: row.arrivalTime,
    unloadedAt: row.arrivalTime,
    inspectionStatus: row.inspectionStatus,
    releaseDate: row.releaseDate,
    releaseOrderReference: row.releaseOrderReference,
    handoverDocumentReference: row.handoverDocumentReference,
    handoverDocumentDate: row.handoverDocumentDate,
    deliveredAt: row.deliveredAt,
    // Carries the saved [Exit Inspection] block so truck-leaving prefills the
    // details captured at arrival (plate, driver, tare, gate-in).
    notes: row.notes,
    booking: row.bookingId
      ? {
          id: row.bookingId,
          reference: row.bookingReference ?? row.bookingId,
          tradeDirection: "IMPORT",
          lastMileDeliveryAddress: row.lastMileRequested ? row.pickupOption : null,
          customerTruckPlateNumber: row.customerTruckPlateNumber,
          customerTruckDriverName: row.customerTruckDriverName,
          customerTruckType: row.customerTruckType,
          customerTruckContainerNumber: row.customerTruckContainerNumber,
          customerTruckAssignedAt: row.customerTruckAssignedAt,
        }
      : null,
  }) as unknown as WarehouseInventoryItem;

const releasePrefillFromLastMile = (
  record: LastMileRecord,
  row?: ImportUnloadedItem | null,
  driversById?: Map<string, Driver>,
): ReleaseOrderTruckPrefill => {
  const vehicle = record.vehicle;
  const truckType = [vehicle?.manufacturer, vehicle?.model].filter(Boolean).join(" ").trim();
  const assignedDriver = vehicle?.assignedDriverId ? driversById?.get(vehicle.assignedDriverId) : undefined;
  const assignedDriverName = assignedDriver
    ? `${assignedDriver.firstName ?? ""} ${assignedDriver.lastName ?? ""}`.trim()
    : "";
  return {
    truckPlateNumber: vehicle?.powerPlateNo || vehicle?.plateNumber || null,
    trailerPlateNumber: vehicle?.trailerPlateNo || null,
    driverName: vehicle?.assignedDriverName || assignedDriverName || null,
    driverLicense: assignedDriver?.licenseNumber || null,
    driverPhone: assignedDriver?.phoneNumber || null,
    truckType: vehicle?.vehicleType || truckType || null,
    containerNumber: row?.containerNumber ?? null,
  };
};

const InfoRow = ({ label, value }: { label: string; value: string }) => (
  <Stack gap={2}>
    <Text size="xs" c="dimmed" tt="uppercase" fw={600}>{label}</Text>
    <Text size="sm">{value}</Text>
  </Stack>
);

const BookingInfo = ({ record }: { record: LastMileRecord }) => {
  const hasDeliveryAddress = record.booking?.lastMileDeliveryAddress != null;
  return (
    <Card radius="md" padding="md" withBorder bg="var(--mantine-color-gray-0)">
      <Stack gap="sm">
        <Group justify="space-between">
          <Text fw={600}>{bookingRef(record)}</Text>
          <Group gap="xs">
            <Badge color={STATUS_META[record.status].color} variant="light" size="sm">
              {STATUS_META[record.status].label}
            </Badge>
            <Badge color={isAssigned(record) ? "green" : "orange"} variant="light" size="sm">
              {isAssigned(record) ? "Assigned" : "Unassigned"}
            </Badge>
          </Group>
        </Group>
        <SimpleGrid cols={2} spacing="sm">
          <InfoRow label="Customer" value={customerName(record)} />
          <InfoRow label="Service type" value={serviceTypeName(record)} />
          <InfoRow label="Pickup (origin yard)" value={originYardName(record)} />
          {hasDeliveryAddress && <InfoRow label="Destination" value={deliveryLocation(record)} />}
          <InfoRow label="Cargo" value={cargoDesc(record)} />
          <InfoRow label="Advanced Payment" value={formatPrice(record.advancedPayment, currencyOf(record))} />
          <InfoRow label="Post Payment" value={formatPrice(record.remainingPayment, currencyOf(record))} />
          <InfoRow label="Contact" value={contactPersonName(record)} />
          <InfoRow label="Phone" value={contactPhone(record)} />
          <InfoRow label="Requested date" value={requestedDate(record)} />
          <InfoRow label="Assigned vehicle" value={vehicleLabel(record) ?? "—"} />
          <InfoRow label="Est. Distance (KM)" value={record.estimatedKm != null ? String(record.estimatedKm) : "—"} />
          <InfoRow label="Actual Distance (KM)" value={record.exactKm != null ? String(record.exactKm) : "—"} />
        </SimpleGrid>
      </Stack>
    </Card>
  );
};

type TripSlipVehicle = NonNullable<LastMileRecord["vehicleAssignments"]>[number];

const tripSlipRows = (
  record: LastMileRecord,
  vehicle?: TripSlipVehicle | null,
): [string, string][] => {
  // Per-vehicle block when a specific truck is chosen (its own driver, container(s)
  // and distance); else fall back to the record-level vehicle summary.
  const vehicleRows: [string, string][] = vehicle
    ? [
        [
          "Vehicle",
          vehicle.vehicle
            ? [vehicle.vehicle.code, vehicle.vehicle.plateNumber].filter(Boolean).join(" · ")
            : vehicle.vehicleId,
        ],
        ["Driver", vehicle.vehicle?.assignedDriverName || "—"],
        [
          "Container(s)",
          vehicle.containerNumber || bookingContainerNumbers(record).join(", ") || "—",
        ],
        ["Distance (KM)", vehicle.distanceKm != null ? String(vehicle.distanceKm) : "—"],
      ]
    : [
        ["Vehicle", vehicleLabel(record) ?? "Unassigned"],
        ["Actual Distance (KM)", record.exactKm != null ? String(record.exactKm) : "—"],
      ];
  return [
    ["Customer", customerName(record)],
    ["Service", serviceTypeName(record)],
    ["Pickup (origin yard)", originYardName(record)],
    ["Destination", deliveryLocation(record)],
    ["Cargo", cargoDesc(record)],
    ["Post Payment", formatPrice(record.remainingPayment, currencyOf(record))],
    ...vehicleRows,
    ["Contact", `${contactPersonName(record)} · ${contactPhone(record)}`],
    ["Requested date", requestedDate(record)],
    ["Status", STATUS_META[record.status].label],
  ];
};

const SampleStamp = () => (
  <Box style={{ height: 96, display: "flex", alignItems: "center" }}>
    <Box
      style={{
        width: 96,
        height: 96,
        borderRadius: "50%",
        border: "2px solid var(--mantine-color-teal-7)",
        transform: "rotate(-12deg)",
        display: "flex",
        alignItems: "center",
        justifyContent: "center",
      }}
    >
      <Box
        style={{
          width: 82,
          height: 82,
          borderRadius: "50%",
          border: "1px solid var(--mantine-color-teal-7)",
          color: "var(--mantine-color-teal-7)",
          display: "flex",
          flexDirection: "column",
          alignItems: "center",
          justifyContent: "center",
          textAlign: "center",
          lineHeight: 1.1,
        }}
      >
        <Text size="9px" fw={700} style={{ letterSpacing: 1 }}>EDR FREIGHT</Text>
        <Text size="sm" fw={800}>APPROVED</Text>
        <Text size="8px" fw={600}>OPERATIONS</Text>
      </Box>
    </Box>
  </Box>
);

const SignatureBlock = ({ title, stamp }: { title: string; stamp?: ReactNode }) => (
  <Stack gap="sm" style={{ flex: 1, position: "relative", minHeight: stamp ? 130 : undefined }}>
    <Text fw={600} size="sm">{title}</Text>
    <Group gap="xs" align="flex-end">
      <Text size="sm" c="dimmed">Name:</Text>
      <Box style={{ flex: 1, borderBottom: "1px solid var(--mantine-color-gray-5)", height: 18 }} />
    </Group>
    <Group gap="xs" align="flex-end">
      <Text size="sm" c="dimmed">Signature:</Text>
      <Box style={{ flex: 1, borderBottom: "1px solid var(--mantine-color-gray-5)", height: 18 }} />
    </Group>
    {stamp && (
      <Box style={{ position: "absolute", right: 4, top: 22, opacity: 0.85, pointerEvents: "none" }}>
        {stamp}
      </Box>
    )}
  </Stack>
);

const TripSlipDocument = ({
  record,
  vehicle,
}: {
  record: LastMileRecord;
  vehicle?: TripSlipVehicle | null;
}) => (
  <Stack gap="md">
    <Stack gap={2} align="center">
      <Text fw={700}>EDR Freight</Text>
      <Text size="sm" c="dimmed" tt="uppercase" fw={600}>Last Mile Trip Slip</Text>
    </Stack>
    <Group justify="space-between">
      <Text size="sm" fw={600}>{bookingRef(record)}</Text>
      <Text size="sm" c="dimmed">{requestedDate(record)}</Text>
    </Group>
    <Divider />
    <SimpleGrid cols={2} spacing="xs">
      {tripSlipRows(record, vehicle).map(([label, value]) => (
        <InfoRow key={label} label={label} value={value} />
      ))}
    </SimpleGrid>
    <Divider label="Acknowledgement" labelPosition="center" />
    <Group align="flex-start" gap="xl" wrap="nowrap">
      <SignatureBlock title="Driver" />
      <SignatureBlock title="Operator" stamp={<SampleStamp />} />
    </Group>
  </Stack>
);

const escapeHtml = (v: string) =>
  v.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");

const buildTripSlipHtml = (record: LastMileRecord, vehicle?: TripSlipVehicle | null) => {
  const rows = tripSlipRows(record, vehicle)
    .map(([l, v]) => `<tr><td class="lbl">${escapeHtml(l)}</td><td>${escapeHtml(v)}</td></tr>`)
    .join("");
  const sig = (title: string, withStamp: boolean) => `
    <div class="sign-col">
      <div class="sign-title">${title}</div>
      <div class="sign-field"><span>Name:</span><span class="line"></span></div>
      <div class="sign-field"><span>Signature:</span><span class="line"></span></div>
      ${withStamp ? '<div class="stamp"><div class="ring"><div class="ring-inner"><span>EDR FREIGHT</span><strong>APPROVED</strong><span>OPERATIONS</span></div></div></div>' : ""}
    </div>`;
  return `<!doctype html><html><head><meta charset="utf-8" />
    <title>Trip Slip ${escapeHtml(bookingRef(record))}</title>
    <style>
      * { box-sizing: border-box; }
      body { font-family: Arial, Helvetica, sans-serif; color: #111; margin: 32px; }
      .head { text-align: center; margin-bottom: 16px; }
      .head h1 { font-size: 18px; margin: 0; }
      .head p { font-size: 12px; letter-spacing: 1px; text-transform: uppercase; color: #555; margin: 2px 0 0; }
      .meta { display: flex; justify-content: space-between; font-size: 13px; font-weight: 600; margin: 8px 0; }
      table { width: 100%; border-collapse: collapse; font-size: 13px; margin: 8px 0 20px; }
      td { padding: 5px 6px; border-bottom: 1px solid #eee; vertical-align: top; }
      td.lbl { color: #666; text-transform: uppercase; font-size: 11px; font-weight: 700; width: 40%; }
      .ack { text-align: center; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; color: #777; margin: 16px 0 8px; }
      .signs { display: flex; gap: 32px; }
      .sign-col { flex: 1; position: relative; min-height: 130px; }
      .sign-title { font-weight: 700; font-size: 13px; margin-bottom: 12px; }
      .sign-field { display: flex; gap: 6px; align-items: flex-end; font-size: 12px; color: #666; margin-bottom: 10px; }
      .sign-field .line { flex: 1; border-bottom: 1px solid #888; height: 16px; }
      .stamp { position: absolute; right: 4px; top: 22px; opacity: 0.85; }
      .ring { width: 96px; height: 96px; border-radius: 50%; border: 2px solid #0c7a57; transform: rotate(-12deg); display: flex; align-items: center; justify-content: center; }
      .ring-inner { width: 82px; height: 82px; border-radius: 50%; border: 1px solid #0c7a57; color: #0c7a57; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; line-height: 1.1; }
      .ring-inner span { font-size: 9px; font-weight: 700; letter-spacing: 1px; }
      .ring-inner strong { font-size: 13px; font-weight: 800; }
    </style></head>
    <body>
      <div class="head"><h1>EDR Freight</h1><p>Last Mile Trip Slip</p></div>
      <div class="meta"><span>${escapeHtml(bookingRef(record))}</span><span>${escapeHtml(requestedDate(record))}</span></div>
      <table>${rows}</table>
      <div class="ack">Acknowledgement</div>
      <div class="signs">${sig("Driver", false)}${sig("Operator", true)}</div>
    </body></html>`;
};

const LastMilePage = () => {
  const { toast } = useToast();
  const qc = useQueryClient();
  const [podRecord, setPodRecord] = useState<LastMileRecord | null>(null);
  const navigate = useNavigate();
  const { pagination, setPagination } = usePagination({ pageSize: 10 });

  const [search, setSearch] = useState("");
  const [statusFilter, setStatusFilter] = useState<StatusFilter>("ALL");
  const [filterPostPaymentPending, setFilterPostPaymentPending] = useState(false);
  const [rowSelection, setRowSelection] = useState<Record<string, boolean>>({});

  const [assignOpen, setAssignOpen] = useState(false);
  const [bulkMode, setBulkMode] = useState(false);
  const [detailOpen, setDetailOpen] = useState(false);
  const [tripSlipOpen, setTripSlipOpen] = useState(false);
  const [tripSlipRecord, setTripSlipRecord] = useState<LastMileRecord | null>(null);
  // Which vehicle the trip slip is for (per-truck), + the pre-print picker.
  const [tripSlipVehicleId, setTripSlipVehicleId] = useState<string | null>(null);
  const [tripSlipSelectOpen, setTripSlipSelectOpen] = useState(false);
  const [activeId, setActiveId] = useState<string | null>(null);
  const [detentionRecord, setDetentionRecord] = useState<LastMileRecord | null>(null);
  // Multi-vehicle assign: one row per truck — vehicle + the container it carries.
  // One row per truck. A truck carries one 40ft or up to two 20ft, so the load
  // is a list, not a single container.
  const [vehicleRows, setVehicleRows] = useState<
    Array<{ vehicleId: string | null; containerNumbers: string[] }>
  >([{ vehicleId: null, containerNumbers: [] }]);

  // 2-step "Assign Mile" accept modal (arrival queue → vehicle)
  const [acceptOpen, setAcceptOpen] = useState(false);
  const [acceptStep, setAcceptStep] = useState<1 | 2>(1);
  const [selectedArrivalItems, setSelectedArrivalItems] = useState<ArrivalQueueItem[]>([]);
  const [acceptVehicleValues, setAcceptVehicleValues] = useState<string[]>([]);
  const [arrivalSearch, setArrivalSearch] = useState("");

  const [distanceOpen, setDistanceOpen] = useState(false);
  // Per-vehicle actual distance, keyed by vehicleId.
  const [distanceRows, setDistanceRows] = useState<Record<string, string>>({});
  // Record pending invoice-generation confirmation (shows a summary first).
  const [invoiceConfirm, setInvoiceConfirm] = useState<LastMileRecord | null>(null);

  const [releaseItem, setReleaseItem] = useState<WarehouseInventoryItem | null>(null);
  const [releaseTruckPrefill, setReleaseTruckPrefill] = useState<ReleaseOrderTruckPrefill | null>(null);

  const { data: listData, isLoading } = useQuery({
    queryKey: QUERY_KEYS.LAST_MILE.list(),
    queryFn: async () => {
      const res = await lastMileService.list();
      return res.data;
    },
  });

  const { data: vehiclesData } = useQuery({
    queryKey: ["vehicles", "free"],
    queryFn: async () => {
      const res = await vehiclesService.getAll({ status: "ACTIVE", availability: "FREE" });
      return res.data;
    },
  });

  const records = listData?.data ?? [];
  const existingLastMileBookingIds = useMemo(
    () => new Set(records.map((record) => record.bookingId)),
    [records],
  );

  const needsDriverLookup = records.some((record) => record.vehicle?.assignedDriverId);

  const { data: driversData } = useQuery({
    queryKey: ["drivers", "list", "ACTIVE"],
    queryFn: async () => {
      const res = await driversService.getAll({ status: "ACTIVE" });
      return res.data;
    },
    enabled: needsDriverLookup,
  });

  const driversById = useMemo(
    () => new Map((driversData ?? []).map((driver) => [driver.id, driver])),
    [driversData],
  );

  const { data: pickupReadyRows = [] } = useQuery({
    queryKey: ["warehouse-inventory", "import-pickup-ready-queue"],
    queryFn: () => warehouseService.importPickupReadyQueue().then((r) => r.data),
  });

  const vehicleOptions = useMemo(
    () =>
      (Array.isArray(vehiclesData) ? vehiclesData : []).map((v) => {
        const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber];
        if (v.code) parts.unshift(v.code);
        const plates = [v.powerPlateNo, v.trailerPlateNo].filter(Boolean).join(" / ");
        if (plates) parts.push(plates);
        return { value: v.id, label: parts.join(" · ") };
      }),
    [vehiclesData],
  );

  const updateMutation = useMutation({
    mutationFn: ({ id, data }: { id: string; data: { status?: LastMileApiStatus; vehicleId?: string | null } }) =>
      lastMileService.update(id, data),
    onSuccess: () => {
      void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT });
      void qc.invalidateQueries({ queryKey: ["vehicles"] });
    },
    onError: () => {
      toast({ title: "Update failed", variant: "destructive" });
    },
  });

  const setVehiclesMutation = useMutation({
    mutationFn: ({
      id,
      vehicles,
    }: {
      id: string;
      vehicles: Array<{ vehicleId: string; containerNumber?: string | null }>;
    }) => lastMileService.setVehicles(id, vehicles),
    onSuccess: () => {
      void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT });
      void qc.invalidateQueries({ queryKey: ["vehicles"] });
    },
    onError: (e: unknown) => {
      // Surface the backend reason (e.g. "Truck … has no assigned driver …").
      const raw = (e as { response?: { data?: { message?: string | string[] } } })?.response?.data
        ?.message;
      const description = Array.isArray(raw) ? raw.join(", ") : raw;
      toast({ title: "Assign failed", description, variant: "destructive" });
    },
  });

  const distanceMutation = useMutation({
    mutationFn: ({
      id,
      distances,
      remainingPayment,
    }: {
      id: string;
      distances: Array<{ vehicleId: string; distanceKm: number }>;
      remainingPayment?: number;
    }) => lastMileService.setDistances(id, distances, remainingPayment),
    onSuccess: (res) => {
      void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT });
      toast({ title: "Distances saved", description: activeRecord ? bookingRef(activeRecord) : undefined });
      const updated = res?.data as LastMileRecord | undefined;
      closeDistance();
      // Every truck has a distance and it isn't billed yet → offer to invoice now.
      const trucks = updated?.vehicleAssignments ?? [];
      const allFilled = trucks.length > 0 && trucks.every((a) => Number(a.distanceKm) > 0);
      if (updated && allFilled && !updated.invoice) {
        setInvoiceConfirm(updated);
      }
    },
    onError: () => {
      toast({ title: "Update failed", variant: "destructive" });
    },
  });

  const generateInvoiceMutation = useMutation({
    mutationFn: (id: string) => lastMileService.generateInvoice(id),
    onSuccess: () => {
      void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT });
      toast({ title: "Invoice generated" });
    },
    onError: () => {
      toast({ title: "Invoice generation failed", variant: "destructive" });
    },
  });

  const deleteMutation = useMutation({
    mutationFn: (id: string) => lastMileService.remove(id),
    onSuccess: () => {
      void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.list() });
      toast({ title: "Record deleted", description: "Last-mile record removed successfully." });
    },
    onError: () => {
      toast({ title: "Delete failed", variant: "destructive" });
    },
  });


  const { data: arrivalQueueData, isLoading: arrivalLoading } = useQuery({
    queryKey: ["warehouse-inventory", "arrival-queue"],
    queryFn: () => warehouseService.arrivalQueue().then((r) => r.data),
    enabled: acceptOpen,
  });
  const arrivalQueue = arrivalQueueData ?? [];

  const filteredArrivalQueue = useMemo(() => {
    let filtered = arrivalQueue.filter((item) => !existingLastMileBookingIds.has(item.bookingId));
    const term = arrivalSearch.trim().toLowerCase();
    if (!term) return filtered;
    return filtered.filter((item) =>
      [item.bookingReference, item.customer, item.cargo, item.warehouse, item.yard]
        .join(" ")
        .toLowerCase()
        .includes(term),
    );
  }, [arrivalQueue, arrivalSearch, existingLastMileBookingIds]);

  const acceptMutation = useMutation({
    mutationFn: async ({ items, vehicleIds }: { items: ArrivalQueueItem[]; vehicleIds: string[] }) => {
      const created = await Promise.all(
        items.map((item) => lastMileService.accept(item.bookingReference).then((r) => r.data)),
      );
      if (vehicleIds.length) {
        const vehicles = vehicleIds.map((v) => ({ vehicleId: v }));
        await Promise.all(created.map((record) => lastMileService.setVehicles(record.id, vehicles)));
      }
      return created;
    },
    onSuccess: (created) => {
      void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT });
      void qc.invalidateQueries({ queryKey: ["vehicles"] });
      toast({
        title: "Last-mile leg created",
        description: `${created.length} ${created.length === 1 ? "delivery" : "deliveries"} accepted successfully.`,
      });
      closeAccept();
    },
    onError: () => {
      toast({ title: "Accept failed", variant: "destructive" });
    },
  });

  const openAccept = () => {
    setAcceptOpen(true);
    setAcceptStep(1);
    setSelectedArrivalItems([]);
    setAcceptVehicleValues([]);
    setArrivalSearch("");
  };

  const closeAccept = () => {
    setAcceptOpen(false);
    setAcceptStep(1);
    setSelectedArrivalItems([]);
    setAcceptVehicleValues([]);
    setArrivalSearch("");
  };

  const toggleArrivalItem = (item: ArrivalQueueItem) => {
    setSelectedArrivalItems((prev) =>
      prev.some((i) => i.bookingId === item.bookingId)
        ? prev.filter((i) => i.bookingId !== item.bookingId)
        : [...prev, item],
    );
  };

  const handleAcceptConfirm = () => {
    if (!selectedArrivalItems.length) return;
    acceptMutation.mutate({ items: selectedArrivalItems, vehicleIds: acceptVehicleValues });
  };

  const openDistance = (id: string) => {
    const rec = records.find((r) => r.id === id);
    const rows: Record<string, string> = {};
    for (const a of rec?.vehicleAssignments ?? []) {
      rows[a.vehicleId] = a.distanceKm != null ? String(a.distanceKm) : "";
    }
    setActiveId(id);
    setDistanceRows(rows);
    setDistanceOpen(true);
  };

  const closeDistance = () => {
    setDistanceOpen(false);
    setActiveId(null);
    setDistanceRows({});
  };



  const handleSaveDistance = () => {
    const distances = Object.entries(distanceRows)
      .map(([vehicleId, val]) => ({ vehicleId, distanceKm: parseFloat(val) }))
      .filter((d) => !Number.isNaN(d.distanceKm) && d.distanceKm >= 0);

    if (!activeId || !distances.length) {
      toast({ title: "Invalid distance", description: "Enter a distance for at least one vehicle.", variant: "destructive" });
      return;
    }

    // Amount is computed server-side per truck (distance × the vehicle's
    // price/km, in the vehicle's currency) — no flat LAST_MILE rate.
    distanceMutation.mutate({ id: activeId, distances });
  };

  const activeRecord = useMemo(
    () => records.find((r) => r.id === activeId) ?? null,
    [records, activeId],
  );

  // Vehicle picker options for the assign modal = free vehicles PLUS the ones
  // already on this record (which are BUSY, so absent from the free list) so a
  // reassign shows its current trucks selected instead of blank.
  const assignVehicleOptions = useMemo(() => {
    const opts = [...vehicleOptions];
    const seen = new Set(opts.map((o) => o.value));
    const pushVehicle = (v?: LastMileVehicle | null) => {
      if (v && !seen.has(v.id)) {
        seen.add(v.id);
        const parts = [`${v.manufacturer} ${v.model}`, v.plateNumber];
        if (v.code) parts.unshift(v.code);
        opts.push({ value: v.id, label: parts.join(" · ") });
      }
    };
    for (const a of activeRecord?.vehicleAssignments ?? []) pushVehicle(a.vehicle);
    pushVehicle(activeRecord?.vehicle);
    // Fallback: an assigned vehicle whose relation didn't load still needs an
    // option so the reassign Select can render it as selected (not blank).
    for (const a of activeRecord?.vehicleAssignments ?? []) {
      if (!seen.has(a.vehicleId)) {
        seen.add(a.vehicleId);
        opts.push({
          value: a.vehicleId,
          label: a.containerNumber ? `Assigned · ${a.containerNumber}` : "Assigned vehicle",
        });
      }
    }
    if (activeRecord?.vehicleId && !seen.has(activeRecord.vehicleId)) {
      opts.push({ value: activeRecord.vehicleId, label: "Assigned vehicle" });
    }
    return opts;
  }, [vehicleOptions, activeRecord]);

  // Pricing gap per vehicle id — an unpriced vehicle is blocked from assignment
  // below rather than silently billing 0 once distances are entered.
  const pricingGapById = useMemo(() => {
    const map = new Map<string, string | null>();
    const add = (v?: { id: string; pricePerKm?: number | string | null; currency?: string | null } | null) => {
      if (v?.id) map.set(v.id, pricingGap(v));
    };
    for (const v of Array.isArray(vehiclesData) ? vehiclesData : []) add(v);
    for (const a of activeRecord?.vehicleAssignments ?? []) add(a.vehicle);
    add(activeRecord?.vehicle);
    return map;
  }, [vehiclesData, activeRecord]);

  const vehicleLabelFor = (id: string) =>
    assignVehicleOptions.find((o) => o.value === id)?.label ?? id;

  // Full booking (with container units) for the assign modal's container dropdown.
  // Fetched on open so container numbers show regardless of what the list embeds.
  const { data: assignBooking } = useQuery({
    queryKey: activeRecord?.bookingId
      ? QUERY_KEYS.BOOKINGS.byId(activeRecord.bookingId)
      : ["bookings", "detail", "none"],
    queryFn: () => bookingsService.getById(activeRecord!.bookingId),
    enabled: assignOpen && !bulkMode && Boolean(activeRecord?.bookingId),
  });

  // Container-number options for the dropdown = the booking's real per-container
  // numbers (units), falling back to whatever the list record carried.
  const containerOptions = useMemo(() => {
    const real = (n?: string | null): n is string =>
      Boolean(n) && !/^TBD/i.test(n!.trim());
    const out: string[] = [];
    for (const c of assignBooking?.bookingContainers ?? []) {
      const units = [...(c.units ?? [])].sort(
        (a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0),
      );
      if (units.length) {
        for (const u of units) if (real(u.containerNumber)) out.push(u.containerNumber);
      } else if (real(c.containerNumber)) {
        out.push(c.containerNumber);
      }
    }
    return out.length ? out : activeRecord ? bookingContainerNumbers(activeRecord) : [];
  }, [assignBooking, activeRecord]);

  // Container number → size ("20ft"/"40ft"), driving the per-truck cap: a 40ft
  // fills the truck alone; two 20ft may share (no size mixing).
  const sizeByNumber = useMemo(() => {
    const map = new Map<string, string>();
    const lines = assignBooking?.bookingContainers?.length
      ? assignBooking.bookingContainers
      : activeRecord?.booking?.bookingContainers ?? [];
    for (const line of lines) {
      // The two payload shapes differ: the list record carries `containerSize`,
      // the booking detail exposes the size on its container type.
      const c = line as {
        containerSize?: string | null;
        containerNumber?: string | null;
        containerType?: { code?: string; label?: string; sizeFt?: number };
        units?: Array<{ containerNumber?: string | null }>;
      };
      const size = String(
        c.containerSize ?? c.containerType?.sizeFt ?? c.containerType?.code ?? c.containerType?.label ?? "",
      );
      for (const u of c.units ?? []) {
        if (u.containerNumber) map.set(u.containerNumber, size);
      }
      if (c.containerNumber) map.set(c.containerNumber, size);
    }
    return map;
  }, [assignBooking, activeRecord]);
  const is40 = (n: string) => (sizeByNumber.get(n) ?? "").includes("40");

  // Trucks that already arrived/left keep their load locked — the API rejects
  // changing or removing them; the modal greys those rows out.
  const lockedVehicles = useMemo(() => {
    const map = new Map<string, string>();
    for (const a of activeRecord?.vehicleAssignments ?? []) {
      if (a.departedAt) map.set(a.vehicleId, "left the warehouse");
      else if (a.arrivedAt) map.set(a.vehicleId, "arrived at the warehouse");
    }
    return map;
  }, [activeRecord]);

  const pickupReadyByBooking = useMemo(() => {
    const map = new Map<string, ImportUnloadedItem>();
    for (const row of pickupReadyRows) {
      if (row.bookingId) map.set(row.bookingId, row);
      if (row.bookingReference) map.set(row.bookingReference, row);
    }
    return map;
  }, [pickupReadyRows]);

  const selectedIds = useMemo(
    () => Object.keys(rowSelection).filter((id) => rowSelection[id]),
    [rowSelection],
  );

  const matchesFilter = (r: LastMileRecord) => {
    switch (statusFilter) {
      case "ALL": return true;
      case "ASSIGNED": return isAssigned(r);
      case "UNASSIGNED": return !isAssigned(r);
      default: return r.status === statusFilter;
    }
  };

  const statusCounts = useMemo(() => {
    const counts: Record<StatusFilter, number> = {
      ALL: records.length,
      PAYMENT_PENDING: 0,
      READY_TO_TRANSIT: 0,
      IN_TRANSIT: 0,
      DELIVERED: 0,
      ASSIGNED: 0,
      UNASSIGNED: 0,
    };
    for (const r of records) {
      counts[r.status] = (counts[r.status] ?? 0) + 1;
      if (isAssigned(r)) counts.ASSIGNED += 1;
      else counts.UNASSIGNED += 1;
    }
    return counts;
  }, [records]);

  const postPaymentPendingCount = useMemo(
    () => records.filter(isPostPaymentPending).length,
    [records],
  );

  // Billing problems on the leg pending invoice confirmation.
  const confirmIssues = invoiceConfirm
    ? billingIssues(invoiceConfirm)
    : { zeroPrice: [] as string[], mixedCurrency: false, currencies: [] as string[] };

  const filteredRecords = useMemo(() => {
    const term = search.trim().toLowerCase();
    return records.filter((r) => {
      if (!matchesFilter(r)) return false;
      if (filterPostPaymentPending && !isPostPaymentPending(r)) return false;
      if (!term) return true;
      return [bookingRef(r), customerName(r), deliveryLocation(r), cargoDesc(r)]
        .join(" ")
        .toLowerCase()
        .includes(term);
    });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [records, search, statusFilter, filterPostPaymentPending]);

  const pageCount = Math.max(1, Math.ceil(filteredRecords.length / pagination.pageSize));
  const pagedRecords = useMemo(() => {
    const start = pagination.pageIndex * pagination.pageSize;
    return filteredRecords.slice(start, start + pagination.pageSize);
  }, [filteredRecords, pagination]);

  // Per-truck exit papers for an EDR delivery (one paper per assigned truck).
  const [exitPapersOpen, setExitPapersOpen] = useState(false);
  const [exitPapersRecord, setExitPapersRecord] = useState<LastMileRecord | null>(null);

  // Bulk drawdown: how much tonnage is still to be hauled on the booking being
  // assigned. Bulk has no containers, so trucks keep going until this hits 0.
  const assignBookingId = activeRecord?.booking?.id ?? null;
  const { data: remainingTons } = useQuery({
    queryKey: ["last-mile", "remaining-tons", assignBookingId],
    queryFn: () => lastMileService.remainingTons(assignBookingId as string).then((r) => r.data),
    enabled: assignOpen && !bulkMode && Boolean(assignBookingId),
  });

  const openAssign = (id: string | null) => {
    const resolved = id ?? filteredRecords.find((r) => !isAssigned(r))?.id ?? null;
    const rec = records.find((r) => r.id === resolved);
    // Prefill each row's container number from the booking's container numbers
    // (by order) when the assignment doesn't already carry one.
    const nums = rec ? bookingContainerNumbers(rec) : [];
    // Prefer the truck's own container list; fall back to the legacy scalar, then
    // to the booking's containers by order.
    const loadOf = (
      a: { containers?: Array<{ containerNumber: string }>; containerNumber?: string | null },
      i: number,
    ) =>
      a.containers?.length
        ? a.containers.map((c) => c.containerNumber)
        : a.containerNumber
          ? [a.containerNumber]
          : nums[i]
            ? [nums[i]]
            : [];
    const rows =
      rec?.vehicleAssignments?.length
        ? rec.vehicleAssignments.map((a, i) => ({
            vehicleId: a.vehicleId,
            containerNumbers: loadOf(a, i),
          }))
        : rec?.vehicleId
          ? [{ vehicleId: rec.vehicleId, containerNumbers: nums[0] ? [nums[0]] : [] }]
          : [{ vehicleId: null, containerNumbers: nums[0] ? [nums[0]] : [] }];
    setBulkMode(false);
    setActiveId(resolved);
    setVehicleRows(
      rows.length ? rows : [{ vehicleId: null, containerNumbers: nums[0] ? [nums[0]] : [] }],
    );
    setAssignOpen(true);
  };

  const openBulkAssign = () => {
    // A single selection has full booking context (details, container list) —
    // use the richer single-record flow instead of the blank bulk form.
    if (selectedIds.length === 1) {
      openAssign(selectedIds[0]);
      return;
    }
    setBulkMode(true);
    setActiveId(null);
    setVehicleRows([{ vehicleId: null, containerNumbers: [] }]);
    setAssignOpen(true);
  };

  const closeAssign = () => {
    setAssignOpen(false);
    setBulkMode(false);
    setActiveId(null);
    setVehicleRows([{ vehicleId: null, containerNumbers: [] }]);
  };

  const handleAssign = () => {
    const seen = new Set<string>();
    const vehicles = vehicleRows
      .filter((r): r is { vehicleId: string; containerNumbers: string[] } => Boolean(r.vehicleId))
      .filter((r) => (seen.has(r.vehicleId) ? false : seen.add(r.vehicleId)))
      .map((r) => ({
        vehicleId: r.vehicleId,
        containerNumbers: r.containerNumbers.map((n) => n.trim()).filter(Boolean),
      }));
    const count = vehicles.length;
    const targetIds = bulkMode
      ? selectedIds
      : [activeId ?? filteredRecords.find((r) => !isAssigned(r))?.id].filter((id): id is string => Boolean(id));

    if (!targetIds.length) return;

    // A 40ft container fills its truck — backstop for pre-filled reassignment
    // rows the MultiSelect guard never saw.
    const overloaded = vehicles.filter(
      (v) => v.containerNumbers.length > 1 && v.containerNumbers.some(is40),
    );
    if (overloaded.length) {
      toast({
        title: "40ft fills the truck",
        description: `${overloaded
          .map((v) => vehicleLabelFor(v.vehicleId))
          .join("; ")} — a 40ft container travels alone.`,
        variant: "destructive",
      });
      return;
    }

    // Backstop for rows the Select guard never saw (pre-filled reassignments).
    const unpriced = vehicles
      .map((v) => ({ label: vehicleLabelFor(v.vehicleId), gap: pricingGapById.get(v.vehicleId) }))
      .filter((v): v is { label: string; gap: string } => Boolean(v.gap));
    if (unpriced.length) {
      toast({
        title: "Vehicle is not priced",
        description: `${unpriced
          .map((v) => `${v.label} (${v.gap} not set)`)
          .join("; ")} — set it on the vehicle before assigning.`,
        variant: "destructive",
      });
      return;
    }

    // Empty set = unassign all (setVehicles releases the removed vehicles).
    Promise.all(targetIds.map((id) => setVehiclesMutation.mutateAsync({ id, vehicles })))
      .then(() => {
        toast({
          title: count === 0 ? "Vehicles unassigned" : count > 1 ? "Vehicles assigned" : "Vehicle assigned",
          description:
            count === 0
              ? bulkMode ? `${targetIds.length} deliveries` : undefined
              : `${bulkMode ? `${targetIds.length} deliveries · ` : ""}${count} vehicle${count > 1 ? "s" : ""}`,
        });
        if (bulkMode) setRowSelection({});
        closeAssign();
      })
      .catch(() => void 0);
  };

  const handleAdvanceStatus = (record: LastMileRecord) => {
    const next = NEXT_STATUS[record.status];
    if (!next) return;
    // Completing a delivery requires proof of delivery — open the capture modal
    // instead of advancing straight to DELIVERED.
    if (next === "DELIVERED") {
      setPodRecord(record);
      return;
    }
    updateMutation.mutate(
      { id: record.id, data: { status: next } },
      {
        onSuccess: () =>
          toast({ title: "Status updated", description: `${bookingRef(record)} → ${STATUS_META[next].label}` }),
      },
    );
  };

  const handlePrintTripSlip = (record: LastMileRecord) => {
    // Always open the picker so the operator chooses which truck to print.
    setTripSlipRecord(record);
    setTripSlipVehicleId(null);
    setTripSlipSelectOpen(true);
  };

  const printBookingSlip = () => {
    setTripSlipVehicleId(null);
    setTripSlipSelectOpen(false);
    setTripSlipOpen(true);
  };

  const chooseTripSlipVehicle = (vehicleId: string) => {
    setTripSlipVehicleId(vehicleId);
    setTripSlipSelectOpen(false);
    setTripSlipOpen(true);
  };

  const openTruckArrival = (record: LastMileRecord) => {
    if (!isAssigned(record)) {
      toast({
        title: "Assign a truck first",
        description: "Truck arrival opens after a last-mile vehicle is assigned.",
        variant: "destructive",
      });
      return;
    }

    const row = pickupReadyByBooking.get(record.bookingId) ?? pickupReadyByBooking.get(bookingRef(record));
    if (!row) {
      toast({
        title: "Import inventory is not pickup-ready",
        description: `${bookingRef(record)} must be unloaded and pass inspection before truck arrival.`,
        variant: "destructive",
      });
      return;
    }

    setReleaseTruckPrefill(releasePrefillFromLastMile(record, row, driversById));
    setReleaseItem(toReleaseInventoryItem(row));
  };

  // Truck leaving the warehouse = the leg is now in transit. Advance the status
  // (same as "Mark In Transit") alongside the warehouse exit-weighing flow.
  const handleTruckLeaving = (record: LastMileRecord) => {
    openTruckArrival(record);
    if (record.status === "READY_TO_TRANSIT") {
      updateMutation.mutate({ id: record.id, data: { status: "IN_TRANSIT" } });
    }
  };

  const closeTruckArrival = () => {
    setReleaseItem(null);
    setReleaseTruckPrefill(null);
    void qc.invalidateQueries({ queryKey: ["warehouse-inventory"] });
    void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT });
  };

  const tripSlipVehicle =
    tripSlipRecord?.vehicleAssignments?.find((a) => a.vehicleId === tripSlipVehicleId) ?? null;

  const printTripSlip = () => {
    if (!tripSlipRecord) return;
    const win = window.open("", "_blank", "width=820,height=920");
    if (!win) {
      toast({ title: "Pop-up blocked", description: "Allow pop-ups to print the trip slip.", variant: "destructive" });
      return;
    }
    win.document.write(buildTripSlipHtml(tripSlipRecord, tripSlipVehicle));
    win.document.close();
    win.focus();
    // Explicit print after the doc paints (onload can miss with document.write).
    setTimeout(() => {
      try {
        win.print();
      } catch {
        /* window may have been closed */
      }
    }, 250);
  };

  const columns = useMemo((): ColumnDef<LastMileRecord>[] => {
    const headerClassName = ruleEngineTable.headerCell;
    const cellClassName = ruleEngineTable.bodyCell;
    return [
      {
        id: "select",
        size: 40,
        meta: { headerClassName, cellClassName },
        header: ({ table }) => (
          <Checkbox
            aria-label="Select all"
            checked={table.getIsAllPageRowsSelected()}
            indeterminate={table.getIsSomePageRowsSelected() && !table.getIsAllPageRowsSelected()}
            onChange={(e) => table.toggleAllPageRowsSelected(e.currentTarget.checked)}
          />
        ),
        cell: ({ row }) => (
          <Checkbox
            aria-label="Select row"
            checked={row.getIsSelected()}
            disabled={!row.getCanSelect()}
            onChange={row.getToggleSelectedHandler()}
          />
        ),
      },
      {
        id: "bookingRef",
        header: "Booking",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => <Text size="sm" fw={600}>{bookingRef(row.original)}</Text>,
      },
      {
        id: "customer",
        header: "Customer",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => customerName(row.original),
      },
      {
        id: "postPayment",
        header: "Post Payment",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => formatPrice(row.original.remainingPayment, currencyOf(row.original)),
      },
      {
        id: "vehicle",
        header: "Vehicle",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => {
          const assigns = row.original.vehicleAssignments ?? [];
          if (assigns.length > 1) {
            const labelFor = (a: (typeof assigns)[number]) => {
              const v = a.vehicle;
              const l = v ? [v.code, v.plateNumber].filter(Boolean).join(" · ") : a.vehicleId;
              return a.containerNumber ? `${l} · ${a.containerNumber}` : l;
            };
            return (
              <Tooltip
                withArrow
                multiline
                label={
                  <div style={{ whiteSpace: "pre-line" }}>
                    {assigns.map(labelFor).join("\n")}
                  </div>
                }
              >
                <Group gap={4} wrap="nowrap" style={{ whiteSpace: "nowrap" }}>
                  <Text size="sm" style={{ whiteSpace: "nowrap" }}>
                    {assigns[0].vehicle
                      ? [assigns[0].vehicle.code, assigns[0].vehicle.plateNumber].filter(Boolean).join(" · ")
                      : assigns[0].vehicleId}
                  </Text>
                  <Badge size="sm" variant="light" color="blue">
                    +{assigns.length - 1}
                  </Badge>
                </Group>
              </Tooltip>
            );
          }
          return vehicleLabel(row.original) ?? <Text c="dimmed">Unassigned</Text>;
        },
      },
      {
        id: "exactKm",
        header: "Actual Distance (KM)",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => row.original.exactKm != null ? row.original.exactKm : <Text c="dimmed">—</Text>,
      },
      {
        id: "invoice",
        header: "Invoice",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => {
          // Only show an invoice once it's actually been generated — NOT merely
          // because distance was entered.
          const invoice = row.original.invoice;
          if (!invoice) {
            return <Text c="dimmed">—</Text>;
          }
          const status = String((row.original as any).paid ? "PAID" : invoice.status || "").toUpperCase();
          const badge = INVOICE_STATUS_META[status] ?? { color: "gray", label: status || "—" };
          return (
            <Group gap="xs" wrap="nowrap">
              <UnstyledButton
                onClick={() =>
                  invoice.id
                    ? navigate(`/dashboard/invoices/${invoice.id}`)
                    : toast({ title: "Invoice link unavailable", description: "Refresh after the API restart.", variant: "destructive" })
                }
                c="blue"
                fw={500}
                style={{ textDecoration: "underline", cursor: "pointer" }}
              >
                <Tooltip label={invoice.number} withArrow>
                  <span>{shortInvoiceNo(invoice.number)}</span>
                </Tooltip>
              </UnstyledButton>
              {status && <Badge color={badge.color} variant="filled" size="sm">{badge.label}</Badge>}
            </Group>
          );
        },
      },
      {
        id: "status",
        header: "Status",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => {
          const meta = STATUS_META[row.original.status];
          return <Badge color={meta.color} variant="light" size="sm">{meta.label}</Badge>;
        },
      },
      {
        id: "actions",
        header: "Actions",
        meta: { headerClassName, cellClassName: `${cellClassName} whitespace-nowrap` },
        cell: ({ row }) => {
          const assigned = isAssigned(row.original);
          const nextStatus = NEXT_STATUS[row.original.status];
          const canPrint = row.original.status !== "PAYMENT_PENDING";
          const isPaid = (row.original as any).paid;
          const delivered = row.original.status === "DELIVERED";
          const releaseRow =
            pickupReadyByBooking.get(row.original.bookingId) ?? pickupReadyByBooking.get(bookingRef(row.original));
          // Gate on PERSISTENT state (status/vehicle/distance), not the truck
          // arrival/leave signals — those live in the warehouse queue and vanish
          // once the item is released, so they can't gate the status advance.
          const status = row.original.status;
          const hasDistance = row.original.exactKm != null;
          // Advance: PAYMENT_PENDING→Ready, READY_TO_TRANSIT→In-transit (needs a
          // vehicle), IN_TRANSIT→Delivered (needs distance/invoice).
          const canAdvance =
            status === "PAYMENT_PENDING" ||
            (status === "READY_TO_TRANSIT" && assigned) ||
            (status === "IN_TRANSIT" && hasDistance);
          // Assign stays active until the whole load has trucks: container
          // bookings until every container is on a truck; bulk until the
          // tonnage is drawn down (trucks depart one by one). Already-departed
          // trucks keep their rows locked in the modal.
          const totalContainers = containerCount(row.original);
          const assignedContainers = (row.original.vehicleAssignments ?? []).reduce(
            (s, a) => s + (a.containers?.length ?? (a.containerNumber ? 1 : 0)),
            0,
          );
          const containersRemain = totalContainers > 0 && assignedContainers < totalContainers;
          const bulkCargo = totalContainers === 0;
          const canAssignStep =
            status !== "DELIVERED" &&
            !row.original.invoice &&
            (!assigned || containersRemain || (bulkCargo && status !== "IN_TRANSIT"));
          const canDistance = status === "IN_TRANSIT";
          // Truck arrival/leaving are independent — each driven by its own
          // warehouse state — but both are done once the leg is IN_TRANSIT/DELIVERED.
          const pastTransit = status === "IN_TRANSIT" || status === "DELIVERED";
          const canArrive = assigned && !releaseRow?.releaseOrderReference && !pastTransit;
          const canLeave =
            Boolean(releaseRow?.releaseOrderReference) && !releaseRow?.releaseDate && !pastTransit;
          return (
            <Group gap={4} justify="flex-end" wrap="nowrap">
              {pastTransit && (
                <Button
                  size="compact-xs"
                  variant="light"
                  color="orange"
                  leftSection={<Receipt size={13} />}
                  onClick={() => setDetentionRecord(row.original)}
                >
                  Detention
                </Button>
              )}
              <Menu
                position="bottom-end"
                width={200}
                withinPortal
                styles={{ dropdown: { maxHeight: 320, overflowY: "auto" } }}
              >
                <Menu.Target>
                  <ActionIcon variant="subtle" color="gray" aria-label="Delivery actions">
                    <MoreHorizontal size={16} />
                  </ActionIcon>
                </Menu.Target>
                <Menu.Dropdown>
                  <Menu.Item
                    leftSection={<ArrowRight size={15} />}
                    disabled={!nextStatus || !canAdvance}
                    onClick={() => handleAdvanceStatus(row.original)}
                  >
                    {nextStatus
                      ? `Mark ${STATUS_META[nextStatus].label}`
                      : STATUS_META[row.original.status].label}
                  </Menu.Item>
                  <Menu.Divider />
                  <Menu.Item
                    leftSection={<Truck size={15} />}
                    disabled={!canAssignStep}
                    onClick={() => openAssign(row.original.id)}
                  >
                    Assign
                  </Menu.Item>
                  <Menu.Item
                    leftSection={<RefreshCw size={15} />}
                    disabled={!assigned || delivered || Boolean(row.original.invoice)}
                    onClick={() => openAssign(row.original.id)}
                  >
                    Reassign
                  </Menu.Item>
                  <Menu.Item
                    color="red"
                    leftSection={<X size={15} />}
                    disabled={!assigned || delivered || Boolean(row.original.invoice)}
                    onClick={() =>
                      setVehiclesMutation.mutate(
                        { id: row.original.id, vehicles: [] },
                        {
                          onSuccess: () =>
                            toast({ title: "Vehicles unassigned", description: bookingRef(row.original) }),
                        },
                      )
                    }
                  >
                    Unassign
                  </Menu.Item>
                  <Menu.Item
                    leftSection={<Truck size={15} />}
                    disabled={!canArrive}
                    onClick={() => openTruckArrival(row.original)}
                  >
                    Truck Arrival
                  </Menu.Item>
                  <Menu.Item
                    leftSection={<Truck size={15} />}
                    disabled={!canLeave}
                    onClick={() => handleTruckLeaving(row.original)}
                  >
                    Truck Leaving
                  </Menu.Item>
                  <Menu.Item
                    leftSection={<FileText size={15} />}
                    disabled={!row.original.vehicleAssignments?.length}
                    onClick={() => {
                      setExitPapersRecord(row.original);
                      setExitPapersOpen(true);
                    }}
                  >
                    Truck exit papers
                  </Menu.Item>
                  <Menu.Divider />
                  <Menu.Item
                    leftSection={<Eye size={15} />}
                    onClick={() => { setActiveId(row.original.id); setDetailOpen(true); }}
                  >
                    View detail
                  </Menu.Item>
                  <Menu.Item
                    leftSection={<Ruler size={15} />}
                    disabled={!canDistance || Boolean(row.original.invoice)}
                    onClick={() => openDistance(row.original.id)}
                  >
                    Add distance
                  </Menu.Item>
                  <Menu.Item
                    leftSection={<Receipt size={15} />}
                    disabled={
                      !(row.original.exactKm != null && row.original.exactKm > 0) ||
                      Boolean(row.original.invoice)
                    }
                    onClick={() => setInvoiceConfirm(row.original)}
                  >
                    {row.original.invoice ? "Invoice generated" : "Generate Invoice"}
                  </Menu.Item>
                  {/* Truck detention: set/adjust arrival & return times, preview the
                      per-truck-per-day charge, and generate its invoice. Available
                      once the vehicle is en route/delivered (clock has a start). */}
                  <Menu.Item
                    leftSection={<Receipt size={15} />}
                    disabled={!pastTransit}
                    onClick={() => setDetentionRecord(row.original)}
                  >
                    Truck detention
                  </Menu.Item>
                  {canPrint && (
                    <Menu.Item
                      leftSection={<Printer size={15} />}
                      onClick={() => handlePrintTripSlip(row.original)}
                    >
                      Print trip slip
                    </Menu.Item>
                  )}
                  {!isPaid && (
                    <>
                      <Menu.Divider />
                      <Menu.Item
                        leftSection={<Trash size={15} />}
                        color="red"
                        disabled={delivered || Boolean(row.original.invoice)}
                        onClick={() => {
                          if (confirm(`Delete last-mile record ${bookingRef(row.original)}?`)) {
                            deleteMutation.mutate(row.original.id);
                          }
                        }}
                      >
                        Delete
                      </Menu.Item>
                    </>
                  )}
                </Menu.Dropdown>
              </Menu>
            </Group>
          );
        },
      },
    ];
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [vehicleOptions, pickupReadyByBooking]);

  return (
    <Stack gap="md" p="md">
      <Card radius="lg" padding={0} withBorder style={{ borderColor: "var(--mantine-color-gray-2)" }}>
        <Stack gap={0}>
          <Box px="md" pt="md" pb="sm" w="100%">
            <Stack gap="sm">
              <Group justify="space-between" wrap="wrap">
                <TextInput
                  placeholder="Search deliveries…"
                  value={search}
                  onChange={(e) => setSearch(e.currentTarget.value)}
                  w={260}
                />
                <Group gap="sm">
                  {selectedIds.length > 0 && (
                    <Button variant="light" leftSection={<Truck size={16} />} onClick={openBulkAssign} styles={{ label: { fontWeight: 500 } }}>
                      Assign vehicle ({selectedIds.length})
                    </Button>
                  )}
                  <Button leftSection={<Truck size={16} />} onClick={openAccept} styles={{ label: { fontWeight: 500 } }}>
                    Assign Mile
                  </Button>
                </Group>
              </Group>
              <Group gap="xs" wrap="wrap">
                {FILTER_OPTIONS.map((option) => {
                  const active = statusFilter === option.value;
                  return (
                    <Button
                      key={option.value}
                      size="xs"
                      variant={active ? "filled" : "default"}
                      styles={{ label: { fontWeight: 500 } }}
                      onClick={() => {
                        setStatusFilter(option.value);
                        setPagination((p) => ({ ...p, pageIndex: 0 }));
                      }}
                    >
                      {option.label} ({statusCounts[option.value] ?? 0})
                    </Button>
                  );
                })}
                <Button
                  size="xs"
                  variant={filterPostPaymentPending ? "filled" : "default"}
                  styles={{ label: { fontWeight: 500 } }}
                  onClick={() => {
                    setFilterPostPaymentPending(!filterPostPaymentPending);
                    setPagination((p) => ({ ...p, pageIndex: 0 }));
                  }}
                >
                  Post Payment Pending ({postPaymentPendingCount})
                </Button>
              </Group>
            </Stack>
          </Box>

          <DataTable
            columns={columns}
            data={pagedRecords}
            status={isLoading ? "loading" : "success"}
            emptyMessage="No last-mile deliveries found"
            pagination={{
              pageIndex: pagination.pageIndex,
              pageSize: pagination.pageSize,
              pageCount,
              totalCount: filteredRecords.length,
            }}
            tableOptions={{
              manualPagination: true,
              pageCount,
              enableRowSelection: true,
              getRowId: (row) => row.id,
              state: { pagination, rowSelection },
              onPaginationChange: setPagination,
              onRowSelectionChange: setRowSelection,
            }}
            containerClassName="border-0 shadow-none bg-transparent"
            footer={({ table, pagination: fp }) => (
              <DataTableFooter table={table} pagination={fp} options={{ labels: { items: "deliveries" } }} />
            )}
          />
        </Stack>
      </Card>

      {/* 2-step Assign Mile (arrival queue → vehicle) */}
      <Modal
        opened={acceptOpen}
        onClose={closeAccept}
        title={
          <Text fw={600}>
            {acceptStep === 1 ? "Select Arrivals" : "Assign Mile"}
          </Text>
        }
        size="xl"
        radius="lg"
        centered
      >
        {acceptStep === 1 ? (
          <Stack gap="md">
            <TextInput
              placeholder="Search by reference, customer, cargo or warehouse…"
              value={arrivalSearch}
              onChange={(e) => setArrivalSearch(e.currentTarget.value)}
            />
            <ScrollArea h={400}>
              <Stack gap="xs">
                {arrivalLoading ? (
                  <Text c="dimmed" size="sm" ta="center" py="md">Loading arrivals…</Text>
                ) : filteredArrivalQueue.length === 0 ? (
                  <Text c="dimmed" size="sm" ta="center" py="md">No arrivals in queue.</Text>
                ) : (
                  filteredArrivalQueue.map((item) => {
                    const checked = selectedArrivalItems.some((i) => i.bookingId === item.bookingId);
                    return (
                      <Card
                        key={item.bookingId}
                        withBorder
                        padding="sm"
                        radius="md"
                        style={{
                          cursor: "pointer",
                          borderColor: checked ? "var(--mantine-color-blue-4)" : "var(--mantine-color-gray-3)",
                          backgroundColor: checked ? "var(--mantine-color-blue-0)" : "var(--mantine-color-white)",
                          transition: "background-color 120ms ease, border-color 120ms ease",
                        }}
                        onClick={() => toggleArrivalItem(item)}
                      >
                        <Group wrap="nowrap" gap="sm">
                          <Checkbox
                            checked={checked}
                            onChange={() => toggleArrivalItem(item)}
                            onClick={(e) => e.stopPropagation()}
                          />
                          <Stack gap={2} style={{ flex: 1, minWidth: 0 }}>
                            <Group justify="space-between" wrap="nowrap">
                              <Text fw={700} size="sm">{item.bookingReference}</Text>
                              <Text size="xs" c="dimmed">{item.arrivalDate ? item.arrivalDate.slice(0, 10) : "—"}</Text>
                            </Group>
                            <Text size="xs" c="dimmed" truncate>{item.customer ?? "—"}</Text>
                            <Group gap="xs" wrap="wrap">
                              {item.cargo && <Text size="xs" c="dimmed">{item.cargo}</Text>}
                              {item.warehouse && <Text size="xs" c="dimmed">· {item.warehouse}</Text>}
                              {item.yard && <Text size="xs" c="dimmed">· {item.yard}</Text>}
                            </Group>
                          </Stack>
                        </Group>
                      </Card>
                    );
                  })
                )}
              </Stack>
            </ScrollArea>
            <Group justify="space-between">
              <Text size="sm" c="dimmed">
                {selectedArrivalItems.length > 0
                  ? `${selectedArrivalItems.length} selected`
                  : "Select one or more arrivals"}
              </Text>
              <Group gap="sm">
                <Button variant="default" onClick={closeAccept}>Cancel</Button>
                <Button
                  disabled={selectedArrivalItems.length === 0}
                  onClick={() => setAcceptStep(2)}
                >
                  Next →
                </Button>
              </Group>
            </Group>
          </Stack>
        ) : (
          <Stack gap="md">
            <Card withBorder padding="sm" radius="md" bg="var(--mantine-color-gray-0)">
              <Stack gap="xs">
                <Text size="sm" fw={600} c="dimmed">Selected arrivals ({selectedArrivalItems.length})</Text>
                {selectedArrivalItems.map((item) => (
                  <Group key={item.bookingId} justify="space-between" wrap="nowrap">
                    <Text size="sm" fw={600}>{item.bookingReference}</Text>
                    <Text size="xs" c="dimmed">{item.customer ?? "—"}</Text>
                    <Text size="xs" c="dimmed">{item.warehouse ?? item.yard ?? "—"}</Text>
                  </Group>
                ))}
              </Stack>
            </Card>
            <Divider />
            <MultiSelect
              label="Assign Vehicles (optional)"
              placeholder={
                vehicleOptions.length === 0
                  ? "No free vehicles"
                  : acceptVehicleValues.length === 0
                    ? "Add vehicles"
                    : undefined
              }
              description={
                vehicleOptions.length === 0
                  ? "No free vehicles available — you can still accept and assign vehicles later."
                  : "Pick one or more trucks for this delivery."
              }
              data={vehicleOptions}
              value={acceptVehicleValues}
              onChange={setAcceptVehicleValues}
              searchable
              clearable
              hidePickedOptions
              disabled={vehicleOptions.length === 0}
            />
            <Group justify="space-between" gap="sm">
              <Button variant="subtle" onClick={() => setAcceptStep(1)}>← Back</Button>
              <Group gap="sm">
                <Button variant="default" onClick={closeAccept}>Cancel</Button>
                <Button
                  onClick={handleAcceptConfirm}
                  loading={acceptMutation.isPending}
                  disabled={selectedArrivalItems.length === 0}
                >
                  Accept {selectedArrivalItems.length > 1 ? `${selectedArrivalItems.length} Deliveries` : "Delivery"}
                </Button>
              </Group>
            </Group>
          </Stack>
        )}
      </Modal>

      {/* Assign / Reassign modal */}
      <Modal
        opened={assignOpen}
        onClose={closeAssign}
        title={<Text fw={600}>Assign Vehicle</Text>}
        size="lg"
        radius="lg"
        centered
      >
        <Stack gap="md">
          {bulkMode ? (
            <Text size="sm">
              Assigning a vehicle to{" "}
              <Text span fw={600}>{selectedIds.length}</Text>{" "}
              selected {selectedIds.length === 1 ? "delivery" : "deliveries"}.
            </Text>
          ) : activeRecord ? (
            <BookingInfo record={activeRecord} />
          ) : (
            <Text size="sm" c="dimmed">No unassigned deliveries available.</Text>
          )}
          {!bulkMode && activeRecord && (() => {
            const containers = containerCount(activeRecord);
            const needed = requiredVehicles(activeRecord);
            const picked = vehicleRows.filter((r) => r.vehicleId).length;
            if (needed === 0) {
              // Bulk: no containers — trucks haul loose tonnage until the
              // booking's total is drawn down to zero by departing trucks.
              const done = remainingTons?.complete;
              return (
                <Alert
                  variant="light"
                  color={done ? "green" : remainingTons ? "blue" : "gray"}
                  title={
                    remainingTons
                      ? `${remainingTons.remainingTons} t remaining of ${remainingTons.totalTons} t`
                      : "No container count on this booking"
                  }
                >
                  {remainingTons
                    ? done
                      ? "Fully hauled — no tonnage left to assign trucks for."
                      : `Bulk booking: ${remainingTons.hauledTons} t hauled so far. Keep assigning trucks until the remaining tonnage reaches 0 — each truck's net weight is deducted when it leaves.`
                    : "Assign trucks as needed."}
                </Alert>
              );
            }
            const coveredContainers = vehicleRows.reduce(
              (s, r) => s + (r.vehicleId ? r.containerNumbers.length : 0),
              0,
            );
            const ok = picked === needed && coveredContainers === containers;
            return (
              <Alert
                variant="light"
                color={ok ? "green" : "yellow"}
                title={`${coveredContainers} of ${containers} container${containers === 1 ? "" : "s"} on trucks · needs ${needed} vehicle${needed === 1 ? "" : "s"}`}
              >
                One 40ft container fills a truck; two 20ft share one (no size mixing).
                {containers - coveredContainers > 0 &&
                  ` ${containers - coveredContainers} container${containers - coveredContainers === 1 ? "" : "s"} still unassigned — keep adding trucks.`}
                {picked > 0 && picked !== needed &&
                  ` You've selected ${picked} vehicle${picked === 1 ? "" : "s"} — ${picked < needed ? "add more" : "that's more than needed"}.`}
              </Alert>
            );
          })()}
          {!bulkMode && activeRecord && containerLabels(activeRecord).length > 0 && (
            <Card withBorder padding="xs" radius="md" bg="var(--mantine-color-gray-0)">
              <Text size="xs" fw={600} c="dimmed" mb={4}>
                Containers ({containerLabels(activeRecord).length})
              </Text>
              <Group gap={6}>
                {containerLabels(activeRecord).map((label, i) => (
                  <Badge key={i} size="sm" variant="outline" color="gray">
                    {label}
                  </Badge>
                ))}
              </Group>
            </Card>
          )}
          <Divider />
          <Stack gap="xs">
            {vehicleRows.map((row, i) => {
              const lockReason = row.vehicleId ? lockedVehicles.get(row.vehicleId) : undefined;
              const rowLocked = Boolean(lockReason);
              const rowHas40 = row.containerNumbers.some(is40);
              return (
              <Group key={i} gap="xs" wrap="nowrap" align="flex-end">
                <Select
                  style={{ flex: 1.4 }}
                  label={i === 0 ? "Vehicle" : undefined}
                  placeholder={assignVehicleOptions.length === 0 ? "No free vehicles" : "Select a vehicle"}
                  data={assignVehicleOptions.filter(
                    (o) => o.value === row.vehicleId || !vehicleRows.some((r) => r.vehicleId === o.value),
                  )}
                  value={row.vehicleId}
                  onChange={(v) => {
                    const gap = v ? pricingGapById.get(v) : null;
                    if (v && gap) {
                      toast({
                        title: "Vehicle is not priced",
                        description: `${vehicleLabelFor(v)} — ${gap} not set. Set it on the vehicle before assigning.`,
                        variant: "destructive",
                      });
                      return;
                    }
                    setVehicleRows((prev) => prev.map((x, idx) => (idx === i ? { ...x, vehicleId: v } : x)));
                  }}
                  searchable
                  clearable
                  disabled={assignVehicleOptions.length === 0 || rowLocked}
                />
                <MultiSelect
                  style={{ flex: 1 }}
                  label={i === 0 ? "Containers (1x40ft or 2x20ft)" : undefined}
                  placeholder={containerOptions.length ? "Select containers" : "No container numbers"}
                  description={rowLocked ? `Locked — truck ${lockReason}` : undefined}
                  // A 40ft container fills the truck alone; two 20ft may share.
                  maxValues={rowHas40 ? 1 : 2}
                  data={[
                    ...containerOptions.filter(
                      (n) =>
                        row.containerNumbers.includes(n) ||
                        // a container rides exactly one truck …
                        (!vehicleRows.some((r, idx) => idx !== i && r.containerNumbers.includes(n)) &&
                          // … and no size mixing: once a 20ft is picked a 40ft
                          // can't join it, and a 40ft truck is already full.
                          !(rowHas40 || (row.containerNumbers.length > 0 && is40(n)))),
                    ),
                    // keep manual/legacy values selectable even if not in the booking
                    ...row.containerNumbers.filter((n) => !containerOptions.includes(n)),
                  ]}
                  value={row.containerNumbers}
                  onChange={(value) => {
                    // Guard the paste/keyboard path too — data filtering only
                    // covers the dropdown.
                    if (value.filter(is40).length > 0 && value.length > 1) {
                      toast({
                        title: "40ft fills the truck",
                        description: "A 40ft container travels alone — remove the other container.",
                        variant: "destructive",
                      });
                      return;
                    }
                    setVehicleRows((prev) =>
                      prev.map((x, idx) => (idx === i ? { ...x, containerNumbers: value } : x)),
                    );
                  }}
                  searchable
                  clearable
                  disabled={rowLocked}
                />
                {vehicleRows.length > 1 && !rowLocked && (
                  <ActionIcon
                    variant="subtle"
                    color="red"
                    aria-label="Remove vehicle"
                    onClick={() => setVehicleRows((prev) => prev.filter((_, idx) => idx !== i))}
                  >
                    <X size={16} />
                  </ActionIcon>
                )}
              </Group>
              );
            })}
            <Button
              variant="light"
              size="xs"
              leftSection={<Plus size={14} />}
              onClick={() =>
                setVehicleRows((prev) => {
                  // Suggest the next unassigned container for the new truck.
                  const taken = new Set(prev.flatMap((r) => r.containerNumbers));
                  const next = (activeRecord ? bookingContainerNumbers(activeRecord) : []).find(
                    (n) => !taken.has(n),
                  );
                  return [...prev, { vehicleId: null, containerNumbers: next ? [next] : [] }];
                })
              }
              disabled={
                assignVehicleOptions.length === 0 ||
                vehicleRows.some((r) => !r.vehicleId) ||
                vehicleRows.filter((r) => r.vehicleId).length >= assignVehicleOptions.length
              }
              style={{ alignSelf: "flex-start" }}
            >
              Add vehicle
            </Button>
          </Stack>
          <Group justify="flex-end" gap="sm">
            <Button variant="default" onClick={closeAssign}>Cancel</Button>
            <Button
              onClick={handleAssign}
              loading={setVehiclesMutation.isPending}
              disabled={bulkMode ? selectedIds.length === 0 : !activeRecord}
            >
              {!bulkMode && activeRecord && isAssigned(activeRecord) ? "Update vehicles" : "Assign"}
            </Button>
          </Group>
        </Stack>
      </Modal>

      {/* View detail modal */}
      <Modal
        opened={detailOpen}
        onClose={() => { setDetailOpen(false); setActiveId(null); }}
        title={<Text fw={600}>Delivery Detail</Text>}
        size="lg"
        radius="lg"
        centered
      >
        <Stack gap="md">
          {activeRecord && <BookingInfo record={activeRecord} />}
          {activeRecord && (activeRecord.vehicleAssignments?.length ?? 0) > 0 && (
            <Card withBorder padding="md" radius="md">
              <Text fw={600} size="sm" mb="sm">Assigned vehicles</Text>
              <Stack gap="xs">
                {activeRecord.vehicleAssignments!.map((a) => {
                  const v = a.vehicle;
                  const label = v
                    ? [v.code, v.plateNumber].filter(Boolean).join(" · ")
                    : a.vehicleId;
                  return (
                    <Group key={a.id} justify="space-between" wrap="nowrap">
                      <Text size="sm">{label}</Text>
                      {a.containerNumber ? (
                        <Badge size="sm" variant="light" color="blue">
                          {a.containerNumber}
                        </Badge>
                      ) : (
                        <Text size="xs" c="dimmed">No container no.</Text>
                      )}
                    </Group>
                  );
                })}
              </Stack>
            </Card>
          )}
          {activeRecord && (
            <Card withBorder padding="md" radius="md">
              <Text fw={600} size="sm" mb="sm">Delivery steps</Text>
              <LastMileStepper
                steps={computeLastMileSteps(
                  activeRecord,
                  pickupReadyByBooking.get(activeRecord.bookingId) ??
                    pickupReadyByBooking.get(bookingRef(activeRecord)),
                )}
              />
            </Card>
          )}
          <Group justify="flex-end">
            <Button variant="default" onClick={() => { setDetailOpen(false); setActiveId(null); }}>Close</Button>
          </Group>
        </Stack>
      </Modal>

      {/* Trip slip modal */}
      <Modal
        opened={tripSlipOpen}
        onClose={() => setTripSlipOpen(false)}
        title={<Text fw={600}>Trip Slip</Text>}
        size="lg"
        radius="lg"
        centered
      >
        <Stack gap="md">
          {tripSlipRecord && <TripSlipDocument record={tripSlipRecord} vehicle={tripSlipVehicle} />}
          <Divider />
          <Group justify="flex-end" gap="sm">
            <Button variant="default" onClick={() => setTripSlipOpen(false)}>Close</Button>
            <Button leftSection={<Printer size={16} />} onClick={printTripSlip}>Print</Button>
          </Group>
        </Stack>
      </Modal>

      {/* Trip slip — pick a vehicle (multi-truck) */}
      <Modal
        opened={tripSlipSelectOpen}
        onClose={() => setTripSlipSelectOpen(false)}
        title={<Text fw={600}>Print trip slip — select vehicle</Text>}
        radius="lg"
        centered
      >
        <Stack gap="sm">
          <Text size="sm" c="dimmed">
            {tripSlipRecord ? bookingRef(tripSlipRecord) : ""} — pick a truck to print its slip.
          </Text>
          {(tripSlipRecord?.vehicleAssignments ?? []).map((a) => {
            const v = a.vehicle;
            const label = v ? [v.code, v.plateNumber].filter(Boolean).join(" · ") : a.vehicleId;
            return (
              <Card
                key={a.id}
                withBorder
                radius="md"
                padding="sm"
                onClick={() => chooseTripSlipVehicle(a.vehicleId)}
                style={{ cursor: "pointer" }}
                className="hover:bg-gray-50"
              >
                <Group justify="space-between" wrap="nowrap" align="center">
                  <Stack gap={2} style={{ minWidth: 0 }}>
                    <Group gap="xs" wrap="nowrap">
                      <Truck size={15} />
                      <Text size="sm" fw={600} truncate>{label}</Text>
                    </Group>
                    <Text size="xs" c="dimmed" truncate>
                      Driver: {v?.assignedDriverName || "—"}
                    </Text>
                    <Text size="xs" c="dimmed" truncate>
                      Container: {a.containerNumber || "—"}
                    </Text>
                  </Stack>
                  <ActionIcon variant="light" color="edr-green" size="lg" aria-label="Print">
                    <Printer size={16} />
                  </ActionIcon>
                </Group>
              </Card>
            );
          })}
          {(tripSlipRecord?.vehicleAssignments?.length ?? 0) === 0 && (
            <Text size="sm" c="dimmed" ta="center" py="xs">No vehicles assigned yet.</Text>
          )}
          <Divider label="or" labelPosition="center" />
          <Button variant="subtle" size="sm" onClick={printBookingSlip}>
            Print booking slip (no vehicle)
          </Button>
        </Stack>
      </Modal>

      {/* Add Actual Distance modal */}
      <Modal
        opened={distanceOpen}
        onClose={closeDistance}
        title={<Text fw={600}>Add Actual Distance</Text>}
        size="md"
        radius="lg"
        centered
      >
        <Stack gap="md">
          {activeRecord && (
            <Card withBorder padding="md" radius="md" bg="var(--mantine-color-gray-0)">
              <Group justify="space-between">
                <Text fw={600} size="sm">{bookingRef(activeRecord)}</Text>
                <Text size="xs" c="dimmed">Est. {activeRecord.estimatedKm ?? "—"} km</Text>
              </Group>
            </Card>
          )}
          {(activeRecord?.vehicleAssignments?.length ?? 0) === 0 ? (
            <Text size="sm" c="dimmed">Assign a vehicle before entering distance.</Text>
          ) : (
            <Stack gap="sm">
              {activeRecord!.vehicleAssignments!.map((a) => {
                const v = a.vehicle;
                const label = v ? [v.code, v.plateNumber].filter(Boolean).join(" · ") : a.vehicleId;
                return (
                  <NumberInput
                    key={a.id}
                    label={`${label}${a.containerNumber ? ` · ${a.containerNumber}` : ""}`}
                    placeholder="Distance (km)"
                    value={distanceRows[a.vehicleId] ?? ""}
                    onChange={(val) =>
                      setDistanceRows((prev) => ({ ...prev, [a.vehicleId]: String(val ?? "") }))
                    }
                    min={0}
                    step={0.1}
                    decimalScale={2}
                  />
                );
              })}
              <Group justify="space-between">
                <Text size="xs" c="dimmed">Total</Text>
                <Text size="sm" fw={600}>
                  {Object.values(distanceRows)
                    .reduce((s, val) => s + (parseFloat(val) || 0), 0)
                    .toFixed(2)}{" "}
                  km
                </Text>
              </Group>
            </Stack>
          )}
          <Group justify="flex-end" gap="sm">
            <Button variant="default" onClick={closeDistance}>Cancel</Button>
            <Button
              onClick={handleSaveDistance}
              loading={distanceMutation.isPending}
              disabled={Object.values(distanceRows).every((v) => !v)}
            >
              Save
            </Button>
          </Group>
        </Stack>
      </Modal>

      {/* Generate Invoice — confirmation summary */}
      <Modal
        opened={Boolean(invoiceConfirm)}
        onClose={() => setInvoiceConfirm(null)}
        title={<Text fw={600}>Generate Invoice</Text>}
        radius="lg"
        centered
      >
        {invoiceConfirm && (
          <Stack gap="md">
            <Group justify="space-between">
              <Text fw={600} size="sm">{bookingRef(invoiceConfirm)}</Text>
              <Text size="sm" c="dimmed">{customerName(invoiceConfirm)}</Text>
            </Group>
            <Card withBorder padding="sm" radius="md" bg="var(--mantine-color-gray-0)">
              <Stack gap={6}>
                {(invoiceConfirm.vehicleAssignments ?? []).map((a) => {
                  const v = a.vehicle;
                  const label = v ? [v.code, v.plateNumber].filter(Boolean).join(" · ") : a.vehicleId;
                  return (
                    <Group key={a.id} justify="space-between" wrap="nowrap">
                      <Text size="sm">
                        {label}
                        {a.containerNumber ? ` · ${a.containerNumber}` : ""}
                      </Text>
                      <Text size="sm">{a.distanceKm != null ? `${a.distanceKm} km` : "—"}</Text>
                    </Group>
                  );
                })}
              </Stack>
            </Card>
            <Group justify="space-between">
              <Text size="sm" c="dimmed">Total distance</Text>
              <Text size="sm" fw={500}>{invoiceConfirm.exactKm ?? 0} km</Text>
            </Group>
            <Group justify="space-between">
              <Text fw={600}>Invoice amount</Text>
              <Text fw={700}>{formatPrice(invoiceConfirm.remainingPayment, currencyOf(invoiceConfirm))}</Text>
            </Group>
            {confirmIssues.mixedCurrency && (
              <Alert color="red" variant="light" title="Mixed truck currencies">
                Trucks use {confirmIssues.currencies.join(", ")}. Assign trucks that share one currency before invoicing.
              </Alert>
            )}
            {confirmIssues.zeroPrice.length > 0 && (
              <Alert color="yellow" variant="light" title="Truck has no price/km">
                {confirmIssues.zeroPrice.join(", ")} will bill 0 — set Price per KM on the vehicle.
              </Alert>
            )}
            <Text size="xs" c="dimmed">
              This creates the delivery-fee invoice. Confirm the distances and amount are correct.
            </Text>
            <Group justify="flex-end" gap="sm">
              <Button variant="default" onClick={() => setInvoiceConfirm(null)}>Cancel</Button>
              <Button
                loading={generateInvoiceMutation.isPending}
                disabled={confirmIssues.mixedCurrency}
                onClick={() =>
                  generateInvoiceMutation.mutate(invoiceConfirm.id, {
                    onSuccess: () => setInvoiceConfirm(null),
                  })
                }
              >
                Generate Invoice
              </Button>
            </Group>
          </Stack>
        )}
      </Modal>

      <ReleaseOrderModal
        opened={Boolean(releaseItem)}
        onClose={closeTruckArrival}
        item={releaseItem}
        truckPrefill={releaseTruckPrefill}
      />

      <EdrTruckExitPapersModal
        opened={exitPapersOpen}
        onClose={() => setExitPapersOpen(false)}
        record={exitPapersRecord}
      />

      <TruckDetentionModal
        opened={Boolean(detentionRecord)}
        onClose={() => setDetentionRecord(null)}
        record={detentionRecord}
      />

      <ProofOfDeliveryModal
        opened={Boolean(podRecord)}
        onClose={() => setPodRecord(null)}
        lastMileId={podRecord?.id ?? null}
        reference={podRecord?.booking?.reference ?? null}
        onDone={() => {
          void qc.invalidateQueries({ queryKey: QUERY_KEYS.LAST_MILE.ROOT });
          void qc.invalidateQueries({ queryKey: ["vehicles"] });
        }}
      />
    </Stack>
  );
};

export default LastMilePage;
