import { useMemo } from "react";
import {
  Alert,
  Badge,
  Box,
  Group,
  Paper,
  Progress,
  Stack,
  Text,
  ThemeIcon,
  Tooltip,
} from "@mantine/core";
import {
  Crown,
  Container,
  Boxes,
  FlaskConical,
  Layers,
  Ruler,
  Scale,
  Sparkles,
  TrainFront,
  Trophy,
  XCircle,
} from "lucide-react";

import type { BatchBoardScheduleDetail } from "@/types/trainScheduling";
import {
  simulateBatch,
  limitsFromDetail,
  type BlockingAxis,
  type ForecastRow,
} from "./batchForecast";

type Props = {
  data: BatchBoardScheduleDetail;
  bookings: BatchBoardScheduleDetail["pendingContract"]["bookings"];
};

const cardVar = (color: string, shade: number) =>
  `var(--mantine-color-${color}-${shade})`;

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

const AXIS_LABEL: Record<BlockingAxis, string> = {
  wagons: "wagon slots full",
  weight: "over max pull weight",
  length: "over train length",
};

/** One capacity axis as a labelled meter (used vs cap). */
function AxisMeter({
  icon: Icon,
  label,
  used,
  cap,
  fmt,
  color,
}: {
  icon: typeof Scale;
  label: string;
  used: number;
  cap: number | null;
  fmt: (n: number) => string;
  color: string;
}) {
  const pct = cap && cap > 0 ? Math.min(100, (used / cap) * 100) : 0;
  const near = pct >= 90;
  return (
    <Box style={{ flex: 1, minWidth: 150 }}>
      <Group justify="space-between" mb={4} wrap="nowrap">
        <Group gap={5} wrap="nowrap">
          <Icon size={13} color={cardVar(color, 6)} />
          <Text size="xs" c="dimmed" fw={600}>
            {label}
          </Text>
        </Group>
        <Text size="xs" fw={700} c={near ? `${color}.8` : "dark.4"}>
          {fmt(used)}
          {cap != null ? ` / ${fmt(cap)}` : ""}
        </Text>
      </Group>
      <Progress
        value={pct}
        size="md"
        radius="xl"
        color={near ? color : "edr-green"}
      />
    </Box>
  );
}

function FreightIcon({ type }: { type: string | null }) {
  const Icon = type === "BULK" ? Boxes : Container;
  return (
    <Tooltip label={type === "BULK" ? "Bulk" : "Container"} withArrow>
      <ThemeIcon size="sm" radius="sm" variant="light" color="gray">
        <Icon size={13} />
      </ThemeIcon>
    </Tooltip>
  );
}

