import { useEffect, useMemo, useState } from "react";
import {
  Navigate,
  useNavigate,
  useParams,
  useSearchParams,
} from "react-router-dom";
import { useQuery } from "@tanstack/react-query";
import {
  Alert,
  Badge,
  Box,
  Button,
  Card,
  Center,
  FileInput,
  Group,
  Loader,
  Paper,
  Progress,
  RingProgress,
  SimpleGrid,
  Stack,
  Table,
  Tabs,
  Text,
  Title,
} from "@mantine/core";
import {
  AlertTriangle,
  ArrowLeft,
  CalendarClock,
  CheckCircle2,
  ChevronRight,
  Download,
  Eye,
  FileBadge,
  FileSignature,
  FileText,
  Flame,
  Inbox,
  Layers,
  type LucideIcon,
  MapPin,
  Package,
  PackagePlus,
  Ship,
  Snowflake,
  Split,
  Upload,
  Weight,
} from "lucide-react";
import { Modal } from "@mantine/core";
import { useDisclosure } from "@mantine/hooks";
import { isViewable, type ViewableFile } from "@edr/ui-common";
import type { Freight } from "@edr/types";
import { clearanceWorkflowFileLabel } from "@edr/types";
import { api } from "@/services/api";
import { contractsService } from "@/services/contracts.service";
import { fetchViewableFile, downloadStoredFile } from "@/services/files.service";
import { useFileViewer } from "@/hooks/useFileViewer";
import toast from "react-hot-toast";
import { labelForDocCode } from "@/pages/bookings/resubmit";
import {
  BookingStatusBadge,
  BookingTypeBadge,
  CargoModeCell,
  PaymentBadge,
  SchedulingCell,
} from "@/pages/bookings/booking-display";
import { ContractClearancePanel } from "./ContractClearancePanel";
import { ContractClearanceWorkflowBanner } from "./ContractClearanceWorkflowBanner";
import { ClearanceUploadedDocumentsPanel } from "@/components/contracts/ClearanceUploadedDocumentsPanel";
import { InitiateBookingButton } from "@/components/customer-actions/ContractCustomerAction";
import { formatRateUnit } from "./new-contract-form/unit-rates";
import { getContractBookingAction } from "./contract-booking-action";
import { closedWindowMessage, hasOpenWindow } from "./booking-window";
import { ContractBookingWindowsSection } from "./ContractBookingWindowsSection";
import {
  BORDER,
  ContractStatusBadge,
  GREEN,
  INK,
  MetaItem,
  MUTED,
} from "./contract-ui";

// Statuses where the customer uploads clearance documents on the contract. Used
// by both paths: Path B (customs, GL-reviewed) and Path A self-clearance
// (non-customs IMPORT/EXPORT, Operations-reviewed).
const CLEARANCE_UPLOAD_STATUSES = [
  "AWAITING_CLEARANCE_DOCUMENTS",
  "CLEARANCE_UNDER_REVIEW",
  "CLEARANCE_READY_FOR_BOOKING",
];

type ContractFile = NonNullable<Freight.IContract["files"]>[number];

// Customer-facing labels for a shipment-request status (BOOKING_REQUEST_STATUSES).
const BOOKING_REQUEST_STATUS_LABELS: Record<string, string> = {
  PENDING: "Pending review",
  ACCEPTED: "Accepted",
  REJECTED: "Rejected",
  CANCELLED: "Cancelled",
};

// Customer-facing labels for an invoice status (Freight.InvoiceStatus).
const INVOICE_STATUS_LABELS: Record<string, string> = {
  DRAFT: "Draft",
  ISSUED: "Issued",
  PENDING: "Due",
  PARTIALLY_PAID: "Partially paid",
  PAID: "Paid",
  OVERDUE: "Overdue",
  CANCELLED: "Cancelled",
  REFUNDED: "Refunded",
  EXPIRED: "Expired",
};

function invoiceStatusLabel(status: string): string {
  return (
    INVOICE_STATUS_LABELS[status] ??
    status
      .replace(/_/g, " ")
      .toLowerCase()
      .replace(/\b\w/g, (m) => m.toUpperCase())
  );
}

// Business-license document codes — surfaced as their own section so they stand
// out from the rest of the onboarding/profile set.
const BUSINESS_LICENSE_DOC_CODES = new Set([
  "business_license",
  "commercial_license",
  "investment_license",
  "trade_license",
]);

// Licences carried from the company profile are suffixed per file
// (`business_license_1`), so match on the stripped base code too.
const isBusinessLicenseCode = (code: string): boolean =>
  BUSINESS_LICENSE_DOC_CODES.has(code) ||
  BUSINESS_LICENSE_DOC_CODES.has(code.replace(/_\d+$/, ""));

// Onboarding / company-profile document codes seeded in file-upload-settings.
// These get attached to the contract at creation and belong under "Profile
// documents" rather than the clearance set.
const PROFILE_DOC_CODES = new Set([
  "tin_certificate",
  "tin",
  "national_id",
  "national_id_passport",
  "passport",
  // The seeded company-onboarding setting stores the national ID field with the
  // bare code "id" — without this the doc lands in the clearance catch-all.
  "id",
]);

interface DocGroup {
  key: string;
  title: string;
  files: ContractFile[];
}

/**
 * Split a contract's files into display sections by their `code`: the generated
 * contract PDF, company profile / onboarding documents, and clearance documents
 * (everything else — the clearance set uses dynamic per-contract codes). Empty
 * groups are dropped so the tab only renders sections that have files.
 *
 * GENERAL contracts clear per booking, so their contract-level "clearance"
 * leftovers are not shown — pass includeClearance: false to keep only the
 * profile / business-licence sections.
 */
function groupContractDocuments(
  files: ContractFile[],
  {
    includeClearance = true,
    clearanceKeys,
  }: { includeClearance?: boolean; clearanceKeys?: Set<string> } = {},
): DocGroup[] {
  const businessLicense: ContractFile[] = [];
  const profile: ContractFile[] = [];
  const clearance: ContractFile[] = [];
  const other: ContractFile[] = [];

  // A file belongs to the clearance set when its code matches a clearance
  // upload field (multi-file uploads append `_<n>`), an ad-hoc `custom_*` doc,
  // or a known GL workflow artifact. Without a key list (clearance view not
  // loaded for this status) everything unclassified stays under clearance —
  // the pre-existing catch-all behaviour.
  const isClearanceCode = (code: string): boolean => {
    if (code.startsWith("custom_")) return true;
    if (clearanceWorkflowFileLabel(code)) return true;
    if (!clearanceKeys || clearanceKeys.size === 0) return true;
    return (
      clearanceKeys.has(code) || clearanceKeys.has(code.replace(/_\d+$/, ""))
    );
  };

  for (const f of files) {
    // The generated contract PDF lives in the contract list / home rows, not
    // here. Signature images are baked into that PDF — skip both.
    if (f.code === "contract" || f.code.startsWith("signature_")) continue;
    else if (isBusinessLicenseCode(f.code)) businessLicense.push(f);
    else if (PROFILE_DOC_CODES.has(f.code)) profile.push(f);
    else if (includeClearance && isClearanceCode(f.code)) clearance.push(f);
    else other.push(f);
  }
  return [
    { key: "profile", title: "Company profile", files: profile },
    { key: "businessLicense", title: "Business license", files: businessLicense },
    { key: "clearance", title: "Clearance documents", files: clearance },
    { key: "other", title: "Other documents", files: other },
  ].filter((g) => g.files.length > 0);
}

