import {
  Alert,
  Button,
  Divider,
  Group,
  Loader,
  Modal,
  Stack,
  Table,
  Text,
  ThemeIcon,
  Tooltip,
} from "@mantine/core";
import { DateTimePicker } from "@mantine/dates";
import { useMutation, useQuery } from "@tanstack/react-query";
import {
  CheckCircle2,
  Flag,
  MapPin,
  PackageCheck,
  TrainFront,
} from "lucide-react";
import { useEffect, useState } from "react";
import { Freight } from "@edr/types";

import { BookingStatusBadge } from "@/components/bookings/BookingStatusBadge";
import { StationWorkControls } from "@/components/trainScheduling/StationWorkControls";
import { Chip } from "./trackPrimitives";
import { DIRECTION_TONE, track as T } from "./trackTheme";
import { useAuth } from "@/auth/useAuth";
import { FREIGHT_PERMS, hasPermission as hasFreightPermission } from "@/lib/permissions";
import { useToast } from "@/hooks/use-toast";
import { api } from "@/services/api";
import type { TrackStation, YardWorkBookingRow } from "@/types/trainScheduling";

const parseError = (error: unknown, fallback: string) => {
  const message = (error as { response?: { data?: { message?: string | string[] } } })
    ?.response?.data?.message;
  if (Array.isArray(message)) return message.join("; ");
  return message || (error as Error)?.message || fallback;
};

const fmtDate = (iso: string) => {
  const d = new Date(iso);
  return Number.isNaN(d.getTime()) ? iso : d.toLocaleString();
};

/** DOMESTIC displays as "Intercity" — shared with the rest of the platform. */
const DIRECTION_LABELS: Record<string, string> = Freight.TRADE_DIRECTION_LABELS;

function DirectionChip({ direction }: { direction: string }) {
  const tone = DIRECTION_TONE[direction] ?? { bg: T.surface3, fg: T.muted };
  return (
    <Chip bg={tone.bg} fg={tone.fg}>
      {DIRECTION_LABELS[direction] ?? direction}
    </Chip>
  );
}

function SectionLabel({
  icon,
  title,
  count,
}: {
  icon: React.ReactNode;
  title: string;
  count: number;
}) {
  return (
    <Group gap={8} align="center">
      <ThemeIcon size={28} radius={8} variant="light" color="edr-green">
        {icon}
      </ThemeIcon>
      <Text fw={700} size="13.5px" c={T.text}>
        {title}
      </Text>
      <Chip bg={T.surface3} fg={T.text2}>
        {String(count)}
      </Chip>
    </Group>
  );
}

/**
 * Yard-work modal for the track page's "Log pass" step.
 *
 * A train runs A→B→C→D and bookings board/alight at any stop, so logging the
 * pass at a yard is the moment its yard work happens: bookings destined here
 * flip to ARRIVED (import/export) or COMPLETED (intercity) automatically the
 * instant the pass is logged, and bookings boarding here become loadable —
 * the server only accepts a load while the train's latest checkpoint is this
 * yard. The modal therefore drives the sequence: log the pass first, then
 * load anything that boards here (including cargo the operator forgot — it
 * stays loadable until the next pass is logged).
 */
