import { memo, useCallback, useMemo, useState } from "react";
import { useNavigate, useParams } from "react-router-dom";
import {
  Accordion,
  Alert,
  Badge,
  Box,
  Button,
  Group,
  Loader,
  Paper,
  Stack,
  Tabs,
  Text,
  ThemeIcon,
  Title,
  Tooltip,
} from "@mantine/core";
import {
  AlertTriangle,
  ArrowLeft,
  ArrowLeftRight,
  CalendarDays,
  CheckCircle2,
  ClipboardCheck,
  Clock,
  FileSignature,
  Hash,
  Hourglass,
  Layers,
  Package,
  PlayCircle,
  RefreshCw,
  Ruler,
  TrainFront,
  Trophy,
  Weight,
  XCircle,
} from "lucide-react";

import { CountdownTimer, DataTable, type ColumnDef } from "@edr/ui-common";

import { KpiStrip, PageContainer } from "@/components/page";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import Breadcrumbs from "@/components/ui/Breadcrumbs";
import AdjustConsistModal from "@/components/trainScheduling/AdjustConsistModal";
import { TrainCompositionDiagram } from "@/components/trainScheduling/TrainCompositionDiagram";
import {
  TrainConsistView,
  CompositionBookingTabs,
} from "@/components/trainScheduling/compositionEditor";
import {
  BookingPipeline,
  HeroChip,
  totalBookingCount,
  WindowPhasePill,
  WindowStatusPill,
} from "@/components/trainScheduling/batchVisuals";
import { RouteCorridor } from "@/components/trainScheduling/scheduleVisuals";
import { PriorityTrackingTab } from "@/components/trainScheduling/PriorityTrackingTab";
import { useBookingWindowSocket } from "@/features/bookingWindows/useBookingWindowSocket";
import { BookingsManager } from "./BookingsManager";
import { useMutation, useQuery } from "@tanstack/react-query";
import { api } from "@/services/api";
import { useToast } from "@/hooks/use-toast";
import type {
  BatchBoardBookingDetail,
  BatchBoardBookingState,
  BatchBoardCounts,
  BatchBoardScheduleDetail,
  BookingAllocationStatus,
} from "@/types/trainScheduling";

const STATE_META: Record<
  BatchBoardBookingState,
  { label: string; color: string; icon: typeof CheckCircle2 }
> = {
  ALLOCATED: { label: "Allocated", color: "edr-green", icon: CheckCircle2 },
  SELECTED_FOR_BATCH: {
    label: "Selected for batch",
    color: "orange",
    icon: Clock,
  },
  READY: { label: "Ready for batch", color: "teal", icon: Hourglass },
  WAITING: { label: "Paid · waiting", color: "blue", icon: Hourglass },
  PENDING_CONTRACT: {
    label: "Pending contract",
    color: "gray",
    icon: Hourglass,
  },
  EXPIRED: { label: "Expired", color: "red", icon: XCircle },
};

const ALLOC_META: Record<
  BookingAllocationStatus,
  { label: string; color: string }
> = {
  ASSIGNED: { label: "Wagons assigned", color: "edr-green" },
  NOT_ATTEMPTED: { label: "Not allocated", color: "gray" },
  DEFERRED: { label: "Deferred", color: "orange" },
  FAILED: { label: "Allocation failed", color: "red" },
};

const fmtTons = (n: number) =>
  `${n.toLocaleString(undefined, { maximumFractionDigits: 1 })} t`;

const fmtMeters = (n: number) =>
  `${n.toLocaleString(undefined, { maximumFractionDigits: 1 })} m`;

const fmtDateTime = (iso: string | null) =>
  iso
    ? new Intl.DateTimeFormat("en-GB", {
      day: "2-digit",
      month: "short",
      hour: "2-digit",
      minute: "2-digit",
      hour12: false,
      timeZone: "Africa/Addis_Ababa",
    }).format(new Date(iso))
    : "—";

const eatDayFmt = new Intl.DateTimeFormat("en-CA", {
  timeZone: "Africa/Addis_Ababa",
  year: "numeric",
  month: "2-digit",
  day: "2-digit",
});

/** "11:00 EAT" if the timestamp falls on today (EAT), else "05 Jun, 11:00 EAT". */
const fmtPhaseTime = (iso: string) => {
  const date = new Date(iso);
  const time = new Intl.DateTimeFormat("en-GB", {
    hour: "2-digit",
    minute: "2-digit",
    hour12: false,
    timeZone: "Africa/Addis_Ababa",
  }).format(date);
  if (eatDayFmt.format(date) === eatDayFmt.format(new Date())) {
    return `${time} EAT`;
  }
  const day = new Intl.DateTimeFormat("en-GB", {
    day: "2-digit",
    month: "short",
    timeZone: "Africa/Addis_Ababa",
  }).format(date);
  return `${day}, ${time} EAT`;
};