export default function ContractDetailPage() {
  const { id } = useParams<{ id: string }>();
  const navigate = useNavigate();
  const [tab, setTab] = useState<string>("details");
  const { view, viewer } = useFileViewer();
  const [clearanceOpen, clearanceModal] = useDisclosure(false);
  const [searchParams, setSearchParams] = useSearchParams();

  // Deep link from the home "needs attention" card: /contracts/:id?action=clearance
  // opens the clearance step modal directly.
  useEffect(() => {
    if (searchParams.get("action") === "clearance") {
      clearanceModal.open();
      searchParams.delete("action");
      setSearchParams(searchParams, { replace: true });
    }
  }, [searchParams, clearanceModal, setSearchParams]);

  const {
    data: contract,
    isLoading,
    isError,
  } = useQuery(
    api.contracts.get.queryOptions({ input: { id: id! }, enabled: !!id }),
  );

  // Shipments booked under this contract.
  const { data: bookingsPage } = useQuery({
    ...api.bookings.list.queryOptions({
      input: { page: 1, pageSize: 50, sortBy: "createdAt", sortOrder: "DESC" },
    }),
    enabled: !!id,
  });

  // Clearance view — drives queries alert, workflow documents, and duty panels.
  const inClearance =
    !!contract && CLEARANCE_UPLOAD_STATUSES.includes(contract.status);
  const isPhasedCustomsClearance =
    !!contract &&
    contract.customsClearingEnabled &&
    contract.contractKind === "ONE_TIME";
  const { data: clearanceView, refetch: refetchClearance } = useQuery({
    ...api.contracts.getClearance.queryOptions({ input: { id: id! } }),
    enabled: !!id && (inClearance || isPhasedCustomsClearance),
  });
  const workflowFiles = clearanceView?.workflowFiles ?? [];
  const workflowFileCount = workflowFiles.filter((f) => f.file).length;
  const queriedCount = (clearanceView?.documents ?? []).filter(
    (d) => d.uploadedBy === "customer" && d.reviewStatus === "QUERIED",
  ).length;

  const showShipmentRequests =
    !!contract &&
    contract.contractKind === "GENERAL" &&
    contract.customsClearingEnabled;
  const { data: shipmentRequests = [] } = useQuery({
    queryKey: ["contract-booking-requests", id],
    queryFn: () => contractsService.listBookingRequests(id!),
    enabled: !!id && showShipmentRequests,
  });
  const activeShipmentRequests = shipmentRequests.filter(
    (r) => r.status === "PENDING" || r.status === "ACCEPTED",
  );

  // Booking windows for this contract's routes — gates the direct "New shipment
  // booking" entry so the customer only sees it while a window is open.
  // Refetched every minute so "Open now" flips without a manual reload.
  const { data: bookingWindows = [], isLoading: windowsLoading } = useQuery({
    ...api.bookings.getContractBookingWindows.queryOptions({
      input: { contractId: id! },
      refetchInterval: 60_000,
    }),
    enabled: !!id,
  });
  // Intercity contracts are never window-gated: the shipment rides a passing
  // import/export train that staff assign later, so booking is always open.
  // ONE_TIME and GENERAL contracts are both gated — booking is only possible
  // while a window on the contract's lane is open.
  const bookingWindowOpen =
    contract?.tradeDirection === "DOMESTIC" ||
    hasOpenWindow(bookingWindows);

  const contractBookings = useMemo(
    () =>
      (bookingsPage?.items ?? []).filter(
        (b) => (b as { contractId?: string }).contractId === id,
      ),
    [bookingsPage, id],
  );

  // A booking reduced by a paid partial split that still holds quantity. On a
  // ONE_TIME contract this switches the contract into remainder-only booking;
  // on a GENERAL contract it is informational (the leftover simply returned).
  const splitBooking = useMemo(
    () =>
      contractBookings.find(
        (b) =>
          (b as { isSplit?: boolean }).isSplit &&
          !["CANCELLED", "REJECTED", "EXPIRED"].includes(b.status),
      ),
    [contractBookings],
  );

  // Draw-down capacity per cargo line (GENERAL contracts), or the outstanding
  // split remainder of a ONE_TIME contract. The backend excludes CANCELLED/
  // REJECTED/EXPIRED bookings, so a shipment that never ships releases its
  // share and the tracker fills back up. Refetched on window focus so it
  // reflects newly created / cancelled shipments.
  const { data: capacityLines = [] } = useQuery({
    queryKey: ["contract-capacity", id],
    queryFn: () => contractsService.getCapacity(id!),
    enabled:
      !!id && (contract?.contractKind === "GENERAL" || Boolean(splitBooking)),
    refetchOnWindowFocus: true,
  });

  if (isLoading) {
    return (
      <Center mih={400} p="xl">
        <Stack align="center" gap="md">
          <Loader color="edr-green" />
          <Text size="sm" c="dimmed">
            Loading contract…
          </Text>
        </Stack>
      </Center>
    );
  }

  if (isError || !contract) {
    return (
      <Box p="xl">
        <Paper withBorder radius="lg" p="xl" style={{ borderColor: BORDER }}>
          <Text fw={700} mb="xs">
            Contract not found
          </Text>
          <Button variant="default" onClick={() => navigate("/contracts")}>
            Back to contracts
          </Button>
        </Paper>
      </Box>
    );
  }

  // Not yet submitted (customer saved a draft) or staff returned the contract for
  // changes — send the customer to the full edit wizard (edit any term + replace
  // documents → submit) rather than the read-only detail.
  if (
    contract.status === "DRAFT" ||
    contract.status === "RENEWAL_DRAFT" ||
    contract.status === "CHANGES_REQUESTED"
  ) {
    return <Navigate to={`/contracts/${contract.id}/edit`} replace />;
  }

  const isContainer = contract.freightType === "CONTAINER";
  const isGeneral = contract.contractKind === "GENERAL";
  const routes = contract.routes ?? [];
  const pricing = contract.pricingBreakdown;
  const files = contract.files ?? [];
  // GENERAL contracts clear per booking — clearance documents live on each
  // booking's detail page, so this tab keeps only profile/licence documents.
  // Clearance upload field keys (when the clearance view is loaded) let the
  // grouping tell real clearance docs apart from other attachments.
  const docGroups = groupContractDocuments(files, {
    includeClearance: contract.contractKind !== "GENERAL",
    clearanceKeys: new Set(
      (clearanceView?.documents ?? []).map((d) => d.fileKey),
    ),
  });
  const docCount = docGroups.reduce((sum, g) => sum + g.files.length, 0);
  // The generated contract PDF — surfaced via a dedicated "View contract" button
  // in the header (it's excluded from the Documents tab groups).
  const contractPdf = files.find((f) => f.code === "contract");
  const hasContractDocument = Boolean(contractPdf || contract.contractGeneratedAt);

  const downloadContractPdf = async () => {
    if (!contract?.id) return;
    try {
      const blob = await contractsService.downloadContractDocument(contract.id);
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = contractPdf?.name ?? `contract-${contract.reference}.pdf`;
      a.click();
      URL.revokeObjectURL(url);
    } catch {
      toast.error("Could not download contract PDF.");
    }
  };

  const canSign = contract.status === "CONTRACT_READY";
  const customsPath = contract.customsClearingEnabled;
  // Intercity (DOMESTIC) has no customs — the document gate collects the
  // admin-configured intercity set, reviewed by Operations.
  const isIntercity = contract.tradeDirection === "DOMESTIC";
  const docNoun = isIntercity ? "intercity documents" : "clearance documents";
  // Only the NON-customs (Path A) customer books himself — once the contract is
  // executed after self-clearance. Customs (Path B) bookings are created by
  // Global Logistics on the customer's behalf, so the customer gets no booking
  // button on a customs contract.
  const clearanceFinalized =
    contract.clearanceStatus === "CLEARANCE_READY_FOR_BOOKING" ||
    contract.status === "CLEARANCE_READY_FOR_BOOKING";
  const bookingAction = getContractBookingAction(contract, contractBookings);
  // Whether the customer may open a new self-service booking. Derived from the
  // shared booking-action helper so it honours the ONE_TIME single-slot rule:
  // once a non-terminal booking exists on a ONE_TIME contract there is no free
  // slot, so the action is "none" and no booking button is shown.
  const canBookShipment =
    bookingAction.kind === "book" || bookingAction.kind === "rebook";
  const canRequestShipment = bookingAction.kind === "request";
  // GENERAL non-customs import/export: one-click bare booking instance — the
  // per-booking clearance runs first, so no window gate applies here.
  const canInitiateBooking = bookingAction.kind === "initiate";
  // Customs + clearance finalized: GL is preparing the booking — surface a
  // status notice instead of any action.
  const glPreparingBooking = customsPath && clearanceFinalized;
  // The customer uploads clearance documents while in a clearance status, until
  // clearance is finalized.
  const canUploadClearance =
    CLEARANCE_UPLOAD_STATUSES.includes(contract.status) && !clearanceFinalized;

  return (
    <Box style={{ padding: "28px 32px 40px" }}>
      <Stack gap="lg">
        {/* Header */}
        <Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
          <Group gap="md" align="center" wrap="nowrap">
            <Button
              variant="subtle"
              color="gray"
              radius="md"
              px={8}
              onClick={() => navigate("/contracts")}
            >
              <ArrowLeft size={18} />
            </Button>
            <div>
              <Group gap={10} align="center">
                <Title order={2} fw={800} fz={22} style={{ color: INK }}>
                  {contract.reference}
                </Title>
                <ContractStatusBadge status={contract.status} />
              </Group>
              <Text size="sm" c="dimmed" mt={2}>
                {isGeneral ? "General contract" : "One-time contract"} ·{" "}
                {isContainer ? "Containerised" : "Bulk"} ·{" "}
                {contract.tradeDirection ?? "—"}
              </Text>
            </div>
          </Group>

          <Group gap="sm">
            {canSign ? (
              <Button
                color="edr-green"
                radius="md"
                size="md"
                leftSection={<FileSignature size={16} />}
                onClick={() => navigate(`/contracts/${contract.id}/view`)}
              >
                View &amp; sign contract
              </Button>
            ) : (
              contractPdf && (
                <Button
                  variant="default"
                  radius="md"
                  size="md"
                  leftSection={<FileText size={16} />}
                  onClick={() =>
                    void fetchViewableFile(contractPdf.id, contractPdf.name).then(
                      view,
                    )
                  }
                >
                  View contract
                </Button>
              )
            )}
            {hasContractDocument && (
              <Button
                variant="default"
                radius="md"
                size="md"
                leftSection={<Download size={16} />}
                onClick={() => void downloadContractPdf()}
              >
                Download PDF
              </Button>
            )}
            {canRequestShipment && (
              <Button
                color="edr-green"
                radius="md"
                size="md"
                leftSection={<PackagePlus size={16} />}
                onClick={() => navigate(bookingAction.to)}
              >
                Request shipment
              </Button>
            )}
            {canInitiateBooking && (
              <InitiateBookingButton
                contract={contract}
                icon={PackagePlus}
                size="md"
              />
            )}
            {canBookShipment &&
              (bookingWindowOpen ? (
                <Button
                  color="edr-green"
                  radius="md"
                  size="md"
                  leftSection={<PackagePlus size={16} />}
                  onClick={() =>
                    navigate(`/contracts/${contract.id}/bookings/new`)
                  }
                >
                  New shipment booking
                </Button>
              ) : (
                <Paper
                  withBorder
                  radius="md"
                  px="md"
                  py={10}
                  maw={420}
                  style={{ borderColor: BORDER, background: "#F8FAFC" }}
                >
                  <Group gap={10} align="flex-start" wrap="nowrap">
                    <CalendarClock
                      size={16}
                      color={MUTED}
                      style={{ flexShrink: 0, marginTop: 2 }}
                    />
                    <Text fz={13} c="dimmed">
                      {closedWindowMessage(bookingWindows)}
                    </Text>
                  </Group>
                </Paper>
              ))}
            {glPreparingBooking && (
              <Badge
                size="lg"
                radius="md"
                variant="light"
                color="teal"
                leftSection={<CheckCircle2 size={14} />}
              >
                Global Logistics is creating your booking
              </Badge>
            )}
            {canUploadClearance && (
              <Button
                color="edr-green"
                radius="md"
                size="md"
                leftSection={<Upload size={16} />}
                onClick={clearanceModal.open}
              >
                {contract.status === "CLEARANCE_UNDER_REVIEW"
                  ? `Manage ${docNoun}`
                  : `Upload ${docNoun}`}
              </Button>
            )}
          </Group>
        </Group>

        {/* Key facts — one premium gradient card */}
        <Paper
          radius={18}
          withBorder
          style={{
            borderColor: "#DCEBE3",
            overflow: "hidden",
            background:
              "linear-gradient(120deg, #F1FAF5 0%, #F7FCF9 34%, #FFFFFF 78%)",
            boxShadow: "0 8px 24px rgba(14,163,113,0.08)",
          }}
        >
          <SimpleGrid
            cols={{ base: 2, sm: 3, xl: 5 }}
            spacing={0}
            verticalSpacing={0}
          >
            <FactCell
              icon={Layers}
              label="Kind"
              value={isGeneral ? "General" : "One-Time"}
            />
            <FactCell
              icon={Package}
              label="Cargo"
              value={isContainer ? "Container" : "Bulk"}
              color="violet"
            />
            <FactCell
              icon={MapPin}
              label="Routes"
              value={String(routes.length || 1)}
            />
            <FactCell
              icon={Ship}
              label="Trade"
              value={contract.tradeDirection ?? "—"}
              color="orange"
            />
            <FactCell
              icon={CalendarClock}
              label="Valid until"
              value={
                contract.contractValidUntil
                  ? new Date(contract.contractValidUntil).toLocaleDateString()
                  : "Not active yet"
              }
            />
          </SimpleGrid>
        </Paper>

        {/* Booking windows on this contract's routes/direction only (the API
            filters by the contract's lanes). Intercity contracts aren't
            window-gated, so nothing is shown for them. */}
        {contract.tradeDirection !== "DOMESTIC" && (
          <ContractBookingWindowsSection
            windows={bookingWindows}
            isLoading={windowsLoading}
          />
        )}

        {/* Tabs: Details · Documents · Bookings (pill style, like the
            backoffice booking-requests page; each tab shows a count badge). */}
        <Tabs
          value={tab}
          onChange={(v) => setTab(v ?? "details")}
          variant="pills"
          color="edr-green"
          keepMounted={false}
        >
          <Tabs.List
            mb="lg"
            style={{
              display: "flex",
              flexWrap: "wrap",
              gap: 8,
              padding: 6,
              background: "#F1F5F9",
              borderRadius: 16,
              border: "1px solid #E2E8F0",
              width: "fit-content",
            }}
          >
            <DetailTab
              value="details"
              active={tab === "details"}
              icon={<FileText size={16} />}
              label="Details"
            />
            <DetailTab
              value="documents"
              active={tab === "documents"}
              icon={<Download size={16} />}
              label="Documents"
              count={docCount + (isPhasedCustomsClearance ? workflowFileCount : 0)}
            />
            <DetailTab
              value="bookings"
              active={tab === "bookings"}
              icon={<Package size={16} />}
              label="Bookings"
              count={contractBookings.length}
            />
          </Tabs.List>

          {/* ── Details tab ───────────────────────────────────────────── */}
          <Tabs.Panel value="details">
            <Stack gap="lg">
        {/* Summary meta */}
        <Paper withBorder radius="lg" p="lg" style={{ borderColor: BORDER }}>
          <Group gap={48} wrap="wrap">
            <MetaItem
              label="Primary route"
              icon={<MapPin size={15} color={MUTED} />}
              value={`${routes[0]?.originYard?.label ?? "—"} → ${
                routes[0]?.destinationYard?.label ?? "—"
              }`}
            />
            <MetaItem
              label="Customs clearance"
              icon={<FileText size={15} color={MUTED} />}
              value={customsPath ? "Included (Global Logistics)" : "Not included"}
            />
            <MetaItem
              label="Payment currency"
              value={contract.paymentCurrency ?? "—"}
            />
          </Group>
        </Paper>


        {/* Clearance notice (both paths) */}
        {queriedCount > 0 && (
          <Paper
            withBorder
            radius="lg"
            p="lg"
            style={{
              borderColor: "#F0B4B4",
              background: "#FDF4F4",
              position: "relative",
              overflow: "hidden",
            }}
          >
            <Box
              style={{
                position: "absolute",
                left: 0,
                top: 0,
                bottom: 0,
                width: 3,
                background: "#D64545",
              }}
            />
            <Group justify="space-between" align="center" wrap="wrap" gap="sm">
              <Group gap={10} align="flex-start" wrap="nowrap">
                <AlertTriangle size={18} color="#D64545" style={{ marginTop: 2 }} />
                <div>
                  <Text fw={700} fz={15} c="#7A1F1F">
                    {queriedCount} document{queriedCount > 1 ? "s" : ""} need
                    correction
                  </Text>
                  <Text fz={13} c="#9A4A4A" mt={2}>
                    A reviewer sent back document
                    {queriedCount > 1 ? "s" : ""} with a query. Re-upload the
                    corrected file{queriedCount > 1 ? "s" : ""} to continue.
                  </Text>
                </div>
              </Group>
              <Button
                color="red"
                radius="md"
                size="sm"
                leftSection={<Upload size={15} />}
                onClick={clearanceModal.open}
              >
                Upload corrected documents
              </Button>
            </Group>
          </Paper>
        )}

        {customsPath && contract.contractKind === "ONE_TIME" ? (
          <ContractClearanceWorkflowBanner contract={contract} />
        ) : null}

        {clearanceView?.riskLevel ? (
          <Paper
            withBorder
            radius="lg"
            p="md"
            style={{ borderColor: BORDER, background: "#FBFDFC" }}
          >
            <Group gap={10} align="center">
              <Text fw={700} fz={14} c={INK}>
                Customs risk level
              </Text>
              <Badge
                color={CUSTOMS_RISK_COLOR[clearanceView.riskLevel] ?? "gray"}
                variant="filled"
                radius="sm"
              >
                {clearanceView.riskLevel.charAt(0) +
                  clearanceView.riskLevel.slice(1).toLowerCase()}
              </Badge>
              {clearanceView.riskAssignedAt ? (
                <Text fz={12} c="dimmed">
                  assigned {new Date(clearanceView.riskAssignedAt).toLocaleString()}
                </Text>
              ) : null}
            </Group>
          </Paper>
        ) : null}

        {clearanceView?.secondDuty?.advised && clearanceView?.linkedBookingId ? (
          <SecondDutyDueCard
            duty={clearanceView.secondDuty}
            bookingId={clearanceView.linkedBookingId}
            onView={view}
            onChanged={() => void refetchClearance()}
          />
        ) : null}

        {clearanceView?.finalInvoice && clearanceView?.linkedBookingId ? (
          <FinalInvoiceDueCard
            invoice={clearanceView.finalInvoice}
            bookingId={clearanceView.linkedBookingId}
            onView={view}
            onChanged={() => void refetchClearance()}
          />
        ) : null}

        {canUploadClearance && (
          <Paper
            withBorder
            radius="lg"
            p="lg"
            style={{
              borderColor: "#CDEBDD",
              background: "#F6FBF8",
              position: "relative",
              overflow: "hidden",
            }}
          >
            <Box
              style={{
                position: "absolute",
                left: 0,
                top: 0,
                bottom: 0,
                width: 3,
                background: GREEN,
              }}
            />
            <Group gap={10} align="center" mb={6}>
              <Upload size={16} color={GREEN} />
              <Text fw={700} fz={15} c={INK}>
                {customsPath
                  ? "Customs clearance shipment"
                  : isIntercity
                    ? "Intercity documents required"
                    : "Customs clearance required"}
              </Text>
            </Group>
            <Text fz={13} c="dimmed">
              {customsPath
                ? contract.status === "AWAITING_CLEARANCE_DOCUMENTS"
                  ? "Upload your clearance documents so Global Logistics can review them. Once they finalize the clearance you can create your shipment booking."
                  : contract.status === "CLEARANCE_UNDER_REVIEW"
                    ? "Global Logistics is reviewing your clearance documents. Re-upload any queried documents to proceed."
                    : "Your documents are cleared. You can now create a shipment booking under this contract."
                : isIntercity
                  ? contract.status === "AWAITING_CLEARANCE_DOCUMENTS"
                    ? "Upload the required intercity documents so the Operations team can review them before you book a shipment."
                    : contract.status === "CLEARANCE_UNDER_REVIEW"
                      ? "The Operations team is reviewing your intercity documents. Re-upload any queried documents to proceed."
                      : "Your intercity documents are approved. You can now create a shipment booking under this contract."
                  : contract.status === "AWAITING_CLEARANCE_DOCUMENTS"
                    ? "This service does not include EDR customs clearance. Clear the cargo yourself and upload your clearance documents so the Operations team can review them before you book a shipment."
                    : contract.status === "CLEARANCE_UNDER_REVIEW"
                      ? "The Operations team is reviewing your clearance documents. Re-upload any queried documents to proceed."
                      : "Your clearance documents are approved. You can now create a shipment booking under this contract."}
            </Text>
            {contract.status !== "CLEARANCE_READY_FOR_BOOKING" && (
              <Button
                mt="md"
                color="edr-green"
                radius="md"
                size="sm"
                leftSection={<Upload size={15} />}
                onClick={clearanceModal.open}
              >
                {contract.status === "AWAITING_CLEARANCE_DOCUMENTS"
                  ? "Upload documents"
                  : "Manage documents"}
              </Button>
            )}
          </Paper>
        )}

        {/* Unit-rate schedule */}
        <Card
          withBorder
          radius="lg"
          p="lg"
          style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
        >
          <Group justify="space-between" align="center" mb={4}>
            <SectionLabel>Pricing schedule</SectionLabel>
            <Badge size="sm" variant="light" color="edr-green" radius="sm">
              Unit rates
            </Badge>
          </Group>
          <Text fz={13} c="dimmed" mb="md">
            Per-unit rates frozen at submission. The final amount on each shipment
            is computed from the quantities you ship.
          </Text>
          {pricing && pricing.lineItems.length > 0 ? (
            <Stack gap={10}>
              {pricing.lineItems.map((item) => (
                <Group
                  key={item.code}
                  justify="space-between"
                  wrap="nowrap"
                  p="sm"
                  style={{ borderRadius: 12, border: `1px solid ${BORDER}` }}
                >
                  <Box style={{ minWidth: 0 }}>
                    <Text fz={14} fw={600} style={{ color: INK }} truncate>
                      {item.label}
                    </Text>
                    {item.containerSize && (
                      <Text fz={12} c="dimmed">
                        {item.containerSize}
                      </Text>
                    )}
                    {item.isClearance && (
                      <Text fz={12} fw={600} style={{ color: GREEN }}>
                        Customs service fee — billed on your shipment booking
                        invoice together with the freight
                      </Text>
                    )}
                  </Box>
                  <Text fz={14} fw={700} style={{ color: GREEN }}>
                    {(item.unitPrice ?? 0).toLocaleString()} {pricing.currency}{" "}
                    <Text span fz={12} fw={600} c="dimmed">
                      / {formatRateUnit(item.unit)}
                    </Text>
                  </Text>
                </Group>
              ))}
            </Stack>
          ) : (
            <Text fz={13} c="dimmed">
              No pricing schedule available yet.
            </Text>
          )}
        </Card>

        {/* Routes + cargo scope */}
        <SimpleGrid cols={{ base: 1, lg: 2 }} spacing="lg">
          <Card
            withBorder
            radius="lg"
            p="lg"
            style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
          >
            <Group justify="space-between" align="center" mb="md">
              <SectionLabel>Routes</SectionLabel>
              <Badge size="sm" variant="light" color="violet" radius="sm">
                {routes.length || 1}
              </Badge>
            </Group>
            <Stack gap={10}>
              {routes.length === 0 && (
                <Text fz={13} c="dimmed">
                  No routes recorded.
                </Text>
              )}
              {routes.map((route) => (
                <Group
                  key={route.id}
                  gap={12}
                  wrap="nowrap"
                  p="sm"
                  style={{ borderRadius: 12, border: `1px solid ${BORDER}` }}
                >
                  <MapPin size={16} color={MUTED} style={{ flexShrink: 0 }} />
                  <Box style={{ minWidth: 0 }}>
                    <Text fz={14} fw={700} style={{ color: INK }} truncate>
                      {route.originYard?.label ?? route.originYardId} →{" "}
                      {route.destinationYard?.label ?? route.destinationYardId}
                    </Text>
                    {route.km != null && (
                      <Text fz={12} c="dimmed">
                        {route.km} km
                      </Text>
                    )}
                  </Box>
                </Group>
              ))}
            </Stack>
          </Card>

          <Card
            withBorder
            radius="lg"
            p="lg"
            style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
          >
            <SectionLabel mb="md">Cargo scope</SectionLabel>
            <Stack gap={10}>
              {(contract.cargoScope ?? []).map((scope) => (
                <Group
                  key={scope.id}
                  gap={12}
                  wrap="nowrap"
                  p="sm"
                  style={{ borderRadius: 12, border: `1px solid ${BORDER}` }}
                >
                  {isContainer ? (
                    <Package size={16} color={MUTED} style={{ flexShrink: 0 }} />
                  ) : (
                    <Weight size={16} color={MUTED} style={{ flexShrink: 0 }} />
                  )}
                  <Text fz={14} fw={600} style={{ color: INK }}>
                    {scope.containerSize ??
                      scope.cargoFreeText ??
                      "Bulk commodity"}
                  </Text>
                </Group>
              ))}
              {(contract.cargoScope ?? []).length === 0 && (
                <Text fz={13} c="dimmed">
                  No cargo scope recorded.
                </Text>
              )}
              <Group gap={10} mt={4}>
                {contract.isHazardous && (
                  <Badge
                    leftSection={<Flame size={12} />}
                    variant="light"
                    color="red"
                    radius="sm"
                  >
                    Hazardous
                  </Badge>
                )}
                {contract.isReefer && (
                  <Badge
                    leftSection={<Snowflake size={12} />}
                    variant="light"
                    color="blue"
                    radius="sm"
                  >
                    Refrigerated
                  </Badge>
                )}
              </Group>
            </Stack>
          </Card>
        </SimpleGrid>

        {/* Booking-was-split notice. ONE_TIME: the customer may only book the
            whole outstanding remainder (API-enforced). GENERAL: informational —
            the leftover returned to the contract and books like any drawdown. */}
        {splitBooking && (
          <Alert
            color={isGeneral ? "edr-green" : "yellow"}
            variant="light"
            radius="md"
            icon={<Split size={16} />}
            title="A booking on this contract was split"
          >
            <Text fz={13}>
              Shipment {splitBooking.reference} was split because the train
              could not carry it whole — the paid part is shipping and the
              rest returned to this contract.{" "}
              {isGeneral
                ? "You can book the remaining quantity any time before the contract validity expires."
                : capacityLines.length > 0
                  ? `Your next booking must take the whole remainder: ${capacityLines
                      .filter((l) => (l.remaining ?? 0) > 0)
                      .map(
                        (l) =>
                          `${l.remaining} ${
                            isContainer
                              ? `× ${l.containerSize ?? "container"}`
                              : "tons"
                          }`,
                      )
                      .join(", ")}. No other booking can be created on this contract.`
                  : "Your next booking must take the whole remaining quantity — no other booking can be created on this contract."}
            </Text>
          </Alert>
        )}

        {/* Draw-down capacity — GENERAL contracts with a per-line quantity cap,
            or the outstanding remainder of a split ONE_TIME contract.
            Fills as shipments consume capacity; empties again when a shipment is
            cancelled/rejected/expired (backend releases it). */}
        {(isGeneral || Boolean(splitBooking)) && capacityLines.length > 0 && (
          <Card
            withBorder
            radius="lg"
            p="lg"
            style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
          >
            <SectionLabel mb="md">Contract capacity</SectionLabel>
            <Stack gap="lg">
              {capacityLines.map((line, i) => {
                const cap = line.cap ?? 0;
                const booked = line.booked ?? 0;
                const remaining = line.remaining ?? Math.max(0, cap - booked);
                const usedPct = cap > 0 ? Math.min(100, (booked / cap) * 100) : 0;
                const remainingPct = cap > 0 ? Math.round((remaining / cap) * 100) : 0;
                const unit = capacityUnitLabel(contract, line);
                const label = isContainer
                  ? `${line.containerSize ?? "Containers"}`
                  : (contract.cargoScope ?? []).find(
                        (s) => s.cargoTypeId === line.cargoTypeId,
                      )?.cargoType?.cargoTypeName ??
                    (contract.cargoScope ?? [])[0]?.cargoFreeText ??
                    "Bulk commodity";
                return (
                  <Group
                    key={line.containerSize ?? line.cargoTypeId ?? i}
                    align="center"
                    wrap="nowrap"
                    gap="lg"
                  >
                    <RingProgress
                      size={72}
                      thickness={8}
                      roundCaps
                      sections={[
                        {
                          value: remainingPct,
                          color: remaining === 0 ? "red" : GREEN,
                        },
                      ]}
                      label={
                        <Text ta="center" fz={13} fw={700} style={{ color: INK }}>
                          {remainingPct}%
                        </Text>
                      }
                    />
                    <Box style={{ flex: 1, minWidth: 0 }}>
                      <Group justify="space-between" mb={6} wrap="nowrap">
                        <Group gap={8} wrap="nowrap">
                          {isContainer ? (
                            <Package size={16} color={MUTED} />
                          ) : (
                            <Weight size={16} color={MUTED} />
                          )}
                          <Text fz={14} fw={600} style={{ color: INK }}>
                            {label}
                          </Text>
                        </Group>
                        <Text fz={13} c="dimmed">
                          {booked} / {cap} {unit} booked
                        </Text>
                      </Group>
                      <Progress
                        value={usedPct}
                        size="md"
                        radius="xl"
                        color={remaining === 0 ? "red" : GREEN}
                      />
                      <Text fz={12} c="dimmed" mt={6}>
                        {remaining} {unit} remaining
                      </Text>
                    </Box>
                  </Group>
                );
              })}
            </Stack>
          </Card>
        )}

        {/* Signatures */}
        {(contract.signatures ?? []).length > 0 && (
          <Card
            withBorder
            radius="lg"
            p="lg"
            style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
          >
            <SectionLabel mb="md">Signatures</SectionLabel>
            <Stack gap={10}>
              {(contract.signatures ?? []).map((sig) => (
                <Group
                  key={sig.id}
                  justify="space-between"
                  wrap="nowrap"
                  p="sm"
                  style={{ borderRadius: 12, border: `1px solid ${BORDER}` }}
                >
                  <Group gap={12} wrap="nowrap">
                    <CheckCircle2
                      size={16}
                      color={GREEN}
                      style={{ flexShrink: 0 }}
                    />
                    <Box>
                      <Text fz={14} fw={600} style={{ color: INK }}>
                        {sig.signerDisplayName}
                      </Text>
                      <Text fz={12} c="dimmed">
                        {sig.role}
                      </Text>
                    </Box>
                  </Group>
                  <Text fz={12} c="dimmed">
                    {new Date(sig.signedAt).toLocaleDateString()}
                  </Text>
                </Group>
              ))}
            </Stack>
          </Card>
        )}
            </Stack>
          </Tabs.Panel>

          {/* ── Documents tab ─────────────────────────────────────────── */}
          <Tabs.Panel value="documents">
            <Stack gap="lg">
              {isPhasedCustomsClearance ? (
                <ClearanceUploadedDocumentsPanel
                  files={workflowFiles}
                  tradeDirection={contract.tradeDirection ?? "IMPORT"}
                  onView={view}
                  onDownload={async (f) => {
                    try {
                      await downloadStoredFile(f.id, f.name);
                    } catch {
                      toast.error("Could not download file.");
                    }
                  }}
                />
              ) : null}

            {docGroups.length === 0 ? (
              <Card
                withBorder
                radius="lg"
                p="lg"
                style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
              >
                <Stack align="center" gap={10} py={48}>
                  <Box
                    style={{
                      width: 56,
                      height: 56,
                      borderRadius: 16,
                      display: "flex",
                      alignItems: "center",
                      justifyContent: "center",
                      background: "#F1F5F9",
                    }}
                  >
                    <FileText size={26} color={MUTED} style={{ opacity: 0.6 }} />
                  </Box>
                  <Text fz={14} fw={600} style={{ color: INK }}>
                    No documents yet
                  </Text>
                  <Text fz={13} c="dimmed" ta="center" maw={420}>
                    {isGeneral
                      ? "Your company profile documents (TIN certificate, business licence, ID) appear here. Clearance documents are managed on each booking."
                      : "The signed contract and any uploaded clearance documents will appear here."}
                  </Text>
                </Stack>
              </Card>
            ) : (
              // One card per section — profile, business licence, clearance,
              // other — instead of a single flat list.
              docGroups.map((group) => {
                const accent = DOC_GROUP_ACCENT[group.key] ?? GREEN;
                const Icon = DOC_GROUP_ICON[group.key] ?? FileText;
                return (
                  <Card
                    key={group.key}
                    withBorder
                    radius="lg"
                    p="lg"
                    style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
                  >
                    <Group gap={12} align="center" mb={4}>
                      <Box
                        style={{
                          width: 34,
                          height: 34,
                          borderRadius: 10,
                          display: "flex",
                          alignItems: "center",
                          justifyContent: "center",
                          background: `${accent}14`,
                          color: accent,
                          flexShrink: 0,
                        }}
                      >
                        <Icon size={17} />
                      </Box>
                      <Text fz={14.5} fw={700} style={{ color: INK }}>
                        {group.title}
                      </Text>
                      <Badge size="sm" variant="light" color="gray" radius="sm">
                        {group.files.length}
                      </Badge>
                    </Group>
                    <Text fz={12.5} c="dimmed" mb="md" ml={46}>
                      {DOC_GROUP_DESC[group.key] ?? ""}
                    </Text>
                    <Stack gap={10}>
                      {group.files.map((file) => (
                        <DocFileRow key={file.id} file={file} onView={view} />
                      ))}
                    </Stack>
                  </Card>
                );
              })
            )}
            </Stack>
          </Tabs.Panel>

          {/* ── Bookings tab ──────────────────────────────────────────── */}
          <Tabs.Panel value="bookings">
            {showShipmentRequests && (
              <Card
                withBorder
                radius="lg"
                p="lg"
                mb="md"
                style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
              >
                <Group justify="space-between" align="center" mb="md">
                  <SectionLabel>Shipment requests</SectionLabel>
                  {canRequestShipment && (
                    <Button
                      color="edr-green"
                      radius="md"
                      size="xs"
                      leftSection={<PackagePlus size={14} />}
                      onClick={() => navigate(bookingAction.to)}
                    >
                      New request
                    </Button>
                  )}
                </Group>
                {activeShipmentRequests.length === 0 ? (
                  <Text fz={13} c="dimmed">
                    {canRequestShipment
                      ? "No pending shipment requests. Submit a request when you are ready to ship."
                      : "Shipment requests appear here once the contract is active."}
                  </Text>
                ) : (
                  <Stack gap={10}>
                    {activeShipmentRequests.map((req) => (
                      <Group
                        key={req.id}
                        justify="space-between"
                        wrap="nowrap"
                        p="sm"
                        style={{
                          borderRadius: 12,
                          border: `1px solid ${BORDER}`,
                          cursor: req.createdBookingId ? "pointer" : "default",
                        }}
                        onClick={() => {
                          if (req.createdBookingId) {
                            navigate(`/bookings/${req.createdBookingId}`);
                          }
                        }}
                      >
                        <Group gap={12} wrap="nowrap" style={{ minWidth: 0 }}>
                          <CalendarClock
                            size={16}
                            color={MUTED}
                            style={{ flexShrink: 0 }}
                          />
                          <Box style={{ minWidth: 0 }}>
                            <Text fz={14} fw={700} style={{ color: INK }} truncate>
                              {req.reference}
                            </Text>
                            <Text fz={12} c="dimmed">
                              {req.scheduledDate
                                ? `Preferred date: ${req.scheduledDate}`
                                : "No preferred date"}
                              {req.notes ? ` · ${req.notes}` : ""}
                            </Text>
                          </Box>
                        </Group>
                        <Group gap="xs" wrap="nowrap">
                          <Badge
                            size="sm"
                            radius="md"
                            variant="light"
                            color={
                              req.status === "ACCEPTED"
                                ? "teal"
                                : req.status === "REJECTED"
                                  ? "red"
                                  : req.status === "CANCELLED"
                                    ? "gray"
                                    : "yellow"
                            }
                          >
                            {req.status === "ACCEPTED" && req.createdBookingId
                              ? "Booking created"
                              : BOOKING_REQUEST_STATUS_LABELS[req.status] ??
                                req.status}
                          </Badge>
                          {req.createdBookingId ? (
                            <ChevronRight size={16} color={MUTED} />
                          ) : null}
                        </Group>
                      </Group>
                    ))}
                  </Stack>
                )}
              </Card>
            )}
            <Card
              withBorder
              radius="lg"
              p="lg"
              style={{ borderColor: BORDER, boxShadow: CARD_SHADOW }}
            >
              <Group justify="space-between" align="center" mb="md">
                <SectionLabel>Bookings under this contract</SectionLabel>
                {canInitiateBooking && (
                  <InitiateBookingButton
                    contract={contract}
                    icon={PackagePlus}
                    size="xs"
                  />
                )}
                {canBookShipment && bookingWindowOpen && (
                  <Button
                    color="edr-green"
                    radius="md"
                    size="xs"
                    leftSection={<PackagePlus size={14} />}
                    onClick={() =>
                      navigate(`/contracts/${contract.id}/bookings/new`)
                    }
                  >
                    New booking
                  </Button>
                )}
              </Group>
              {canBookShipment && !bookingWindowOpen && (
                <Group gap={8} align="flex-start" wrap="nowrap" mb="md">
                  <CalendarClock
                    size={15}
                    color={MUTED}
                    style={{ flexShrink: 0, marginTop: 2 }}
                  />
                  <Text fz={13} c="dimmed">
                    {closedWindowMessage(bookingWindows)}
                  </Text>
                </Group>
              )}
              {contractBookings.length === 0 ? (
                <Stack align="center" gap={10} py="xl">
                  <Inbox size={26} color={MUTED} style={{ opacity: 0.5 }} />
                  <Text fz={13} c="dimmed" ta="center" maw={380}>
                    {canBookShipment
                      ? "No bookings yet. Use “New booking” to ship against this contract."
                      : customsPath
                        ? "No bookings yet. After your clearance documents are approved, Global Logistics creates the booking on your behalf."
                        : canUploadClearance
                          ? "No bookings yet. After the Operations team approves your clearance documents, you can create a booking here."
                          : "Bookings appear here once the contract is fully executed."}
                  </Text>
                </Stack>
              ) : (
                <Table.ScrollContainer minWidth={980}>
                  <Table
                    verticalSpacing="sm"
                    horizontalSpacing="md"
                    highlightOnHover
                    style={{ fontSize: 13 }}
                  >
                    <Table.Thead>
                      <Table.Tr>
                        <BookingsTh label="Booking" />
                        <BookingsTh label="Type" />
                        <BookingsTh label="Cargo" />
                        <BookingsTh label="Route" />
                        <BookingsTh label="Payment" />
                        <BookingsTh label="Train" />
                        <BookingsTh label="Status" />
                        <BookingsTh label="Amount" right />
                      </Table.Tr>
                    </Table.Thead>
                    <Table.Tbody>
                      {contractBookings.map((booking) => {
                        const origin =
                          booking.originYard?.label ??
                          booking.originYard?.code ??
                          "—";
                        const dest =
                          booking.destinationYard?.label ??
                          booking.destinationYard?.code ??
                          "—";
                        const amount = Number(booking.totalAmount ?? 0);
                        return (
                          <Table.Tr
                            key={booking.id}
                            style={{ cursor: "pointer" }}
                            onClick={() => navigate(`/bookings/${booking.id}`)}
                          >
                            <Table.Td>
                              <Group gap={10} wrap="nowrap">
                                <Package
                                  size={16}
                                  color={MUTED}
                                  style={{ flexShrink: 0 }}
                                />
                                <Box style={{ minWidth: 0 }}>
                                  <Text
                                    fz={13.5}
                                    fw={700}
                                    style={{ color: INK }}
                                    truncate
                                  >
                                    {booking.reference}
                                  </Text>
                                  <Text fz={11.5} c="dimmed">
                                    {booking.freightType === "BULK"
                                      ? "Bulk cargo"
                                      : "Container"}
                                  </Text>
                                </Box>
                              </Group>
                            </Table.Td>
                            <Table.Td>
                              <BookingTypeBadge booking={booking} />
                            </Table.Td>
                            <Table.Td>
                              <CargoModeCell booking={booking} />
                            </Table.Td>
                            <Table.Td>
                              <Text fz={13} fw={600} style={{ color: INK }}>
                                {origin} → {dest}
                              </Text>
                              {booking.scheduledDate && (
                                <Text fz={11.5} c="dimmed">
                                  {new Date(
                                    booking.scheduledDate,
                                  ).toLocaleDateString()}
                                </Text>
                              )}
                            </Table.Td>
                            <Table.Td>
                              <PaymentBadge status={booking.paymentStatus} />
                            </Table.Td>
                            <Table.Td>
                              <SchedulingCell booking={booking} />
                            </Table.Td>
                            <Table.Td>
                              <BookingStatusBadge status={booking.status} />
                            </Table.Td>
                            <Table.Td style={{ textAlign: "right" }}>
                              <Text
                                fz={13.5}
                                fw={700}
                                style={{
                                  color: amount > 0 ? INK : "#94A3B8",
                                  whiteSpace: "nowrap",
                                }}
                              >
                                {amount > 0
                                  ? `ETB ${amount.toLocaleString()}`
                                  : "—"}
                              </Text>
                            </Table.Td>
                          </Table.Tr>
                        );
                      })}
                    </Table.Tbody>
                  </Table>
                </Table.ScrollContainer>
              )}
            </Card>
          </Tabs.Panel>
        </Tabs>
      </Stack>
      {viewer}

      <Modal
        opened={clearanceOpen}
        onClose={clearanceModal.close}
        title={
          <Text fw={700} fz={16}>
            {isIntercity ? "Intercity documents" : "Clearance documents"}
          </Text>
        }
        size="xl"
        radius="md"
        centered
        overlayProps={{ blur: 2, backgroundOpacity: 0.55 }}
      >
        <ContractClearancePanel
          contractId={contract.id}
          tradeDirection={contract.tradeDirection ?? "IMPORT"}
          bare
        />
      </Modal>
    </Box>
  );
}