/** A single forecast row: rank, booking, capacity contribution, projected verdict. */
function ForecastCard({ row }: { row: ForecastRow }) {
  const { booking, rank, selected, blockedBy } = row;
  const gov = booking.isGovernment;

  return (
    <Paper
      radius="md"
      p="sm"
      withBorder
      style={{
        borderColor: selected
          ? cardVar("edr-green", 3)
          : cardVar("gray", 2),
        background: selected
          ? `linear-gradient(90deg, ${cardVar("edr-green", 0)} 0%, var(--mantine-color-white) 55%)`
          : "var(--mantine-color-white)",
        opacity: selected ? 1 : 0.92,
      }}
    >
      <Group justify="space-between" wrap="nowrap" gap="sm">
        <Group wrap="nowrap" gap="sm" style={{ minWidth: 0 }}>
          <ThemeIcon
            size={32}
            radius="xl"
            variant={selected && rank <= 3 ? "filled" : "light"}
            color={gov ? "grape" : selected ? "edr-green" : "gray"}
            style={{ flexShrink: 0, fontWeight: 800 }}
          >
            {gov ? (
              <Crown size={15} />
            ) : (
              <Text fw={800} size="sm">
                {rank}
              </Text>
            )}
          </ThemeIcon>
          <Stack gap={2} style={{ minWidth: 0 }}>
            <Group gap={6} wrap="nowrap">
              <Text fw={700} size="sm" truncate>
                {booking.reference}
              </Text>
              <FreightIcon type={booking.freightType} />
              {gov ? (
                <Tooltip label="Government — boards first" withArrow>
                  <ThemeIcon size="xs" radius="sm" variant="light" color="grape">
                    <Crown size={10} />
                  </ThemeIcon>
                </Tooltip>
              ) : null}
            </Group>
            <Text size="xs" c="dimmed" truncate>
              {booking.company}
            </Text>
          </Stack>
        </Group>

        <Group wrap="nowrap" gap="lg" style={{ flexShrink: 0 }}>
          {/* score */}
          <Group gap={4} wrap="nowrap" w={70} justify="flex-end">
            <Trophy size={12} color={cardVar("edr-green", 6)} />
            <Text fw={800} size="sm" c="edr-green.7">
              {booking.priorityScore}
            </Text>
          </Group>
          {/* wagons + weight this booking adds */}
          <Group gap={4} wrap="nowrap" w={64} justify="flex-end">
            <TrainFront size={13} color={cardVar("gray", 6)} />
            <Text fw={700} size="sm">
              {booking.wagons}w
            </Text>
          </Group>
          <Text size="xs" c="dimmed" w={64} ta="right">
            {fmtTons(booking.weightTons)}
          </Text>
          {/* verdict */}
          <Box w={150} style={{ textAlign: "right" }}>
            {selected ? (
              <Badge
                variant="light"
                color="edr-green"
                radius="sm"
                leftSection={<Sparkles size={11} />}
              >
                Would board
              </Badge>
            ) : (
              <Tooltip
                label={
                  blockedBy
                    ? `Doesn't fit — ${AXIS_LABEL[blockedBy]}`
                    : "Below the capacity line"
                }
                withArrow
              >
                <Badge variant="light" color="gray" radius="sm">
                  Waiting list
                </Badge>
              </Tooltip>
            )}
          </Box>
        </Group>
      </Group>
    </Paper>
  );
}

/** Cut line between the simulated batch and the simulated waiting list. */
function CutLine({ full }: { full: boolean }) {
  return (
    <Group gap="xs" my={2} wrap="nowrap">
      <Box style={{ flex: 1, height: 2, background: cardVar("orange", 3) }} />
      <Group gap={6} wrap="nowrap">
        <ThemeIcon size="sm" radius="xl" variant="light" color="orange">
          <Layers size={12} />
        </ThemeIcon>
        <Text size="xs" fw={700} c="orange.7">
          Forecast capacity line{full ? " · TRAIN FULL" : ""}
        </Text>
      </Group>
      <Box style={{ flex: 1, height: 2, background: cardVar("orange", 3) }} />
    </Group>
  );
}

/**
 * Forecast / "what-if" panel. Simulates the batch engine's greedy fill on the
 * current pool and shows the projected winners + waiting list BEFORE document
 * review closes. Not the real selection — the engine commits that when staff run
 * the batch after the review window ends.
 */
