import {
  Badge,
  Box,
  Button,
  Checkbox,
  Group,
  Loader,
  Paper,
  RingProgress,
  Stack,
  Tabs,
  Text,
  Textarea,
  TextInput,
  ThemeIcon,
  Title,
} from "@mantine/core";
import { isAxiosError } from "axios";
import {
  ArrowLeft,
  CalendarClock,
  CheckCircle2,
  Container as ContainerIcon,
  Eye,
  FileText,
  LayoutGrid,
  Navigation,
  Package,
  PackageCheck,
  Route as RouteIcon,
  Send,
  Train,
  Weight,
  Workflow as WorkflowIcon,
} from "lucide-react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { Link, useParams } from "react-router-dom";

import { KpiStrip, PageContainer } from "@/components/page";
import {
  autoFillPlacements,
  mergePlacementsWithSaved,
  placementsFromScheduleWagons,
  validateLocalPlacements,
} from "@/components/trainScheduling/containerPlacement.util";
import { ContainerPlacementGrid } from "@/components/trainScheduling/ContainerPlacementGrid";
import { FleetAvailabilitySummary } from "@/components/trainScheduling/FleetAvailabilitySummary";
import { ImportLoadingConfirmationPanel } from "@/components/trainScheduling/ImportLoadingConfirmationPanel";
import { RescheduleTrainDialog } from "@/components/trainScheduling/RescheduleTrainDialog";
import { ScheduleBatchPanel } from "@/components/trainScheduling/ScheduleBatchPanel";
import { ScheduleBookingsStep } from "@/components/trainScheduling/ScheduleBookingsStep";
import { ScheduleWorkspacePanel } from "@/components/trainScheduling/ScheduleWorkspacePanel";
import { FreightTypeBadge } from "@/components/trainScheduling/ScheduleStatusBadge";
import {
  RouteCorridor,
  StatusPill,
  scheduleBrand,
} from "@/components/trainScheduling/scheduleVisuals";
import {
  PreviewSummary,
  ScheduleWarningsAlert,
} from "@/components/trainScheduling/ScheduleWarningsAlert";
import { TrainCompositionDiagram } from "@/components/trainScheduling/TrainCompositionDiagram";
import { WagonPlanGrid } from "@/components/trainScheduling/WagonPlanGrid";
import { WorkflowRail, WorkflowStep } from "@/components/trainScheduling/WorkflowStep";
import { openPdfBlob } from "@/components/warehouses/pdf";
import { useMutation, useQuery } from "@tanstack/react-query";
import { api } from "@/services/api";
import { trainSchedulingService } from "@/services/trainScheduling.service";
import { useToast } from "@/hooks/use-toast";
import type {
  ContainerPlacement,
  FreightType,
  TrainSchedulePreviewResponse,
} from "@/types/trainScheduling";

const parseError = (error: unknown, fallback: string) => {
  if (isAxiosError(error)) {
    const data = error.response?.data as Record<string, unknown> | undefined;
    const message = data?.message;
    if (Array.isArray(message)) return message.join(", ");
    if (typeof message === "string") return message;
    const violations = data?.violations;
    if (Array.isArray(violations)) return violations.join(", ");
  }
  return fallback;
};