// Subtle card elevation shared across the detail page sections.
const CARD_SHADOW = "0 1px 2px rgba(16,24,40,0.04)";

// Accent hues matching the contract-ui StatCard rail palette.
const KEY_FACT_ACCENT: Record<string, string> = {
  "edr-green": GREEN,
  violet: "#6A40B8",
  orange: "#C77F09",
};

// Per-section accent + icon + description for the Documents tab groups.
const DOC_GROUP_ACCENT: Record<string, string> = {
  clearance: "#C77F09",
  businessLicense: "#0A6F4D",
  profile: "#2B6CB0",
  other: "#64748B",
};
const DOC_GROUP_ICON: Record<string, LucideIcon> = {
  clearance: Upload,
  businessLicense: FileBadge,
  profile: FileText,
  other: FileText,
};
const DOC_GROUP_DESC: Record<string, string> = {
  profile:
    "Identity and onboarding documents attached from your company profile.",
  businessLicense: "Business and trade licences on file for this company.",
  clearance:
    "Documents uploaded for the customs clearance review of this contract.",
  other: "Additional files attached to this contract.",
};

/**
 * A pill-style detail tab matching the backoffice booking-requests tabs: an
 * icon, a label, and an always-visible count badge (shows 0 when empty).
 */
function DetailTab({
  value,
  active,
  icon,
  label,
  count,
}: {
  value: string;
  active: boolean;
  icon: React.ReactNode;
  label: string;
  count?: number;
}) {
  return (
    <Tabs.Tab
      value={value}
      leftSection={icon}
      rightSection={
        count !== undefined ? (
          <Badge
            size="sm"
            radius="sm"
            variant={active ? "white" : "light"}
            color={active ? "edr-green" : "gray"}
            styles={
              active
                ? {
                    root: {
                      background: "rgba(255,255,255,0.92)",
                      color: "#15805F",
                    },
                  }
                : undefined
            }
          >
            {count}
          </Badge>
        ) : undefined
      }
      styles={{
        tab: {
          borderRadius: 11,
          padding: "9px 16px",
          fontWeight: 600,
        },
      }}
    >
      {label}
    </Tabs.Tab>
  );
}