export function ForecastPanel({ data, bookings }: Props) {
  const limits = useMemo(() => limitsFromDetail(data), [data]);
  const sim = useMemo(
    () => simulateBatch(bookings, limits),
    [bookings, limits],
  );

  const noCaps =
    limits.maxWagons == null &&
    limits.maxWeightTons == null &&
    limits.maxLengthMeters == null;

  return (
    <Stack gap="lg">
      {/* Header + explainer */}
      <Paper radius="lg" withBorder p="lg">
        <Group justify="space-between" wrap="wrap" gap="md" mb="md">
          <Group gap="sm">
            <ThemeIcon variant="light" color="violet" radius="md" size="lg">
              <FlaskConical size={18} />
            </ThemeIcon>
            <Stack gap={2}>
              <Group gap={8}>
                <Text fw={700}>Forecast batch (simulated)</Text>
                <Badge variant="light" color="violet" radius="sm" size="sm">
                  Preview
                </Badge>
              </Group>
              <Text size="xs" c="dimmed" maw={520}>
                What the batch engine would pick if it ran now — greedy fill by
                priority until the train is full. The real selection happens when
                document review ends and staff run the batch.
              </Text>
            </Stack>
          </Group>
          <Group gap="lg">
            <Stack gap={0} align="flex-end">
              <Text size="xl" fw={800} c="edr-green.7">
                {sim.selected.length}
              </Text>
              <Text size="xs" c="dimmed">
                would board
              </Text>
            </Stack>
            <Stack gap={0} align="flex-end">
              <Text size="xl" fw={800} c="gray.7">
                {sim.waiting.length}
              </Text>
              <Text size="xs" c="dimmed">
                waiting list
              </Text>
            </Stack>
          </Group>
        </Group>

        {/* Three capacity axes */}
        <Group gap="lg" align="flex-end" wrap="wrap">
          <AxisMeter
            icon={TrainFront}
            label="Wagon slots"
            used={sim.usedWagons}
            cap={limits.maxWagons}
            fmt={(n) => `${n}`}
            color="edr-green"
          />
          <AxisMeter
            icon={Scale}
            label="Max pull weight"
            used={sim.usedWeightTons}
            cap={limits.maxWeightTons}
            fmt={fmtTons}
            color="orange"
          />
          <AxisMeter
            icon={Ruler}
            label="Train length"
            used={sim.usedLengthMeters}
            cap={limits.maxLengthMeters}
            fmt={fmtMeters}
            color="blue"
          />
        </Group>

        {noCaps ? (
          <Alert
            color="yellow"
            mt="md"
            radius="md"
            icon={<XCircle size={16} />}
          >
            No locomotive / capacity limits on this schedule yet — forecast can't
            draw the capacity line. Assign a locomotive to simulate the fill.
          </Alert>
        ) : null}
      </Paper>

      {sim.rows.length === 0 ? (
        <Paper radius="lg" withBorder p="xl">
          <Text c="dimmed" ta="center">
            No eligible bookings to forecast yet.
          </Text>
        </Paper>
      ) : (
        <Stack gap={6}>
          {/* WOULD BOARD */}
          {sim.selected.length > 0 ? (
            <Stack gap={6}>
              <Group gap="xs">
                <ThemeIcon
                  size="sm"
                  radius="sm"
                  variant="light"
                  color="edr-green"
                >
                  <Sparkles size={13} />
                </ThemeIcon>
                <Text fw={700} size="sm">
                  Projected batch{" "}
                  <Text span c="dimmed" fw={500}>
                    ({sim.selected.length}) — top priority, fits capacity
                  </Text>
                </Text>
              </Group>
              {sim.selected.map((r) => (
                <ForecastCard key={r.booking.id} row={r} />
              ))}
            </Stack>
          ) : null}

          <CutLine full={sim.full} />

          {/* WAITING LIST */}
          {sim.waiting.length > 0 ? (
            <Stack gap={6}>
              <Group gap="xs">
                <ThemeIcon size="sm" radius="sm" variant="light" color="gray">
                  <Layers size={13} />
                </ThemeIcon>
                <Text fw={700} size="sm">
                  Projected waiting list{" "}
                  <Text span c="dimmed" fw={500}>
                    ({sim.waiting.length}) — boards only if a slot frees up
                  </Text>
                </Text>
              </Group>
              {sim.waiting.map((r) => (
                <ForecastCard key={r.booking.id} row={r} />
              ))}
            </Stack>
          ) : null}

          {/* INELIGIBLE (expired / pending contract) */}
          {sim.ineligible.length > 0 ? (
            <Text size="xs" c="dimmed" mt={4}>
              {sim.ineligible.length} booking
              {sim.ineligible.length === 1 ? "" : "s"} not in the forecast
              (expired or contract not signed).
            </Text>
          ) : null}
        </Stack>
      )}
    </Stack>
  );
}

export default ForecastPanel;