export default function TrainScheduleV2DetailPage() {
  const { scheduleId } = useParams<{ scheduleId: string }>();
  const { toast } = useToast();
  const [activeStep, setActiveStep] = useState(0);
  const [selectedBookingIds, setSelectedBookingIds] = useState<string[]>([]);
  const [forceAssign, setForceAssign] = useState(false);
  const [previewResult, setPreviewResult] = useState<TrainSchedulePreviewResponse | null>(null);
  const [containerPlacements, setContainerPlacements] = useState<ContainerPlacement[]>([]);
  const [maintenanceOpen, setMaintenanceOpen] = useState(false);
  const [gatepassSecuredAt, setGatepassSecuredAt] = useState("");
  const [gatepassReference, setGatepassReference] = useState("");
  const [gatepassFileUrl, setGatepassFileUrl] = useState("");
  const [gatepassNotes, setGatepassNotes] = useState("");
  const autoPreviewedRef = useRef(false);

  const detailQuery = useQuery(
    api.trainScheduling.scheduleDetail.queryOptions({
      input: { id: scheduleId ?? "" },
      enabled: Boolean(scheduleId),
    }),
  );
  const schedule = detailQuery.data;
  const freightType: FreightType | undefined = schedule?.freightType as FreightType | undefined;
  const isDjiboutiPort = (value?: string | null) =>
    ["DJIBOUTI", "DORALEH", "DMP", "DCT", "NAGAD"].some((token) =>
      (value ?? "").toUpperCase().includes(token),
    );
  const gatepassApplies = Boolean(
    schedule &&
      ((schedule.direction === "IMPORT" &&
        isDjiboutiPort(`${schedule.originStation?.code ?? ""} ${schedule.originStation?.label ?? ""}`)) ||
        (schedule.direction === "EXPORT" &&
          isDjiboutiPort(`${schedule.destinationStation?.code ?? ""} ${schedule.destinationStation?.label ?? ""}`))),
  );
  const gatepassQuery = useQuery({
    queryKey: ["train-scheduling", "gatepass", scheduleId],
    queryFn: () => trainSchedulingService.getImportDjiboutiOperation(scheduleId as string),
    enabled: Boolean(scheduleId && gatepassApplies),
  });
  const secureGatepass = useMutation({
    mutationFn: () =>
      trainSchedulingService.grantImportDjiboutiGatepass(scheduleId as string, {
        securedAt: gatepassSecuredAt ? new Date(gatepassSecuredAt).toISOString() : undefined,
        reference: gatepassReference.trim() || undefined,
        fileUrl: gatepassFileUrl.trim() || undefined,
        notes: gatepassNotes.trim() || undefined,
      }),
    onSuccess: () => {
      toast({ title: "Gate pass secured" });
      void gatepassQuery.refetch();
    },
    onError: (error) => {
      toast({
        title: "Gate pass failed",
        description: parseError(error, "Could not secure gate pass"),
        variant: "destructive",
      });
    },
  });

  const importLoadingQuery = useQuery(
    api.trainScheduling.importLoadingBookings.queryOptions({
      input: { id: scheduleId ?? "" },
      enabled: Boolean(scheduleId && schedule?.direction === "IMPORT"),
    }),
  );

  const eligibleFilters = useMemo(
    () =>
      schedule
        ? {
            originStationId: schedule.originStation?.id,
            destinationStationId: schedule.destinationStation?.id,
            // Only this schedule's own bookings are eligible — same rule as the auto batch.
            trainScheduleId: scheduleId,
          }
        : undefined,
    [schedule, scheduleId],
  );

  const eligibleFreightType =
    freightType === "CONTAINER" || freightType === "BULK" ? freightType : undefined;

  const eligibleQuery = useQuery(
    api.trainScheduling.eligibleBookings.queryOptions({
      input: { filters: eligibleFilters, freightType: eligibleFreightType },
      enabled: Boolean(schedule),
    }),
  );
  const preview = useMutation(api.trainScheduling.preview.mutationOptions());
  const assign = useMutation(api.trainScheduling.assignBookings.mutationOptions());
  const unassign = useMutation(api.trainScheduling.unassignBooking.mutationOptions());
  const finalize = useMutation(api.trainScheduling.finalizeSchedule.mutationOptions());
  const dispatch = useMutation(api.trainScheduling.dispatchSchedule.mutationOptions());
  const downloadMarshalling = useMutation({
    mutationFn: ({ id, direction }: { id: string; direction?: string | null }) =>
      direction === "EXPORT"
        ? trainSchedulingService.downloadExportLoadListDocument(id)
        : trainSchedulingService.downloadImportDjiboutiLoadListDocument(id),
  });

  useEffect(() => {
    const operation = gatepassQuery.data;
    if (!operation) return;
    const secured = operation.gatepassSecuredAt ?? operation.gatepassGrantedAt;
    setGatepassSecuredAt(secured ? new Date(secured).toISOString().slice(0, 16) : "");
    setGatepassReference(operation.documents?.GATE_PASS?.reference ?? "");
    setGatepassFileUrl(operation.documents?.GATE_PASS?.fileUrl ?? "");
    setGatepassNotes(operation.documents?.GATE_PASS?.notes ?? operation.notes ?? "");
  }, [gatepassQuery.data]);

  const assignedIds = useMemo(
    () => (schedule?.bookings ?? []).map((b) => b.id),
    [schedule?.bookings],
  );

  const allSelectedIds = useMemo(() => {
    const merged = new Set([...assignedIds, ...selectedBookingIds]);
    return [...merged];
  }, [assignedIds, selectedBookingIds]);

  const containerUnits = previewResult?.containerUnits ?? [];
  const containerSlots = previewResult?.containerSlotSequenceNos ?? [];
  // Container-number placement step removed — the customer enters container
  // numbers when booking, so scheduling skips straight from the wagon plan to
  // finalize. Steps: select bookings → review wagons → finalize.
  const hasContainerStep = false;

  const displayWagonPlan = useMemo(() => {
    const savedWagons = schedule?.trainSet?.wagons ?? [];
    // Map each slot to its reserved physical wagon number (from the wagon table) so the
    // plan shows real wagon ids (e.g. WGN-DEMO-001) instead of generic "Wagon #1".
    const physicalBySeq = new Map(
      savedWagons.map((w) => [w.sequenceNo, w.physicalWagonNumber ?? null]),
    );
    if (previewResult?.wagonPlan?.length) {
      return previewResult.wagonPlan.map((slot) => ({
        ...slot,
        physicalWagonNumber: physicalBySeq.get(slot.sequenceNo) ?? null,
      }));
    }
    if (savedWagons.length) return savedWagons;
    return [];
  }, [previewResult?.wagonPlan, schedule?.trainSet?.wagons]);

  const runPreview = useCallback(
    async (options?: { silent?: boolean; advanceStep?: boolean }) => {
      if (!schedule || !scheduleId) return null;
      if (!allSelectedIds.length) {
        if (!options?.silent) {
          toast({ title: "Select at least one booking", variant: "destructive" });
        }
        return null;
      }
      const originStationId = schedule.originStation?.id;
      const destinationStationId = schedule.destinationStation?.id;
      if (!originStationId || !destinationStationId) {
        if (!options?.silent) {
          toast({ title: "Schedule missing origin or destination", variant: "destructive" });
        }
        return null;
      }
      try {
        const result = await preview.mutateAsync({
          freightType,
          payload: {
            bookingIds: allSelectedIds,
            scheduleDate: schedule.scheduledDepartureDate,
            originStationId,
            destinationStationId,
            targetScheduleId: scheduleId,
          },
        });
        setPreviewResult(result);
        if (result.containerUnits?.length && result.containerSlotSequenceNos?.length) {
          const autoFilled = autoFillPlacements(
            result.containerUnits,
            result.containerSlotSequenceNos,
          );
          const saved = schedule.trainSet?.wagons
            ? placementsFromScheduleWagons(schedule.trainSet.wagons)
            : [];
          setContainerPlacements(
            saved.length ? mergePlacementsWithSaved(autoFilled, saved) : autoFilled,
          );
        } else {
          setContainerPlacements([]);
        }
        if (!options?.silent) {
          if (!result.valid) {
            toast({ title: "Preview has violations", variant: "destructive" });
          } else if (options?.advanceStep !== false) {
            setActiveStep(1);
          }
        }
        return result;
      } catch (err) {
        if (!options?.silent) {
          toast({
            title: "Preview failed",
            description: parseError(err, "Could not preview"),
            variant: "destructive",
          });
        }
        return null;
      }
    },
    [allSelectedIds, freightType, preview, schedule, scheduleId, toast],
  );

  useEffect(() => {
    if (!schedule || !scheduleId || autoPreviewedRef.current) return;
    if (!assignedIds.length) return;
    autoPreviewedRef.current = true;
    void runPreview({ silent: true, advanceStep: false });
  }, [assignedIds.length, runPreview, schedule, scheduleId]);

  const savedPlacementsFromSchedule = useMemo(
    () =>
      schedule?.trainSet?.wagons
        ? placementsFromScheduleWagons(schedule.trainSet.wagons)
        : [],
    [schedule?.trainSet?.wagons],
  );

  useEffect(() => {
    if (!containerUnits.length || !containerSlots.length) return;

    setContainerPlacements((current) => {
      if (current.length && current.some((p) => p.containerNumber?.trim())) {
        return current;
      }
      const autoFilled = autoFillPlacements(containerUnits, containerSlots);
      if (savedPlacementsFromSchedule.length) {
        return mergePlacementsWithSaved(autoFilled, savedPlacementsFromSchedule);
      }
      if (current.length) return current;
      return autoFilled;
    });
  }, [containerUnits, containerSlots, savedPlacementsFromSchedule]);

  if (detailQuery.isLoading) {
    return (
      <PageContainer>
        <Group justify="center" py="xl">
          <Loader size="sm" />
        </Group>
      </PageContainer>
    );
  }

  if (!schedule || !scheduleId) {
    return (
      <PageContainer>
        <Text c="dimmed" py="xl">
          Schedule not found
        </Text>
      </PageContainer>
    );
  }

  // All locomotives pulling the train (≥2), falling back to the legacy single loco.
  const locomotives =
    schedule.trainSet?.locomotives && schedule.trainSet.locomotives.length > 0
      ? schedule.trainSet.locomotives
      : schedule.trainSet?.locomotive
        ? [schedule.trainSet.locomotive]
        : [];

  const canEditBookings = ["DRAFT", "SCHEDULED"].includes(schedule.status);
  const canFinalize = schedule.status === "DRAFT" && (schedule.bookings?.length ?? 0) > 0;
  const canDispatch = schedule.status === "SCHEDULED";
  const finalizeStep = hasContainerStep ? 3 : 2;
  const canModifyBookings = canEditBookings && !["DISPATCHED", "ARRIVED"].includes(schedule.status);
  const canPrintMarshalling =
    (schedule.direction === "IMPORT" || schedule.direction === "EXPORT") &&
    ["DISPATCHED", "ARRIVED"].includes(schedule.status);

  const openMarshallingDocument = async (options?: {
    title?: string;
    successDescription?: string;
    errorTitle?: string;
  }) => {
    const pdfWindow = window.open("", "_blank");
    try {
      const blob = await downloadMarshalling.mutateAsync({
        id: scheduleId,
        direction: schedule.direction,
      });
      const prefix = schedule.direction === "EXPORT" ? "export-marshalling" : "import-marshalling";
      const filename = `${prefix}-${schedule.trainNumber ?? scheduleId}.pdf`;
      const opened = openPdfBlob(blob, filename, pdfWindow);
      toast({
        title: options?.title ?? "Marshalling document ready",
        description:
          options?.successDescription ??
          (opened
            ? "The PDF opened in a browser tab for printing or saving."
            : "The browser blocked the preview tab, so the PDF was downloaded."),
      });
    } catch (error) {
      pdfWindow?.close();
      toast({
        title: options?.errorTitle ?? "Could not open marshalling document",
        description: parseError(error, "Make sure the train has wagon allocations, then try again."),
        variant: "destructive",
      });
    }
  };

  const handleAssign = async () => {
    if (!allSelectedIds.length) return;

    if (hasContainerStep) {
      const issues = validateLocalPlacements(containerUnits, containerPlacements);
      if (issues.length) {
        toast({
          title: "Complete container assignments",
          description: issues.join(", "),
          variant: "destructive",
        });
        return;
      }
    }

    try {
      const result = await assign.mutateAsync({
        id: scheduleId,
        freightType,
        payload: {
          bookingIds: allSelectedIds,
          forceAssign,
          containerPlacements: hasContainerStep ? containerPlacements : undefined,
        },
      });
      toast({ title: "Bookings assigned — wagons auto-pinned" });
      const refreshed = await detailQuery.refetch();
      const saved = refreshed.data?.trainSet?.wagons
        ? placementsFromScheduleWagons(refreshed.data.trainSet.wagons)
        : [];
      if (saved.length) {
        setContainerPlacements(saved);
      }
      autoPreviewedRef.current = false;
      setActiveStep(finalizeStep);
      if (result.deferredBookings?.length) {
        toast({
          title: "Partial assignment",
          description: `${result.deferredBookings.length} booking(s) deferred to next train`,
        });
      }
    } catch (err) {
      toast({
        title: "Assign failed",
        description: parseError(err, "Could not assign"),
        variant: "destructive",
      });
    }
  };

  const handleUnassign = async (bookingId: string) => {
    try {
      await unassign.mutateAsync({ id: scheduleId, bookingId });
      toast({ title: "Booking unassigned" });
      setSelectedBookingIds((ids) => ids.filter((id) => id !== bookingId));
      setPreviewResult(null);
      autoPreviewedRef.current = false;
    } catch (err) {
      toast({
        title: "Unassign failed",
        description: parseError(err, "Could not unassign"),
        variant: "destructive",
      });
    }
  };

  const containerComplete =
    hasContainerStep &&
    containerUnits.length > 0 &&
    validateLocalPlacements(containerUnits, containerPlacements).length === 0;
  const finalizeComplete = ["SCHEDULED", "DISPATCHED", "ARRIVED"].includes(
    schedule.status,
  );

  const stepsMeta = [
    {
      key: "bookings",
      icon: Package,
      title: "Bookings",
      subtitle: "Select cargo & preview the plan",
      complete: Boolean(previewResult) || assignedIds.length > 0,
    },
    {
      key: "wagon",
      icon: LayoutGrid,
      title: "Wagon plan",
      subtitle: "Review generated allocations",
      complete: displayWagonPlan.length > 0,
    },
    ...(hasContainerStep
      ? [
          {
            key: "container",
            icon: ContainerIcon,
            title: "Containers",
            subtitle: "Map units to wagon slots",
            complete: containerComplete,
          },
        ]
      : []),
    {
      key: "finalize",
      icon: CheckCircle2,
      title: "Finalize",
      subtitle: "Lock the plan & dispatch",
      complete: finalizeComplete,
    },
  ];
  const completedCount = stepsMeta.filter((s) => s.complete).length;
  const progressPct = Math.round((completedCount / stepsMeta.length) * 100);
  const toggleStep = (i: number) => setActiveStep((cur) => (cur === i ? -1 : i));

  const renderStepRightSlot = (key: string) => {
    if (key === "bookings") {
      if (previewResult) {
        return (
          <Badge
            variant="light"
            color={previewResult.valid ? "edr-green" : "red"}
            radius="sm"
          >
            {previewResult.valid ? "Plan valid" : "Has issues"}
          </Badge>
        );
      }
      return allSelectedIds.length ? (
        <Badge variant="light" color="edr-green" radius="sm">
          {allSelectedIds.length} selected
        </Badge>
      ) : null;
    }
    if (key === "wagon" && displayWagonPlan.length) {
      return (
        <Badge variant="light" color="edr-green" radius="sm">
          {displayWagonPlan.length} wagons
        </Badge>
      );
    }
    if (key === "container" && containerUnits.length) {
      return (
        <Badge
          variant="light"
          color={containerComplete ? "edr-green" : "yellow"}
          radius="sm"
        >
          {containerUnits.length} units
        </Badge>
      );
    }
    if (key === "finalize") {
      return <StatusPill status={schedule.status} />;
    }
    return null;
  };

  const renderStepBody = (key: string) => {
    if (key === "bookings") {
      return (
        <Stack gap="md">
          <ScheduleBookingsStep
            assignedBookings={(schedule.bookings ?? []).map((b) => ({
              id: b.id,
              reference: b.reference ?? b.id.slice(0, 8),
              weightTons: b.weightTons,
            }))}
            eligibleItems={eligibleQuery.data?.items ?? []}
            eligibleLoading={eligibleQuery.isLoading}
            selectedIds={allSelectedIds}
            onSelectionChange={(ids) => {
              const assigned = new Set(assignedIds);
              setSelectedBookingIds(ids.filter((id) => !assigned.has(id)));
            }}
            assignedIds={assignedIds}
            freightType={freightType}
            canRemove={canModifyBookings}
            onRemove={handleUnassign}
          />

          {canEditBookings ? (
            <Group
              align="center"
              justify="space-between"
              wrap="wrap"
              gap="md"
              p="sm"
              style={{
                borderRadius: 12,
                background: "var(--mantine-color-gray-0)",
                border: "1px solid var(--mantine-color-gray-2)",
              }}
            >
              <Checkbox
                label="Force assign (bypass hold / overweight warnings)"
                checked={forceAssign}
                onChange={(e) => setForceAssign(e.currentTarget.checked)}
                size="sm"
              />
              <Button
                color="edr-green"
                radius="md"
                leftSection={<Eye size={16} />}
                loading={preview.isPending}
                onClick={() => void runPreview()}
              >
                Preview plan
              </Button>
            </Group>
          ) : null}

          {previewResult ? (
            <Stack gap="sm">
              <ScheduleWarningsAlert
                violations={previewResult.violations}
                warnings={previewResult.warnings}
              />
              <FleetAvailabilitySummary
                fleetAvailability={previewResult.fleetAvailability}
                deferredBookings={previewResult.deferredBookings}
              />
              <PreviewSummary summary={previewResult.summary} />
            </Stack>
          ) : null}
        </Stack>
      );
    }

    if (key === "wagon") {
      return (
        <Stack gap="md">
          {!displayWagonPlan.length && !previewResult ? (
            <Paper p="md" radius="lg" withBorder bg="gray.0">
              <Text size="sm" c="dimmed">
                Run a preview from the Bookings step to generate the wagon plan.
              </Text>
            </Paper>
          ) : null}
          <FleetAvailabilitySummary
            fleetAvailability={previewResult?.fleetAvailability}
            deferredBookings={previewResult?.deferredBookings}
          />
          <WagonPlanGrid wagonPlan={displayWagonPlan} freightType={freightType} />
          {canEditBookings && (previewResult || displayWagonPlan.length) ? (
            <Group>
              {!hasContainerStep ? (
                <Button
                  color="edr-green"
                  radius="md"
                  loading={assign.isPending}
                  onClick={handleAssign}
                >
                  {assignedIds.length ? "Save assignments" : "Assign bookings"}
                </Button>
              ) : (
                <Button
                  color="edr-green"
                  radius="md"
                  rightSection={<ContainerIcon size={16} />}
                  onClick={() => setActiveStep(2)}
                >
                  Continue to containers
                </Button>
              )}
              <Button variant="default" radius="md" onClick={() => void runPreview()}>
                Refresh preview
              </Button>
            </Group>
          ) : null}
        </Stack>
      );
    }

    if (key === "container") {
      return (
        <Stack gap="md">
          {!containerUnits.length ? (
            <Paper p="md" radius="lg" withBorder bg="gray.0">
              <Text size="sm" c="dimmed">
                Run preview from the Bookings step to load container units for numbering.
              </Text>
            </Paper>
          ) : (
            <ContainerPlacementGrid
              units={containerUnits}
              containerSlots={containerSlots}
              placements={containerPlacements}
              onChange={setContainerPlacements}
            />
          )}
          {canEditBookings ? (
            <Group>
              <Button
                color="edr-green"
                radius="md"
                loading={assign.isPending}
                onClick={handleAssign}
              >
                {assignedIds.length ? "Save assignments" : "Assign bookings"}
              </Button>
              <Button
                variant="default"
                radius="md"
                onClick={() => setActiveStep(finalizeStep)}
              >
                Skip to finalize
              </Button>
            </Group>
          ) : null}
        </Stack>
      );
    }

    // finalize
    return (
      <Stack gap="md">
        <TrainCompositionDiagram
          locomotive={schedule.trainSet?.locomotive}
          wagons={
            schedule.trainSet?.wagons?.length
              ? schedule.trainSet.wagons
              : displayWagonPlan
          }
          freightType={freightType}
          trainNumber={schedule.trainNumber}
          totalLengthMeters={schedule.trainSet?.totalLengthMeters}
        />
        <Paper
          p="lg"
          radius="lg"
          withBorder
          style={{
            background: scheduleBrand.softSurface,
            borderColor: scheduleBrand.mutedBorder,
          }}
        >
          <Group gap="md" align="flex-start" wrap="nowrap">
            <ThemeIcon size={44} radius="md" variant="light" color="#F2A516">
              <CheckCircle2 size={22} />
            </ThemeIcon>
            <Stack gap={2}>
              <Text fw={600}>Ready to depart</Text>
              <Text size="sm" c="dimmed">
                Finalizing locks the plan and moves the schedule to{" "}
                <Text span fw={600} c="edr-green.7">
                  SCHEDULED
                </Text>
                . Dispatch then begins rail movement and notifies the yard.
              </Text>
            </Stack>
          </Group>
        </Paper>
        <Group>
          {canFinalize ? (
            <Button
              color="edr-green"
              size="md"
              radius="md"
              leftSection={<CheckCircle2 size={18} />}
              loading={finalize.isPending}
              onClick={async () => {
                try {
                  await finalize.mutateAsync(scheduleId);
                  toast({ title: "Schedule finalized" });
                } catch (err) {
                  toast({
                    title: "Finalize failed",
                    description: parseError(err, "Could not finalize"),
                    variant: "destructive",
                  });
                }
              }}
            >
              Finalize schedule
            </Button>
          ) : null}
          {canDispatch ? (
            <Button
              color="edr-green"
              size="md"
              radius="md"
              leftSection={<Send size={18} />}
              loading={dispatch.isPending}
              onClick={async () => {
                try {
                  await dispatch.mutateAsync(scheduleId);
                  await openMarshallingDocument({
                    title: "Train dispatched",
                    successDescription: "Marshalling document generated for the dispatched train.",
                    errorTitle: "Train dispatched, but document could not open",
                  });
                } catch (err) {
                  toast({
                    title: "Dispatch failed",
                    description: parseError(err, "Could not dispatch"),
                    variant: "destructive",
                  });
                }
              }}
            >
              Dispatch train
            </Button>
          ) : null}
          {!canFinalize && !canDispatch ? (
            <Text size="sm" c="dimmed">
              No actions available for this schedule status.
            </Text>
          ) : null}
        </Group>
      </Stack>
    );
  };

  return (
    <PageContainer>
      <Button
        component={Link}
        to="/dashboard/operations/train-scheduling-v2"
        variant="subtle"
        color="gray"
        size="compact-sm"
        leftSection={<ArrowLeft size={16} />}
        w="fit-content"
      >
        Back to schedules
      </Button>

      <Paper
        radius="xl"
        p="xl"
        style={{ position: "relative", overflow: "hidden" }}
      >
        <Stack gap="lg" style={{ position: "relative" }}>
          <Group justify="space-between" align="flex-start" wrap="wrap">
            <Group gap="md" align="flex-start" wrap="nowrap">
              <ThemeIcon size={56} radius="lg" variant="light" color="#F2A516">
                <Train size={28} />
              </ThemeIcon>
              <Stack gap={6}>
                <Group gap="sm" align="center" wrap="wrap">
                  <Title order={2} fw={700} style={{ color: "#0f172a" }}>
                    {schedule.route?.name ?? "Train schedule"}
                  </Title>
                  {schedule.trainNumber ? (
                    <Badge variant="light" color="#F2A516" radius="sm" style={{ fontWeight: 600 }}>
                      {schedule.trainNumber}
                    </Badge>
                  ) : null}
                </Group>
                <Box maw={340}>
                  <RouteCorridor
                    origin={
                      schedule.originStation?.label ?? schedule.originStation?.code
                    }
                    destination={
                      schedule.destinationStation?.label ??
                      schedule.destinationStation?.code
                    }
                  />
                </Box>
                <Group gap="sm" align="center">
                  <FreightTypeBadge freightType={schedule.freightType} />
                  <StatusPill status={schedule.status} />
                </Group>
              </Stack>
            </Group>
            <Group gap="sm">
              {canPrintMarshalling ? (
                <Button
                  variant="light"
                  color="edr-green"
                  radius="lg"
                  size="sm"
                  leftSection={<FileText size={16} />}
                  loading={downloadMarshalling.isPending}
                  onClick={() => void openMarshallingDocument()}
                >
                  Marshalling PDF
                </Button>
              ) : null}
              {["DISPATCHED", "ARRIVED"].includes(schedule.status) ? (
                <Button
                  component={Link}
                  to={`/dashboard/operations/train-scheduling-v2/${scheduleId}/track`}
                  color="edr-green"
                  radius="lg"
                  size="sm"
                  leftSection={<Navigation size={16} />}
                >
                  Track train
                </Button>
              ) : null}
              {["DRAFT", "SCHEDULED"].includes(schedule.status) ? (
                <Button
                  variant="default"
                  radius="lg"
                  size="sm"
                  onClick={() => setMaintenanceOpen(true)}
                >
                  Reschedule train
                </Button>
              ) : null}
            </Group>
          </Group>

          {previewResult ? (
            <Badge
              size="lg"
              radius="sm"
              variant="light"
              color={previewResult.valid ? "edr-green" : "red"}
              leftSection={
                <Box
                  w={8}
                  h={8}
                  style={{
                    borderRadius: 999,
                    background: previewResult.valid
                      ? "var(--mantine-color-edr-green-6)"
                      : "var(--mantine-color-red-6)",
                  }}
                />
              }
            >
              Preview {previewResult.valid ? "valid" : "has issues"}
            </Badge>
          ) : null}
        </Stack>
      </Paper>

      <KpiStrip
        items={[
          {
            label: locomotives.length > 1 ? "Locomotives" : "Locomotive",
            value: locomotives.length
              ? locomotives.map((l) => l.code).join(" + ")
              : "—",
            hint: locomotives.length
              ? `${locomotives.length} locomotive${locomotives.length > 1 ? "s" : ""}`
              : "No locomotives assigned",
            icon: Train,
          },
          {
            label: "Bookings",
            value: schedule.bookings?.length ?? 0,
            icon: Package,
          },
          {
            label: "Wagons / load",
            value: `${schedule.trainSet?.wagonCount ?? displayWagonPlan.length} · ${
              schedule.trainSet?.totalWeightTons ?? 0
            }T`,
            icon: Weight,
          },
          {
            label: "Departure",
            value: new Date(schedule.scheduledDepartureDate).toLocaleDateString("en", {
              month: "short",
              day: "2-digit",
            }),
            hint: new Date(schedule.scheduledDepartureDate).toLocaleTimeString("en", {
              hour: "2-digit",
              minute: "2-digit",
            }),
            icon: CalendarClock,
          },
        ]}
      />

      {schedule?.direction === "IMPORT" ? (
        <Paper radius="xl" p="lg" withBorder>
          <Stack gap="md">
            <Text fw={600}>Import loading confirmation</Text>
            <Text size="sm" c="dimmed">
              Paid import bookings with a wagon allocated on this schedule. Marking loaded/unloaded
              is tracking only — it does not block dispatch.
            </Text>
            <ImportLoadingConfirmationPanel
              scheduleId={scheduleId as string}
              items={importLoadingQuery.data?.items ?? []}
              isLoading={importLoadingQuery.isLoading}
            />
          </Stack>
        </Paper>
      ) : null}

      {gatepassApplies ? (
        <Paper radius="xl" p="lg" withBorder>
          <Stack gap="md">
            <Group justify="space-between" align="flex-start" wrap="wrap">
              <Group gap="md" align="flex-start" wrap="nowrap">
                <ThemeIcon
                  size={44}
                  radius="md"
                  variant="light"
                  color={gatepassQuery.data?.gatepassStatus === "SECURED" ? "edr-green" : "orange"}
                >
                  <FileText size={22} />
                </ThemeIcon>
                <Stack gap={4}>
                  <Group gap="sm">
                    <Title order={4} fw={700}>
                      Djibouti Port gate pass
                    </Title>
                    <Badge
                      color={gatepassQuery.data?.gatepassStatus === "SECURED" ? "green" : "orange"}
                      variant="light"
                    >
                      {gatepassQuery.data?.gatepassStatus ?? "NOT_SECURED"}
                    </Badge>
                  </Group>
                  <Text size="sm" c="dimmed">
                    {schedule.direction === "IMPORT"
                      ? "Secure before dispatch from Djibouti."
                      : "Secure after dispatch before Djibouti Port entry / unloading."}
                  </Text>
                </Stack>
              </Group>
              {gatepassQuery.isLoading ? <Loader size="sm" /> : null}
            </Group>

            <Group align="flex-end" grow>
              <TextInput
                label="Secured date"
                type="datetime-local"
                value={gatepassSecuredAt}
                onChange={(event) => setGatepassSecuredAt(event.currentTarget.value)}
              />
              <TextInput
                label="Document reference"
                placeholder="Optional"
                value={gatepassReference}
                onChange={(event) => setGatepassReference(event.currentTarget.value)}
              />
              <TextInput
                label="Document URL"
                placeholder="Optional upload/link"
                value={gatepassFileUrl}
                onChange={(event) => setGatepassFileUrl(event.currentTarget.value)}
              />
            </Group>
            <Textarea
              label="Notes"
              placeholder="Optional"
              autosize
              minRows={2}
              value={gatepassNotes}
              onChange={(event) => setGatepassNotes(event.currentTarget.value)}
            />
            <Group justify="flex-end">
              <Button
                color="edr-green"
                leftSection={<CheckCircle2 size={16} />}
                loading={secureGatepass.isPending}
                onClick={() => secureGatepass.mutate()}
              >
                Save as Secured
              </Button>
            </Group>
          </Stack>
        </Paper>
      ) : null}

      <Tabs defaultValue="workflow" radius="md" color="edr-green" keepMounted={false}>
        <Tabs.List mb="md">
          <Tabs.Tab value="workflow" leftSection={<WorkflowIcon size={16} />}>
            Workflow
          </Tabs.Tab>
          <Tabs.Tab value="workspace" leftSection={<PackageCheck size={16} />}>
            Workspace
          </Tabs.Tab>
        </Tabs.List>

        <Tabs.Panel value="workflow">
          <Stack gap="lg">
      <Paper radius="xl" p="lg">
        <Stack gap="lg">
          {/* Workflow header with ring progress */}
          <Group justify="space-between" align="center" wrap="nowrap">
            <Group gap="md" align="center" wrap="nowrap">
              <ThemeIcon size={44} radius="md" variant="light" color="edr-green">
                <RouteIcon size={22} />
              </ThemeIcon>
              <Stack gap={2}>
                <Title order={4} fw={700}>
                  Scheduling workflow
                </Title>
                <Text size="sm" c="dimmed">
                  {completedCount} of {stepsMeta.length} steps complete · expand any
                  step to edit
                </Text>
              </Stack>
            </Group>
            <RingProgress
              size={64}
              thickness={6}
              roundCaps
              sections={[{ value: progressPct, color: "edr-green" }]}
              label={
                <Text ta="center" size="xs" fw={700} c="edr-green.7">
                  {progressPct}%
                </Text>
              }
            />
          </Group>

          <WorkflowRail>
            {stepsMeta.map((step, index) => (
              <WorkflowStep
                key={step.key}
                index={index}
                icon={step.icon}
                title={step.title}
                subtitle={step.subtitle}
                state={
                  activeStep === index
                    ? "active"
                    : step.complete
                      ? "complete"
                      : "upcoming"
                }
                open={activeStep === index}
                onToggle={() => toggleStep(index)}
                rightSlot={renderStepRightSlot(step.key)}
              >
                {renderStepBody(step.key)}
              </WorkflowStep>
            ))}
          </WorkflowRail>
        </Stack>
      </Paper>

            <ScheduleBatchPanel schedule={schedule} />
          </Stack>
        </Tabs.Panel>

        <Tabs.Panel value="workspace">
          <ScheduleWorkspacePanel
            schedule={schedule}
            onChanged={() => {
              autoPreviewedRef.current = false;
              void detailQuery.refetch();
            }}
          />
        </Tabs.Panel>
      </Tabs>

      {scheduleId ? (
        <RescheduleTrainDialog
          scheduleId={scheduleId}
          currentBookingIds={(schedule.bookings ?? []).map((b) => b.id)}
          opened={maintenanceOpen}
          onClose={() => setMaintenanceOpen(false)}
          onComplete={() => void detailQuery.refetch()}
        />
      ) : null}
    </PageContainer>
  );
}