/** A small uppercase eyebrow used as a section heading. */
function SectionLabel({
  children,
  mb,
}: {
  children: React.ReactNode;
  mb?: number | string;
}) {
  return (
    <Text
      fz={11}
      fw={700}
      tt="uppercase"
      c="dimmed"
      mb={mb}
      style={{ letterSpacing: "0.06em" }}
    >
      {children}
    </Text>
  );
}

/** Column header for the bookings table — mirrors the /bookings list styling. */
function BookingsTh({ label, right }: { label: string; right?: boolean }) {
  return (
    <Table.Th style={{ textAlign: right ? "right" : "left" }}>
      <Text
        fz={11}
        fw={700}
        tt="uppercase"
        c="dimmed"
        style={{ letterSpacing: "0.06em", whiteSpace: "nowrap" }}
      >
        {label}
      </Text>
    </Table.Th>
  );
}

/**
 * Unit noun for a capacity line: "containers" for CONTAINER freight, else the
 * bulk cargo's unit of measure ("tons" for PER_TON, "items" for PER_ITEM).
 */
function capacityUnitLabel(
  contract: Freight.IContract,
  line: Freight.ContractCapacityLine,
): string {
  if (contract.freightType === "CONTAINER") return "containers";
  const scope =
    (contract.cargoScope ?? []).find(
      (s) => s.cargoTypeId === line.cargoTypeId,
    ) ?? (contract.cargoScope ?? [])[0];
  return scope?.cargoType?.unitOfMeasure === "PER_ITEM" ? "items" : "tons";
}