/** Countdown label for the current booking-cycle phase, e.g. "Closes 11:00 EAT". */
function phaseCountdown(data: BatchBoardScheduleDetail): string | null {
  switch (data.windowPhase) {
    case "PRE_WINDOW":
      return data.windowOpensAt
        ? `Opens ${fmtPhaseTime(data.windowOpensAt)}`
        : null;
    case "OPEN":
      return data.windowClosesAt
        ? `Closes ${fmtPhaseTime(data.windowClosesAt)}`
        : null;
    case "DOC_REVIEW":
      return data.docReviewEndsAt
        ? `Doc review ends ${fmtPhaseTime(data.docReviewEndsAt)}`
        : null;
    case "PAYMENT":
      return data.paymentPhaseEndsAt
        ? `Payment ends ${fmtPhaseTime(data.paymentPhaseEndsAt)}`
        : null;
    case "CLOSED_FOR_DAY":
      return data.windowOpensAt
        ? `Reopens ${fmtPhaseTime(data.windowOpensAt)}`
        : null;
    default:
      return null;
  }
}

const initials = (name: string) =>
  name
    .split(/\s+/)
    .filter(Boolean)
    .slice(0, 2)
    .map((w) => w[0])
    .join("")
    .toUpperCase() || "?";

function StateBadge({ state }: { state: BatchBoardBookingState }) {
  const meta = STATE_META[state];
  const Icon = meta.icon;
  return (
    <Badge
      variant="light"
      color={meta.color}
      radius="sm"
      leftSection={<Icon size={11} />}
    >
      {meta.label}
    </Badge>
  );
}

function AllocationBadge({
  status,
  issue,
}: {
  status: BookingAllocationStatus;
  issue: string | null;
}) {
  const meta = ALLOC_META[status];
  const badge = (
    <Badge variant="light" color={meta.color} radius="sm">
      {meta.label}
    </Badge>
  );
  if (!issue) return badge;
  return (
    <Tooltip label={issue} multiline maw={320} withArrow>
      <Group gap={4} wrap="nowrap">
        {badge}
        <AlertTriangle size={14} color="var(--mantine-color-red-6)" />
      </Group>
    </Tooltip>
  );
}

const bookingCellMeta = {
  headerClassName: ruleEngineTable.headerCell,
  cellClassName: ruleEngineTable.bodyCell,
};

const BOOKING_COLUMNS: ColumnDef<BatchBoardBookingDetail>[] = [
  {
    id: "reference",
    header: "Reference",
    meta: bookingCellMeta,
    cell: ({ row }) => {
      const b = row.original;
      return (
        <Group gap={6} wrap="nowrap">
          <Text size="sm" fw={700} c="dark.5">
            {b.reference}
          </Text>
          {b.isGovernment ? (
            <Badge size="xs" variant="light" color="grape">
              Gov
            </Badge>
          ) : null}
          {b.consolidationPartnerRef ? (
            <Tooltip
              label={`Consolidated — shares one wagon with ${b.consolidationPartnerRef}`}
              withArrow
              multiline
              maw={260}
            >
              <Badge
                size="xs"
                variant="light"
                color="edr-green"
                radius="sm"
                leftSection={<ArrowLeftRight size={10} />}
                style={{ textTransform: "none" }}
              >
                shared wagon · {b.consolidationPartnerRef}
              </Badge>
            </Tooltip>
          ) : null}
        </Group>
      );
    },
  },
  {
    id: "customer",
    header: "Customer",
    meta: bookingCellMeta,
    cell: ({ row }) => {
      const b = row.original;
      return (
        <Group gap={8} wrap="nowrap">
          <Box
            style={{
              display: "flex",
              alignItems: "center",
              justifyContent: "center",
              width: 26,
              height: 26,
              borderRadius: 8,
              flexShrink: 0,
              background: "#FEF1D5",
              border: "1px solid #FBD171",
            }}
          >
            <Text size="10px" fw={800} style={{ color: "#B26C09" }}>
              {initials(b.company)}
            </Text>
          </Box>
          <Text size="sm" c="gray.7" truncate>
            {b.company}
          </Text>
        </Group>
      );
    },
  },
  {
    id: "contractSigned",
    header: "Contract signed",
    meta: bookingCellMeta,
    cell: ({ row }) => (
      <Text size="sm" style={{ whiteSpace: "nowrap" }}>
        {fmtDateTime(row.original.fullyExecutedAt)} EAT
      </Text>
    ),
  },
  {
    id: "selectedForBatch",
    header: "Selected for batch",
    meta: bookingCellMeta,
    cell: ({ row }) => {
      const b = row.original;
      if (!b.selectedForBatchAt) {
        return (
          <Text size="sm" c="dimmed">
            —
          </Text>
        );
      }
      return (
        <>
          <Text size="sm" style={{ whiteSpace: "nowrap" }}>
            {fmtDateTime(b.selectedForBatchAt)} EAT
          </Text>
          {b.paymentDeadline ? (
            <Text
              size="xs"
              c="orange.7"
              fw={600}
              style={{ whiteSpace: "nowrap" }}
            >
              Pay by {fmtDateTime(b.paymentDeadline)} EAT
            </Text>
          ) : null}
        </>
      );
    },
  },
  {
    id: "capacity",
    header: "Capacity",
    meta: bookingCellMeta,
    cell: ({ row }) => {
      const b = row.original;
      return (
        <Group gap={4} wrap="nowrap">
          <Badge variant="default" radius="sm" size="sm">
            {b.wagons}w
          </Badge>
          <Badge variant="default" radius="sm" size="sm">
            {fmtTons(b.weightTons)}
          </Badge>
        </Group>
      );
    },
  },
  {
    id: "state",
    header: "Batch state",
    meta: bookingCellMeta,
    cell: ({ row }) => <StateBadge state={row.original.state} />,
  },
  {
    id: "allocation",
    header: "Wagon allocation",
    meta: bookingCellMeta,
    cell: ({ row }) => (
      <AllocationBadge
        status={row.original.allocationStatus}
        issue={row.original.allocationIssue}
      />
    ),
  },
];