export function LogPassYardWorkModal({
  opened,
  onClose,
  scheduleId,
  station,
  isFinal,
  alreadyLogged,
}: {
  opened: boolean;
  onClose: () => void;
  scheduleId: string;
  station: TrackStation | null;
  isFinal: boolean;
  /** True when opened for the current station (pass already logged). */
  alreadyLogged: boolean;
}) {
  const { toast } = useToast();
  const { user } = useAuth();
  const canLoad = hasFreightPermission(user, FREIGHT_PERMS.trainScheduling.load);
  const canUnload = hasFreightPermission(user, FREIGHT_PERMS.trainScheduling.unload);
  const canLeave = hasFreightPermission(user, FREIGHT_PERMS.trainScheduling.update);
  const [justLogged, setJustLogged] = useState(false);
  // When the train was here — defaults to now, past allowed (recorded after the fact).
  const [passAt, setPassAt] = useState<Date | null>(null);
  useEffect(() => {
    setJustLogged(false);
    setPassAt(new Date());
  }, [station?.sequenceNo, opened]);
  const logged = alreadyLogged || justLogged;

  const yardWorkQuery = useQuery(
    api.trainScheduling.yardWork.queryOptions({
      input: { scheduleId },
      enabled: opened && Boolean(scheduleId),
    }),
  );
  const recordCheckpoint = useMutation(
    api.trainScheduling.recordCheckpoint.mutationOptions(),
  );
  const load = useMutation(api.trainScheduling.loadScheduleBooking.mutationOptions());
  const unload = useMutation(api.trainScheduling.unloadScheduleBooking.mutationOptions());
  // "Leave behind": the cargo is not on the train — unassign frees its wagons
  // and returns the booking to the pool for a later schedule. Reversible (the
  // booking can be re-assigned), so no extra confirm step.
  const leave = useMutation(api.trainScheduling.unassignBooking.mutationOptions());

  const yard = yardWorkQuery.data?.yards.find((y) => y.yardId === station?.yardId);
  const boarders: YardWorkBookingRow[] = yard?.toLoad ?? [];
  const arrivals: YardWorkBookingRow[] = yard?.toUnload ?? [];
  const pendingBoarders = boarders.filter((r) => !r.loadedAt);
  // Loading/unloading time windows at this station: the server rejects booking
  // load/unload until the matching window is started, so the buttons mirror it.
  const workLog = station
    ? yardWorkQuery.data?.stationWorkLogs?.[station.yardId]
    : undefined;
  const loadingStarted = Boolean(workLog?.loading?.startedAt);
  const unloadingStarted = Boolean(workLog?.unloading?.startedAt);

  const doLogPass = () => {
    if (!station) return;
    recordCheckpoint.mutate(
      {
        id: scheduleId,
        payload: {
          sequenceNo: station.sequenceNo,
          ...(passAt ? { occurredAt: passAt.toISOString() } : {}),
        },
      },
      {
        onSuccess: () => {
          setJustLogged(true);
          toast({
            title: isFinal
              ? "Train arrived — remaining bookings marked arrived, assets freed"
              : `Pass logged at ${station.label}`,
            description: isFinal
              ? undefined
              : arrivals.some((r) => r.canUnload)
                ? unloadingStarted
                  ? "Bookings arriving here have been marked arrived."
                  : "Start unloading, then unload each arriving booking."
                : undefined,
          });
          void yardWorkQuery.refetch();
        },
        onError: (err) =>
          toast({
            title: "Could not log checkpoint",
            description: parseError(err, "Please try again"),
            variant: "destructive",
          }),
      },
    );
  };

  const doLoad = (row: YardWorkBookingRow) => {
    load.mutate(
      { scheduleId, bookingId: row.id },
      {
        onSuccess: () => {
          toast({
            title: `${row.reference ?? "Booking"} loaded`,
            description: `Cargo boarded the train at ${station?.label ?? "this yard"}.`,
          });
          void yardWorkQuery.refetch();
        },
        onError: (err) =>
          toast({
            title: "Could not load booking",
            description: parseError(err, "Please try again"),
            variant: "destructive",
          }),
      },
    );
  };

  const doUnload = (row: YardWorkBookingRow) => {
    unload.mutate(
      { scheduleId, bookingId: row.id },
      {
        onSuccess: () => {
          toast({
            title: `${row.reference ?? "Booking"} unloaded`,
            description: `Cargo left the train at ${station?.label ?? "this yard"}.`,
          });
          void yardWorkQuery.refetch();
        },
        onError: (err) =>
          toast({
            title: "Could not unload booking",
            description: parseError(err, "Please try again"),
            variant: "destructive",
          }),
      },
    );
  };

  const doLeave = (row: YardWorkBookingRow) => {
    leave.mutate(
      { id: scheduleId, bookingId: row.id },
      {
        onSuccess: () => {
          toast({
            title: `${row.reference ?? "Booking"} left behind`,
            description:
              "Removed from this train — wagons freed, booking returned to the pool for a later schedule.",
          });
          void yardWorkQuery.refetch();
        },
        onError: (err) =>
          toast({
            title: "Could not leave booking behind",
            description: parseError(err, "Please try again"),
            variant: "destructive",
          }),
      },
    );
  };

  const hasWork = boarders.length > 0 || arrivals.length > 0;

  return (
    <Modal
      opened={opened}
      onClose={onClose}
      size="xl"
      radius={18}
      title={
        <Group gap={8}>
          {isFinal ? <Flag size={18} /> : <MapPin size={18} />}
          <Text fw={700}>
            {isFinal ? "Arrival" : "Yard work"} — {station?.label ?? ""}
          </Text>
          {logged ? (
            <Chip bg={T.brandDim} fg={T.brand}>
              {isFinal ? "ARRIVED" : "PASS LOGGED"}
            </Chip>
          ) : null}
        </Group>
      }
    >
      <Stack gap="md">
        {yardWorkQuery.isLoading ? (
          <Group justify="center" py="lg">
            <Loader size="sm" color="edr-green" />
          </Group>
        ) : !hasWork ? (
          <Alert color="gray" variant="light" radius="md" icon={<MapPin size={16} />}>
            No bookings board or alight at this station.
          </Alert>
        ) : (
          <>
            {/* ── Arriving here ─────────────────────────────────────────── */}
            {arrivals.length > 0 ? (
              <Stack gap="xs">
                <SectionLabel
                  icon={<Flag size={14} />}
                  title="Arriving at this yard"
                  count={arrivals.length}
                />
                {station ? (
                  <StationWorkControls
                    scheduleId={scheduleId}
                    yardId={station.yardId}
                    phase="unloading"
                    log={workLog?.unloading}
                  />
                ) : null}
                {!logged ? (
                  <Text size="xs" c="dimmed">
                    Log the pass, start unloading, then unload each booking below.
                  </Text>
                ) : !unloadingStarted && arrivals.some((r) => r.canUnload) ? (
                  <Text size="xs" c="dimmed">
                    Start unloading first — bookings can only be unloaded inside a
                    started unloading window.
                  </Text>
                ) : null}
                <Table.ScrollContainer minWidth={620}>
                  <Table
                    verticalSpacing={11}
                    highlightOnHover
                    styles={{
                      th: {
                        fontSize: 9.5,
                        fontWeight: 700,
                        letterSpacing: 0.7,
                        textTransform: "uppercase",
                        color: T.muted,
                        background: T.surface2,
                      },
                    }}
                  >
                    <Table.Thead>
                      <Table.Tr>
                        <Table.Th>Booking</Table.Th>
                        <Table.Th>Customer</Table.Th>
                        <Table.Th>Direction</Table.Th>
                        <Table.Th>Status</Table.Th>
                        <Table.Th>Arrived</Table.Th>
                        <Table.Th />
                      </Table.Tr>
                    </Table.Thead>
                    <Table.Tbody>
                      {arrivals.map((row) => (
                        <Table.Tr key={row.id}>
                          <Table.Td>
                            <Text size="12px" fw={600} style={{ fontFamily: T.mono }}>
                              {row.reference ?? row.id.slice(0, 8)}
                            </Text>
                          </Table.Td>
                          <Table.Td>
                            <Text size="12.5px" c={T.text2}>{row.customer}</Text>
                          </Table.Td>
                          <Table.Td>
                            <DirectionChip direction={row.tradeDirection} />
                          </Table.Td>
                          <Table.Td>
                            <BookingStatusBadge status={row.status} />
                          </Table.Td>
                          <Table.Td>
                            <Text size="xs" c="dimmed">
                              {row.arrivedAt ? fmtDate(row.arrivedAt) : "—"}
                            </Text>
                          </Table.Td>
                          <Table.Td>
                            {row.canUnload ? (
                              <Tooltip
                                label={
                                  !canUnload
                                    ? "You don't have permission to unload cargo"
                                    : !logged
                                      ? "Log the pass first — the train must be at this yard"
                                      : !unloadingStarted
                                        ? "Start unloading first"
                                        : "Confirm cargo unloaded off the train"
                                }
                              >
                                <Button
                                  size="compact-xs"
                                  radius={8}
                                  variant="light"
                                  color="teal"
                                  leftSection={<PackageCheck size={13} />}
                                  disabled={!canUnload || !logged || !unloadingStarted}
                                  loading={
                                    unload.isPending &&
                                    unload.variables?.bookingId === row.id
                                  }
                                  onClick={() => doUnload(row)}
                                >
                                  Unload
                                </Button>
                              </Tooltip>
                            ) : null}
                          </Table.Td>
                        </Table.Tr>
                      ))}
                    </Table.Tbody>
                  </Table>
                </Table.ScrollContainer>
              </Stack>
            ) : null}

            {arrivals.length > 0 && boarders.length > 0 ? <Divider /> : null}

            {/* ── Boarding here ─────────────────────────────────────────── */}
            {boarders.length > 0 ? (
              <Stack gap="xs">
                <SectionLabel
                  icon={<TrainFront size={14} />}
                  title="Boarding at this yard"
                  count={boarders.length}
                />
                {station ? (
                  <StationWorkControls
                    scheduleId={scheduleId}
                    yardId={station.yardId}
                    phase="loading"
                    log={workLog?.loading}
                  />
                ) : null}
                {!logged && pendingBoarders.length > 0 ? (
                  <Text size="xs" c="dimmed">
                    Log the pass first — the train must be at {station?.label} before
                    cargo can be loaded.
                  </Text>
                ) : !loadingStarted && pendingBoarders.length > 0 ? (
                  <Text size="xs" c="dimmed">
                    Start loading first — bookings can only be loaded inside a started
                    loading window.
                  </Text>
                ) : null}
                <Table.ScrollContainer minWidth={620}>
                  <Table
                    verticalSpacing={11}
                    highlightOnHover
                    styles={{
                      th: {
                        fontSize: 9.5,
                        fontWeight: 700,
                        letterSpacing: 0.7,
                        textTransform: "uppercase",
                        color: T.muted,
                        background: T.surface2,
                      },
                    }}
                  >
                    <Table.Thead>
                      <Table.Tr>
                        <Table.Th>Booking</Table.Th>
                        <Table.Th>Customer</Table.Th>
                        <Table.Th>Direction</Table.Th>
                        <Table.Th>Status</Table.Th>
                        <Table.Th>Loaded</Table.Th>
                        <Table.Th />
                      </Table.Tr>
                    </Table.Thead>
                    <Table.Tbody>
                      {boarders.map((row) => (
                        <Table.Tr key={row.id}>
                          <Table.Td>
                            <Group gap={6} wrap="nowrap">
                              <Text size="12px" fw={600} style={{ fontFamily: T.mono }}>
                                {row.reference ?? row.id.slice(0, 8)}
                              </Text>
                              {row.isGovernment ? (
                                <Chip bg={T.grapeDim} fg={T.grape}>
                                  GOV
                                </Chip>
                              ) : null}
                            </Group>
                          </Table.Td>
                          <Table.Td>
                            <Text size="12.5px" c={T.text2}>{row.customer}</Text>
                          </Table.Td>
                          <Table.Td>
                            <DirectionChip direction={row.tradeDirection} />
                          </Table.Td>
                          <Table.Td>
                            <BookingStatusBadge status={row.status} />
                          </Table.Td>
                          <Table.Td>
                            {row.loadedAt ? (
                              <Group gap={4} wrap="nowrap">
                                <CheckCircle2
                                  size={13}
                                  color="var(--mantine-color-edr-green-7)"
                                />
                                <Text size="xs" c="dimmed">
                                  {fmtDate(row.loadedAt)}
                                </Text>
                              </Group>
                            ) : (
                              <Text size="xs" c="dimmed">
                                Not loaded
                              </Text>
                            )}
                          </Table.Td>
                          <Table.Td>
                            {!row.loadedAt ? (
                              <Group gap={6} wrap="nowrap">
                                <Tooltip
                                  label={
                                    !canLoad
                                      ? "You don't have permission to load cargo"
                                      : !logged
                                        ? "Log the pass first — the train must be at this yard"
                                        : !loadingStarted
                                          ? "Start loading first"
                                          : !row.canLoad
                                            ? "Booking is not ready to load (payment pending)"
                                            : "Confirm cargo loaded onto the train"
                                  }
                                >
                                  <Button
                                    size="compact-xs"
                                    radius={8}
                                    color="edr-green"
                                    leftSection={<PackageCheck size={13} />}
                                    disabled={!canLoad || !logged || !loadingStarted || !row.canLoad}
                                    loading={
                                      load.isPending && load.variables?.bookingId === row.id
                                    }
                                    onClick={() => doLoad(row)}
                                  >
                                    Load
                                  </Button>
                                </Tooltip>
                                <Tooltip
                                  label={
                                    row.isGovernment
                                      ? "Government bookings cannot be removed from a train"
                                      : !canLeave
                                        ? "You don't have permission to remove bookings"
                                        : "Cargo is not on the train — free its wagons and return the booking to the pool"
                                  }
                                >
                                  <Button
                                    size="compact-xs"
                                    radius={8}
                                    variant="light"
                                    color="red"
                                    disabled={!canLeave || row.isGovernment}
                                    loading={
                                      leave.isPending && leave.variables?.bookingId === row.id
                                    }
                                    onClick={() => doLeave(row)}
                                  >
                                    Leave
                                  </Button>
                                </Tooltip>
                              </Group>
                            ) : null}
                          </Table.Td>
                        </Table.Tr>
                      ))}
                    </Table.Tbody>
                  </Table>
                </Table.ScrollContainer>
              </Stack>
            ) : null}
          </>
        )}

        {!logged ? (
          <DateTimePicker
            label={isFinal ? "Arrival time" : "Time at station"}
            description="Defaults to now — pick an earlier time if you are recording after the fact."
            value={passAt}
            onChange={(v) => setPassAt(v ? new Date(v) : null)}
            maxDate={new Date()}
            valueFormat="DD MMM YYYY HH:mm"
            clearable={false}
            radius="md"
            maw={320}
          />
        ) : null}

        <Group justify="space-between" mt="xs">
          <Text size="xs" c="dimmed">
            {logged && pendingBoarders.length > 0
              ? `${pendingBoarders.length} booking${pendingBoarders.length === 1 ? "" : "s"} still to load before the next station.`
              : ""}
          </Text>
          <Group gap="sm">
            <Button variant="default" radius={9} onClick={onClose}>
              Close
            </Button>
            {!logged ? (
              // Arrival comes BEFORE unloading: the train is marked arrived
              // whenever it physically gets there, and the unloading window
              // opens afterwards. Bookings then unload per booking inside the
              // started window (the buttons above enforce that).
              <Button
                radius={9}
                color={isFinal ? "teal" : "edr-green"}
                leftSection={isFinal ? <Flag size={15} /> : <MapPin size={15} />}
                loading={recordCheckpoint.isPending}
                onClick={doLogPass}
              >
                {isFinal
                  ? `Mark arrived at ${station?.label ?? "destination"}`
                  : `Log pass at ${station?.label ?? "station"}`}
              </Button>
            ) : null}
          </Group>
        </Group>
      </Stack>
    </Modal>
  );
}