/**
 * One document row in the Documents tab: the file's kind (passport, business
 * license, contract, …) derived from its `code` as the primary label, the
 * stored filename and size as secondary text, and view / download actions that
 * stream through the API by file id.
 */
/** Extension → a small colored type chip (PDF red, image green, etc.). */
function fileTypeChip(name: string, mimeType?: string | null): {
  ext: string;
  color: string;
} {
  const dot = name.lastIndexOf(".");
  let ext = dot >= 0 ? name.slice(dot + 1).toUpperCase() : "";
  if (!ext && mimeType) ext = mimeType.split("/")[1]?.toUpperCase() ?? "FILE";
  if (!ext) ext = "FILE";
  const color =
    ext === "PDF"
      ? "#D64545"
      : ["PNG", "JPG", "JPEG", "GIF", "WEBP", "SVG"].includes(ext)
        ? "#2F9E6E"
        : ["DOC", "DOCX"].includes(ext)
          ? "#2B6CB0"
          : ["XLS", "XLSX", "CSV"].includes(ext)
            ? "#2F855A"
            : ["MP4", "WEBM", "MOV"].includes(ext)
              ? "#7A40C8"
              : "#6B7C8E";
  return { ext: ext.slice(0, 4), color };
}

function DocFileRow({
  file,
  onView,
}: {
  file: ContractFile;
  onView: (f: ViewableFile) => void;
}) {
  const kind =
    clearanceWorkflowFileLabel(file.code) ?? labelForDocCode(file.code);
  const { ext, color } = fileTypeChip(file.name, file.mimeType);
  const viewable = isViewable({
    name: file.name,
    url: "",
    mimeType: file.mimeType,
  });
  return (
    <Group
      justify="space-between"
      wrap="nowrap"
      p="sm"
      style={{
        borderRadius: 14,
        border: `1px solid ${BORDER}`,
        background: "#fff",
        transition: "border-color 120ms ease, box-shadow 120ms ease",
      }}
      className="hover:border-edr-green-3 hover:shadow-sm"
    >
      <Group gap={12} wrap="nowrap" style={{ minWidth: 0 }}>
        <Box
          style={{
            width: 40,
            height: 40,
            flexShrink: 0,
            borderRadius: 10,
            display: "flex",
            flexDirection: "column",
            alignItems: "center",
            justifyContent: "center",
            background: `${color}14`,
            color,
          }}
        >
          <FileText size={16} />
          <Text fz={8} fw={800} mt={1} style={{ letterSpacing: "0.04em" }}>
            {ext}
          </Text>
        </Box>
        <Box style={{ minWidth: 0 }}>
          <Text fz={14} fw={600} style={{ color: INK }} truncate>
            {kind}
          </Text>
          <Text fz={12} c="dimmed" truncate>
            {file.name}
            {file.size ? ` · ${(file.size / 1024).toFixed(0)} KB` : ""}
          </Text>
        </Box>
      </Group>
      <Group gap={8} wrap="nowrap">
        {viewable && (
          <Button
            variant="light"
            color="edr-green"
            size="xs"
            radius="md"
            leftSection={<Eye size={14} />}
            onClick={() =>
              void fetchViewableFile(file.id, file.name).then(onView)
            }
          >
            View
          </Button>
        )}
        <Button
          component="button"
          type="button"
          onClick={() => void downloadStoredFile(file.id, file.name)}
          variant="default"
          size="xs"
          radius="md"
          leftSection={<Download size={14} />}
        >
          Download
        </Button>
      </Group>
    </Group>
  );
}