// Memoized: the page re-renders on unrelated state (tab switch, composition
// booking selection, background-fetch flags) while the bookings arrays keep
// their identity (useMemo + React Query structural sharing) — skip re-rendering
// the whole table in those cases.
const BookingTable = memo(function BookingTable({
  bookings,
}: {
  bookings: BatchBoardBookingDetail[];
}) {
  return (
    <DataTable
      columns={BOOKING_COLUMNS}
      data={bookings}
      status="success"
      emptyMessage="No bookings in this batch window."
      containerClassName="overflow-x-auto rounded-lg border border-edr-border"
    />
  );
});

function WindowCountChips({ counts }: { counts: BatchBoardCounts }) {
  const chips: Array<{ value: number; color: string; label: string }> = [
    { value: counts.allocated, color: "edr-green", label: "allocated" },
    { value: counts.selectedForBatch, color: "orange", label: "selected" },
    { value: counts.ready, color: "teal", label: "ready" },
    { value: counts.waiting, color: "blue", label: "waiting" },
    { value: counts.expired, color: "red", label: "expired" },
  ].filter((c) => c.value > 0);

  return (
    <Group gap={5} wrap="nowrap">
      {chips.map((c) => (
        <Tooltip key={c.label} label={`${c.value} ${c.label}`} withArrow>
          <Group
            gap={4}
            wrap="nowrap"
            style={{
              padding: "2px 8px",
              borderRadius: 999,
              background: `var(--mantine-color-${c.color}-0)`,
              border: `1px solid var(--mantine-color-${c.color}-2)`,
            }}
          >
            <Box
              w={6}
              h={6}
              style={{
                borderRadius: 999,
                background: `var(--mantine-color-${c.color}-6)`,
              }}
            />
            <Text size="xs" fw={700} c={`${c.color}.8`}>
              {c.value}
            </Text>
          </Group>
        </Tooltip>
      ))}
    </Group>
  );
}

/** "05 Jun 2026 · 06:00 – 09:00 EAT" → "06:00 – 09:00 EAT" (date lives in the day header). */
const EAT_TZ = "Africa/Addis_Ababa";
const dateLabelFmt = new Intl.DateTimeFormat("en-GB", {
  timeZone: EAT_TZ,
  weekday: "short",
  day: "2-digit",
  month: "short",
});
const timeFmt = new Intl.DateTimeFormat("en-GB", {
  timeZone: EAT_TZ,
  hour: "2-digit",
  minute: "2-digit",
  hour12: false,
});

interface ScheduleWindow {
  windowPhase: BatchBoardScheduleDetail["windowPhase"];
  bookingWindowStatus: string;
  windowOpensAt: string | null;
  windowClosesAt: string | null;
  docReviewEndsAt: string | null;
  paymentPhaseEndsAt: string | null;
  bookingCycleNo?: number;
}

/**
 * Deadline + label for the phase the schedule's booking window is currently in —
 * the SAME phases the customer sees on the portal: pre-window (opens) → open
 * (closes) → document review → payment. `expiredText` names the next step so a
 * lapsed deadline reads as a handover, not a bare "Expired".
 */