/**
 * One fact inside the unified key-facts card: a soft accent-tinted icon chip,
 * an uppercase label, and the value. Hairline dividers between cells make the
 * row read as a single card rather than five tiles.
 */
function FactCell({
  icon: Icon,
  label,
  value,
  color = "edr-green",
}: {
  icon: LucideIcon;
  label: string;
  value: React.ReactNode;
  color?: string;
}) {
  const accent = KEY_FACT_ACCENT[color] ?? GREEN;
  return (
    <Group
      gap={12}
      align="center"
      wrap="nowrap"
      p="lg"
      style={{
        minWidth: 0,
        borderRight: `1px solid rgba(16,24,40,0.06)`,
        borderBottom: `1px solid rgba(16,24,40,0.06)`,
      }}
    >
      <Box
        style={{
          width: 40,
          height: 40,
          flexShrink: 0,
          borderRadius: 12,
          display: "flex",
          alignItems: "center",
          justifyContent: "center",
          color: accent,
          background: `${accent}14`,
        }}
      >
        <Icon size={19} strokeWidth={2} />
      </Box>
      <Box style={{ minWidth: 0 }}>
        <Text
          fz={10.5}
          fw={700}
          tt="uppercase"
          c="dimmed"
          style={{ letterSpacing: "0.06em" }}
        >
          {label}
        </Text>
        <Text
          fz={16}
          fw={800}
          lh={1.2}
          mt={3}
          truncate
          style={{ color: INK, letterSpacing: "-0.01em" }}
        >
          {value}
        </Text>
      </Box>
    </Group>
  );
}

/**
 * Post-offload final invoice from GL Djibouti (export): shows the due amount +
 * invoice document; the customer pays offline and attaches the payment slip
 * here, then GL confirms and the badge flips to PAID.
 */
function FinalInvoiceDueCard({
  invoice,
  bookingId,
  onView,
  onChanged,
}: {
  invoice: NonNullable<Freight.ContractClearanceView["finalInvoice"]>;
  bookingId: string;
  onView: (file: { name: string; url: string }) => void;
  onChanged: () => void;
}) {
  const [slip, setSlip] = useState<File | null>(null);
  const [uploading, setUploading] = useState(false);
  const paid = invoice.status === "PAID";

  return (
    <Paper
      withBorder
      radius="lg"
      p="lg"
      style={{
        borderColor: paid ? "#CDEBDD" : "#F2D9A6",
        background: paid ? "#F6FBF8" : "#FFFBF2",
        position: "relative",
        overflow: "hidden",
      }}
    >
      <Box
        style={{
          position: "absolute",
          left: 0,
          top: 0,
          bottom: 0,
          width: 3,
          background: paid ? GREEN : "#E3A93C",
        }}
      />
      <Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
        <div>
          <Group gap={8} align="center">
            <FileBadge size={16} color={paid ? GREEN : "#B07C1F"} />
            <Text fw={700} fz={15} c={INK}>
              {paid ? "Final invoice paid" : "Final invoice due"} —{" "}
              {invoice.invoiceNumber}
            </Text>
            <Badge color={paid ? "edr-green" : "yellow"} variant="light" radius="sm">
              {invoiceStatusLabel(invoice.status)}
            </Badge>
          </Group>
          <Text fz={20} fw={800} mt={6} c={INK}>
            {invoice.totalAmount.toLocaleString()} {invoice.currency}
          </Text>
          {invoice.description ? (
            <Text fz={13} c="dimmed" mt={2}>
              {invoice.description}
            </Text>
          ) : null}
          {!paid ? (
            <Text fz={13} c="#9A6B1F" mt={6}>
              Pay the amount above and attach your payment slip — Global
              Logistics will confirm the payment.
            </Text>
          ) : null}
        </div>

        <Stack gap="xs" miw={260}>
          {invoice.invoiceFile ? (
            <Button
              variant="default"
              radius="md"
              size="sm"
              leftSection={<Eye size={15} />}
              onClick={() =>
                onView({
                  name: invoice.invoiceFile!.name,
                  url: invoice.invoiceFile!.url,
                })
              }
            >
              View invoice
            </Button>
          ) : null}
          {invoice.slipFile ? (
            <Button
              variant="default"
              radius="md"
              size="sm"
              leftSection={<Eye size={15} />}
              onClick={() =>
                onView({
                  name: invoice.slipFile!.name,
                  url: invoice.slipFile!.url,
                })
              }
            >
              View payment slip
            </Button>
          ) : null}
          {!paid ? (
            <>
              <FileInput
                placeholder={
                  invoice.slipFile ? "Replace payment slip" : "Attach payment slip"
                }
                value={slip}
                onChange={setSlip}
                size="sm"
                radius="md"
              />
              <Button
                color="edr-green"
                radius="md"
                size="sm"
                loading={uploading}
                disabled={!slip}
                leftSection={<Upload size={15} />}
                onClick={async () => {
                  if (!slip) return;
                  setUploading(true);
                  try {
                    await contractsService.uploadFinalInvoiceSlip(bookingId, slip);
                    setSlip(null);
                    toast.success("Payment slip attached");
                    onChanged();
                  } catch (e) {
                    toast.error(
                      e instanceof Error ? e.message : "Upload failed",
                    );
                  } finally {
                    setUploading(false);
                  }
                }}
              >
                {invoice.slipFile ? "Replace slip" : "Submit payment slip"}
              </Button>
            </>
          ) : null}
        </Stack>
      </Group>
    </Paper>
  );
}