function windowPhaseCountdown(
  w: ScheduleWindow,
): { label: string; deadline: string; expiredText: string } | null {
  switch (w.windowPhase) {
    case "PRE_WINDOW":
      return w.windowOpensAt
        ? { label: "Booking opens in", deadline: w.windowOpensAt, expiredText: "Booking opening now…" }
        : null;
    case "OPEN":
      return w.windowClosesAt
        ? { label: "Window closes in", deadline: w.windowClosesAt, expiredText: "Document review starting…" }
        : null;
    case "DOC_REVIEW":
      return w.docReviewEndsAt
        ? { label: "Document review ends in", deadline: w.docReviewEndsAt, expiredText: "Payment starting…" }
        : null;
    case "PAYMENT":
      return w.paymentPhaseEndsAt
        ? { label: "Payment window ends in", deadline: w.paymentPhaseEndsAt, expiredText: "Payment window closing…" }
        : null;
    default:
      return null;
  }
}

/** One phase row: label + its clock time (or "—" when unset). */
function PhaseTimeRow({
  label,
  iso,
  active,
}: {
  label: string;
  iso: string | null;
  active: boolean;
}) {
  return (
    <Group justify="space-between" gap="sm" wrap="nowrap">
      <Text size="sm" fw={active ? 700 : 500} c={active ? "edr-green.7" : "dimmed"}>
        {label}
      </Text>
      <Text size="sm" fw={active ? 700 : 500} c={active ? "dark" : "dimmed"}>
        {iso ? `${timeFmt.format(new Date(iso))} EAT` : "—"}
      </Text>
    </Group>
  );
}

/**
 * The schedule's REAL booking window — the exact same window the customer sees on
 * the portal (frozen open/close from the schedule's own snapshot + the post-close
 * document-review and payment phases), with a live countdown to the current phase.
 * Replaces the old theoretical "3-hour windows across every day" projection.
 */
function ScheduleWindowPanel({ window: w }: { window: ScheduleWindow }) {
  const phase = w.windowPhase;
  const cd = windowPhaseCountdown(w);
  const open = phase === "OPEN" && w.bookingWindowStatus === "OPEN";

  const openDay = w.windowOpensAt
    ? dateLabelFmt.format(new Date(w.windowOpensAt))
    : null;

  return (
    <Paper
      withBorder
      radius="lg"
      p="md"
      mt="md"
      style={{
        borderColor: open
          ? "var(--mantine-color-edr-green-2)"
          : "var(--mantine-color-gray-2)",
        background: open ? "var(--mantine-color-edr-green-0)" : undefined,
      }}
    >
      <Group justify="space-between" wrap="nowrap" mb="sm">
        <Group gap="sm" wrap="nowrap">
          {phase ? (
            <WindowPhasePill phase={phase} cycleNo={w.bookingCycleNo} />
          ) : null}
          <WindowStatusPill status={w.bookingWindowStatus} />
        </Group>
        {openDay ? (
          <Text size="xs" c="dimmed">
            Booking day · {openDay}
          </Text>
        ) : null}
      </Group>

      {cd ? (
        <Box mb="sm">
          <CountdownTimer
            deadline={cd.deadline}
            label={cd.label}
            expiredText={cd.expiredText}
            size="md"
          />
        </Box>
      ) : null}

      <Stack gap={6}>
        <PhaseTimeRow label="Window opens" iso={w.windowOpensAt} active={phase === "PRE_WINDOW"} />
        <PhaseTimeRow label="Window closes" iso={w.windowClosesAt} active={phase === "OPEN"} />
        <PhaseTimeRow label="Document review ends" iso={w.docReviewEndsAt} active={phase === "DOC_REVIEW"} />
        <PhaseTimeRow label="Payment window ends" iso={w.paymentPhaseEndsAt} active={phase === "PAYMENT"} />
      </Stack>
    </Paper>
  );
}

/** EAT calendar date key for a window — prefers the API field, falls back to `start`. */

export default function BatchScheduleDetailPage() {
  const { scheduleId } = useParams<{ scheduleId: string }>();
  const navigate = useNavigate();
  const { toast } = useToast();
  const { data, isLoading, isFetching, refetch } = useQuery(
    api.trainScheduling.batchBoardDetail.queryOptions({
      input: { scheduleId: scheduleId ?? "" },
      enabled: Boolean(scheduleId),
      // Real-time updates come from the booking-window socket (batch-board:changed
      // + PHASE pushes invalidate this query); 60s is only a self-heal safety net
      // for a missed emit.
      refetchInterval: 60_000,
    }),
  );
  // Keep the board in sync with server-pushed window-phase transitions too
  // (invalidates the batch-board list + patches window carousels).
  useBookingWindowSocket(Boolean(scheduleId));
  const runAllocation = useMutation(
    api.trainScheduling.runAllocation.mutationOptions(),
  );
  const completeDocReview = useMutation(
    api.trainScheduling.completeDocReview.mutationOptions(),
  );

  const hasAssignedWagons = useMemo(
    () =>
      Boolean(
        data?.bookings.some((b) => b.allocationStatus === "ASSIGNED") ||
        data?.pendingContract.bookings.some(
          (b) => b.allocationStatus === "ASSIGNED",
        ),
      ),
    [data],
  );

  const [activeTab, setActiveTab] = useState<string | null>("overview");

  const scheduleDetailQuery = useQuery(
    api.trainScheduling.scheduleDetail.queryOptions({
      input: { id: scheduleId ?? "", freightType: "CONTAINER" },
      // The heavy composition graph is only rendered by the composition tab and
      // the overview diagram (which needs assigned wagons) — don't fetch it
      // until one of them can actually show something.
      enabled:
        Boolean(scheduleId) &&
        (hasAssignedWagons || activeTab === "composition"),
      // Composition data only changes through mutations, which invalidate the
      // whole train-scheduling root — no need to refetch on remounts in between.
      staleTime: 5 * 60_000,
    }),
  );

  // Every booking on this schedule: in-window + pending-contract (the two
  // buckets are disjoint). Feeds the management table.
  const allBookings = useMemo(() => {
    if (!data) return [] as BatchBoardBookingDetail[];
    return [...data.bookings, ...data.pendingContract.bookings];
  }, [data]);

  // Bookings inside the schedule's booking window — they belong to the single
  // window panel above.
  const windowBookings = data?.bookings ?? [];

  const windowCounts = useMemo(() => {
    const counts = {
      allocated: 0,
      selectedForBatch: 0,
      ready: 0,
      waiting: 0,
      expired: 0,
      pendingContract: 0,
    };
    for (const b of windowBookings) {
      if (b.state === "ALLOCATED") counts.allocated += 1;
      else if (b.state === "SELECTED_FOR_BATCH") counts.selectedForBatch += 1;
      else if (b.state === "READY") counts.ready += 1;
      else if (b.state === "WAITING") counts.waiting += 1;
      else if (b.state === "EXPIRED") counts.expired += 1;
      else counts.pendingContract += 1;
    }
    return counts;
  }, [windowBookings]);

  // Batch bookings by state for the composition side panel (payment / expired lists).
  const batchBookings = useMemo(() => {
    const all = allBookings;
    return {
      awaitingPayment: all.filter((b) => b.state === "SELECTED_FOR_BATCH"),
      expired: all.filter((b) => b.state === "EXPIRED"),
    };
  }, [allBookings]);

  const bookingsReadOnly = useMemo(
    () => ["DISPATCHED", "ARRIVED"].includes(data?.status ?? ""),
    [data?.status],
  );

  const [adjustConsistOpen, setAdjustConsistOpen] = useState(false);
  const [selectedBookingId, setSelectedBookingId] = useState<string | null>(
    null,
  );

  // Stable identity so the memoized BookingsManager isn't re-rendered by
  // unrelated page state (tab switches, composition selection, fetch flags).
  const handleBookingsChanged = useCallback(() => void refetch(), [refetch]);

  const handleCompleteDocReview = () => {
    completeDocReview
      .mutateAsync(scheduleId ?? "")
      .then(() => {
        toast({
          title: "Document review complete",
          description: "Batch is running for this route-day group",
        });
        void refetch();
      })
      .catch(() => {
        toast({
          title: "Could not complete document review",
          variant: "destructive",
        });
      });
  };

  const handleRunAllocation = () => {
    runAllocation
      .mutateAsync({ scheduleId: scheduleId ?? "" })
      .then((result) => {
        const failed = result.issues.filter(
          (i) => i.status === "FAILED",
        ).length;
        const deferred = result.deferred.length;
        toast({
          title: "Allocation run complete",
          description:
            failed || deferred
              ? `${result.assignedBookingIds.length} assigned · ${deferred} deferred · ${failed} failed`
              : `${result.assignedBookingIds.length} booking(s) assigned to wagons`,
          variant: failed ? "destructive" : "default",
        });
        void refetch();
      })
      .catch(() => {
        toast({ title: "Allocation failed", variant: "destructive" });
      });
  };

  if (isLoading || !data) {
    return (
      <PageContainer fluid>
        <Group justify="center" py="xl">
          <Loader color="edr-green" />
        </Group>
      </PageContainer>
    );
  }

  const totalBookings = totalBookingCount(data.counts);
  const countdown = phaseCountdown(data);

  return (
    <PageContainer fluid>
      <Breadcrumbs
        items={[
          { label: "Operations" },
          { label: "Batch board", href: "/dashboard/operations/batch-board" },
          {
            label:
              data.scheduleReference ??
              data.trainNumber ??
              data.routeName ??
              "Schedule",
          },
        ]}
      />

      <Tabs value={activeTab} onChange={setActiveTab}>
        <Tabs.List>
          <Tabs.Tab value="overview">Overview</Tabs.Tab>
          <Tabs.Tab
            value="priority"
            leftSection={<Trophy size={14} />}
          >
            Priority Tracking{" "}
            {allBookings.length > 0 && `(${allBookings.length})`}
          </Tabs.Tab>
          <Tabs.Tab value="composition">
            Train Composition{" "}
            {scheduleDetailQuery.data?.trainSet?.wagons &&
              scheduleDetailQuery.data.trainSet.wagons.length > 0 &&
              `(${scheduleDetailQuery.data.trainSet.wagons.length})`}
          </Tabs.Tab>
        </Tabs.List>

        <Tabs.Panel value="overview" pt="lg">
          <Stack gap="lg">
            <Group
              justify="space-between"
              align="flex-start"
              wrap="wrap"
              gap="md"
            >
              <Stack gap={9} style={{ minWidth: 0 }}>
                <Group gap="sm" wrap="wrap" align="center">
                  <Button
                    variant="subtle"
                    color="gray"
                    radius="md"
                    px="sm"
                    leftSection={<ArrowLeft size={16} />}
                    onClick={() =>
                      navigate("/dashboard/operations/batch-board")
                    }
                  >
                    Back
                  </Button>
                  <Title order={2} fw={800}>
                    {data.trainNumber ?? data.routeName ?? "Schedule"}
                  </Title>
                  {data.scheduleReference ? (
                    <HeroChip icon={<Hash size={12} />}>
                      {data.scheduleReference}
                    </HeroChip>
                  ) : null}
                  <WindowStatusPill status={data.bookingWindowStatus} />
                  {data.windowPhase ? (
                    <WindowPhasePill
                      phase={data.windowPhase}
                      cycleNo={data.bookingCycleNo}
                    />
                  ) : null}
                  <HeroChip>{data.status}</HeroChip>
                </Group>
                <RouteCorridor
                  origin={data.origin}
                  destination={data.destination}
                />
                <Group gap={6} wrap="wrap">
                  <HeroChip icon={<CalendarDays size={12} />}>
                    {data.scheduleDate
                      ? new Intl.DateTimeFormat("en-GB", {
                        weekday: "short",
                        day: "2-digit",
                        month: "short",
                        year: "numeric",
                        hour: "2-digit",
                        minute: "2-digit",
                        hour12: false,
                        timeZone: "Africa/Addis_Ababa",
                      }).format(new Date(data.scheduleDate)) + " EAT"
                      : "No date"}
                  </HeroChip>
                  {data.train ? (
                    <HeroChip icon={<TrainFront size={12} />}>
                      Train {data.train.code}
                      {data.train.trainName ? ` — ${data.train.trainName}` : ""}
                    </HeroChip>
                  ) : null}
                  {data.locomotive ? (
                    <HeroChip icon={<TrainFront size={12} />}>
                      Loco {data.locomotive.code} ·{" "}
                      {fmtTons(data.locomotive.maxPullWeightTons)} ·{" "}
                      {data.locomotive.maxTrainLengthMeters} m
                    </HeroChip>
                  ) : null}
                  {data.windowPhase ? (
                    <HeroChip icon={<Clock size={12} />}>
                      Cycle {data.bookingCycleNo}
                      {countdown ? ` · ${countdown}` : ""}
                    </HeroChip>
                  ) : null}
                </Group>
              </Stack>

              <Group gap="sm">
                <Button
                  variant="default"
                  radius="md"
                  leftSection={<RefreshCw size={16} />}
                  loading={isFetching}
                  onClick={() => void refetch()}
                >
                  Refresh
                </Button>
                {/* {data.train && ["DRAFT", "SCHEDULED"].includes(data.status) ? (
                  <Button
                    variant="light"
                    color="edr-green"
                    radius="md"
                    leftSection={<TrainFront size={16} />}
                    onClick={() => setAdjustConsistOpen(true)}
                  >
                    Adjust consist
                  </Button>
                ) : null} */}
                {data.windowPhase === "DOC_REVIEW" ? (
                  <Button
                    color="yellow"
                    radius="md"
                    leftSection={<ClipboardCheck size={16} />}
                    loading={completeDocReview.isPending}
                    onClick={handleCompleteDocReview}
                  >
                    Doc review complete — run batch
                  </Button>
                ) : null}
                <Button
                  color="edr-green"
                  radius="md"
                  leftSection={<PlayCircle size={16} />}
                  loading={runAllocation.isPending}
                  onClick={handleRunAllocation}
                >
                  Run allocation
                </Button>
                <Button
                  variant="light"
                  color="edr-green"
                  radius="md"
                  leftSection={<Layers size={16} />}
                  onClick={() =>
                    navigate(
                      `/dashboard/operations/train-scheduling-v2/${data.scheduleId}`,
                    )
                  }
                >
                  Open schedule
                </Button>
              </Group>
            </Group>

            {!data.locomotive ? (
              <Alert color="red" radius="md" icon={<AlertTriangle size={16} />}>
                No locomotive assigned — wagon allocation cannot run.
              </Alert>
            ) : null}

            <KpiStrip
              items={[
                {
                  label: "Train length",
                  value: data.capacity.maxLengthMeters
                    ? `${fmtMeters(data.capacity.allocatedLengthMeters)} / ${fmtMeters(data.capacity.maxLengthMeters)}`
                    : fmtMeters(data.capacity.allocatedLengthMeters),
                  icon: Ruler,
                },
                {
                  label: "Gross weight",
                  value: data.capacity.maxWeightTons
                    ? `${fmtTons(data.capacity.usedWeightTons)} / ${fmtTons(data.capacity.maxWeightTons)}`
                    : fmtTons(data.capacity.usedWeightTons),
                  hint: "wagon tare + cargo",
                  icon: Weight,
                },
                {
                  label: "Bookings",
                  value: totalBookings,
                  hint: `${data.counts.allocated} allocated · ${data.counts.expired} expired`,
                  icon: Package,
                },
              ]}
            />

            {/* Booking pipeline */}
            <Paper
              radius="lg"
              withBorder
              p="lg"
              mt="lg"
              style={{ borderColor: "var(--mantine-color-gray-2)" }}
            >
              <Group justify="space-between" mb="sm">
                <Group gap={8} wrap="nowrap">
                  <ThemeIcon
                    size={32}
                    radius="md"
                    variant="light"
                    color="#F2A516"
                  >
                    <Package size={16} />
                  </ThemeIcon>
                  <Text fw={700}>Booking pipeline</Text>
                </Group>
                <Text size="sm" fw={700} c="dark.4">
                  {totalBookings} booking{totalBookings === 1 ? "" : "s"}
                </Text>
              </Group>
              <BookingPipeline counts={data.counts} size={14} />
            </Paper>

            {data.allocationViolations.length ? (
              <Alert
                color="red"
                mt="lg"
                radius="lg"
                icon={<AlertTriangle size={16} />}
                title="Allocation constraints"
              >
                <Stack gap={4}>
                  {data.allocationViolations.map((v) => (
                    <Text key={v} size="sm">
                      {v}
                    </Text>
                  ))}
                </Stack>
              </Alert>
            ) : null}

            {/* Manage bookings — search, filter, remove / re-assign (bulk too) */}
            <Paper
              radius="lg"
              withBorder
              p="lg"
              mt="lg"
              style={{ borderColor: "var(--mantine-color-gray-2)" }}
            >
              <Group gap="sm" mb="md" wrap="nowrap" align="flex-start">
                <ThemeIcon
                  size={38}
                  radius="md"
                  variant="light"
                  color="#F2A516"
                >
                  <Package size={19} />
                </ThemeIcon>
                <Box>
                  <Title order={4}>Manage bookings</Title>
                  <Text size="sm" c="dimmed">
                    Search and filter every booking on this train. Remove an
                    allocated booking to free its wagons, or re-assign one that
                    is not yet allocated — individually or in bulk.
                  </Text>
                </Box>
              </Group>
              <BookingsManager
                scheduleId={scheduleId ?? ""}
                bookings={allBookings}
                onChanged={handleBookingsChanged}
                readOnly={bookingsReadOnly}
              />
            </Paper>

            {/* Batch windows */}
            <Paper
              radius="lg"
              withBorder
              p="lg"
              mt="lg"
              style={{ borderColor: "var(--mantine-color-gray-2)" }}
            >
              <Group gap="sm" mb={4} wrap="nowrap" align="flex-start">
                <ThemeIcon
                  size={38}
                  radius="md"
                  variant="light"
                  color="#F2A516"
                >
                  <Clock size={19} />
                </ThemeIcon>
                <Box>
                  <Title order={4}>Booking window (EAT)</Title>
                  <Text size="sm" c="dimmed">
                    The schedule's real booking window — the same window and
                    phase timings the customer sees on the portal. Bookings in
                    the window are listed below.
                  </Text>
                </Box>
              </Group>

              <ScheduleWindowPanel window={data} />

              {windowBookings.length ? (
                <Box mt="lg">
                  <Group justify="space-between" align="center" mb="sm">
                    <Text fw={700} size="sm">
                      Bookings in this window
                    </Text>
                    <WindowCountChips counts={windowCounts} />
                  </Group>
                  <BookingTable bookings={windowBookings} />
                </Box>
              ) : (
                <Text size="sm" c="dimmed" ta="center" py="lg">
                  No bookings in this window yet.
                </Text>
              )}

              {data.pendingContract.bookings.length ? (
                <Accordion
                  multiple
                  defaultValue={["pending-contract"]}
                  variant="separated"
                  radius="md"
                  mt="md"
                  className="bb-window-accordion"
                >
                  <Accordion.Item value="pending-contract">
                    <Accordion.Control>
                      <Group
                        justify="space-between"
                        wrap="nowrap"
                        pr="md"
                        gap="sm"
                      >
                        <Group gap="sm" wrap="nowrap">
                          <Box
                            style={{
                              display: "flex",
                              alignItems: "center",
                              justifyContent: "center",
                              width: 34,
                              height: 34,
                              borderRadius: 10,
                              flexShrink: 0,
                              background: "var(--mantine-color-gray-0)",
                              border: "1px solid var(--mantine-color-gray-2)",
                              color: "var(--mantine-color-gray-6)",
                            }}
                          >
                            <FileSignature size={16} />
                          </Box>
                          <Box>
                            <Text fw={700} size="sm">
                              Pending contract
                            </Text>
                            <Text size="xs" c="dimmed">
                              Contract not signed yet — not in any window
                            </Text>
                          </Box>
                        </Group>
                        <Badge variant="outline" color="gray" size="sm">
                          {data.pendingContract.bookings.length} booking
                          {data.pendingContract.bookings.length === 1
                            ? ""
                            : "s"}
                        </Badge>
                      </Group>
                    </Accordion.Control>
                    <Accordion.Panel>
                      <BookingTable bookings={data.pendingContract.bookings} />
                    </Accordion.Panel>
                  </Accordion.Item>
                </Accordion>
              ) : null}
            </Paper>

            {/* Train composition diagram */}
            {hasAssignedWagons && scheduleDetailQuery.data ? (
              <Box mt="lg">
                <TrainCompositionDiagram
                  locomotive={scheduleDetailQuery.data.trainSet?.locomotive}
                  wagons={scheduleDetailQuery.data.trainSet?.wagons ?? []}
                  freightType={scheduleDetailQuery.data.freightType ?? null}
                  trainNumber={scheduleDetailQuery.data.trainNumber}
                  totalLengthMeters={
                    scheduleDetailQuery.data.trainSet?.totalLengthMeters
                  }
                />
              </Box>
            ) : null}
          </Stack>
        </Tabs.Panel>

        <Tabs.Panel value="priority" pt="lg">
          <PriorityTrackingTab data={data} bookings={allBookings} />
        </Tabs.Panel>

        <Tabs.Panel value="composition" pt="lg">
          {scheduleDetailQuery.data && scheduleDetailQuery.data.trainSet ? (
            <Group align="stretch" gap="md" wrap="nowrap">
              <Box style={{ flex: 1, minWidth: 0 }}>
                <TrainConsistView
                  scheduleDetail={scheduleDetailQuery.data}
                  scheduleId={scheduleId ?? ""}
                  maxWagons={data.capacity.maxWagons ?? 53}
                  highlightBookingId={selectedBookingId}
                />
              </Box>
              <Box style={{ width: 380, flexShrink: 0, minHeight: 520 }}>
                <CompositionBookingTabs
                  scheduleDetail={scheduleDetailQuery.data}
                  scheduleId={scheduleId ?? ""}
                  awaitingPayment={batchBookings.awaitingPayment}
                  expired={batchBookings.expired}
                  selectedBookingId={selectedBookingId}
                  onSelectBooking={setSelectedBookingId}
                />
              </Box>
            </Group>
          ) : (
            <Paper
              radius="lg"
              withBorder
              py={64}
              style={{ borderColor: "var(--mantine-color-gray-2)" }}
            >
              <Group justify="center">
                <Loader color="edr-green" size="sm" />
                <Text size="sm" c="dimmed">
                  Loading train composition…
                </Text>
              </Group>
            </Paper>
          )}
        </Tabs.Panel>
      </Tabs>

      <AdjustConsistModal
        scheduleId={data.scheduleId}
        opened={adjustConsistOpen}
        onClose={() => setAdjustConsistOpen(false)}
      />
    </PageContainer>
  );
}