const CUSTOMS_RISK_COLOR: Record<string, string> = {
  GREEN: "green",
  YELLOW: "yellow",
  RED: "red",
};

/**
 * Post-arrival additional duty/tax round (import): GL advises an extra amount
 * with a notice; the customer pays offline and attaches another slip here.
 */
function SecondDutyDueCard({
  duty,
  bookingId,
  onView,
  onChanged,
}: {
  duty: NonNullable<Freight.ContractClearanceView["secondDuty"]>;
  bookingId: string;
  onView: (file: { name: string; url: string }) => void;
  onChanged: () => void;
}) {
  const [slip, setSlip] = useState<File | null>(null);
  const [uploading, setUploading] = useState(false);
  const paid = duty.paid;

  return (
    <Paper
      withBorder
      radius="lg"
      p="lg"
      style={{
        borderColor: paid ? "#CDEBDD" : "#F2D9A6",
        background: paid ? "#F6FBF8" : "#FFFBF2",
        position: "relative",
        overflow: "hidden",
      }}
    >
      <Box
        style={{
          position: "absolute",
          left: 0,
          top: 0,
          bottom: 0,
          width: 3,
          background: paid ? GREEN : "#E3A93C",
        }}
      />
      <Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
        <div>
          <Group gap={8} align="center">
            <FileBadge size={16} color={paid ? GREEN : "#B07C1F"} />
            <Text fw={700} fz={15} c={INK}>
              {paid ? "Additional duty & tax paid" : "Additional duty & tax due"}
            </Text>
            <Badge color={paid ? "edr-green" : "yellow"} variant="light" radius="sm">
              {paid ? "PAID" : "DUE"}
            </Badge>
          </Group>
          <Text fz={20} fw={800} mt={6} c={INK}>
            {(duty.amount ?? 0).toLocaleString()} {duty.currency ?? ""}
          </Text>
          {duty.declarationSerial ? (
            <Text fz={13} c="dimmed" mt={2}>
              Payment code: {duty.declarationSerial}
            </Text>
          ) : null}
          {!paid ? (
            <Text fz={13} c="#9A6B1F" mt={6}>
              Customs advised additional duty/tax after arrival. Pay the amount
              above and attach your payment slip.
            </Text>
          ) : null}
        </div>

        <Stack gap="xs" miw={260}>
          {duty.noticeFile ? (
            <Button
              variant="default"
              radius="md"
              size="sm"
              leftSection={<Eye size={15} />}
              onClick={() =>
                onView({ name: duty.noticeFile!.name, url: duty.noticeFile!.url })
              }
            >
              View duty notice
            </Button>
          ) : null}
          {duty.slipFile ? (
            <Button
              variant="default"
              radius="md"
              size="sm"
              leftSection={<Eye size={15} />}
              onClick={() =>
                onView({ name: duty.slipFile!.name, url: duty.slipFile!.url })
              }
            >
              View payment slip
            </Button>
          ) : null}
          {!paid ? (
            <>
              <FileInput
                placeholder={duty.slipFile ? "Replace payment slip" : "Attach payment slip"}
                value={slip}
                onChange={setSlip}
                size="sm"
                radius="md"
              />
              <Button
                color="edr-green"
                radius="md"
                size="sm"
                loading={uploading}
                disabled={!slip}
                leftSection={<Upload size={15} />}
                onClick={async () => {
                  if (!slip) return;
                  setUploading(true);
                  try {
                    await contractsService.uploadSecondDutySlip(bookingId, slip);
                    setSlip(null);
                    toast.success("Payment slip attached");
                    onChanged();
                  } catch (e) {
                    toast.error(e instanceof Error ? e.message : "Upload failed");
                  } finally {
                    setUploading(false);
                  }
                }}
              >
                {duty.slipFile ? "Replace slip" : "Submit payment slip"}
              </Button>
            </>
          ) : null}
        </Stack>
      </Group>
    </Paper>
  );
}
