import { useMemo } from "react";
import { Box, Group, Paper, Progress, Stack, Text, Tooltip } from "@mantine/core";
import { useElementSize } from "@mantine/hooks";
import { Box as BoxIcon, Container as ContainerIcon, Fuel, Gauge, TrainFront } from "lucide-react";

import { freightBrand } from "@/theme/freight-brand";

/**
 * Visual train composition: a locomotive coupled to its wagons, drawn like a real
 * consist. Long trains wrap into a serpentine (zig-zag) so the whole train stays on
 * screen. Each wagon shows its load (container blocks or a bulk fill gauge), physical
 * wagon number and tonnage.
 */

type DiagramWagonInput = {
  sequenceNo: number;
  capacityTons: number;
  assignedWeightTons: number;
  slotLoadType?: string | null;
  wagonType?: { code?: string | null } | null;
  wagonTypeCode?: string | null;
  physicalWagonNumber?: string | null;
  allocations?: Array<{
    bookingReference?: string | null;
    bookingId?: string;
    loadType?: string | null;
    containerItems?: Array<{ containerNumber?: string | null }> | null;
    bulkLoad?: { weightTons?: number | null; cargoDescription?: string | null } | null;
  }> | null;
};

type NormalizedWagon = {
  sequenceNo: number;
  capacityTons: number;
  assignedWeightTons: number;
  wagonTypeCode: string | null;
  physicalWagonNumber: string | null;
  isEmpty: boolean;
  isBulk: boolean;
  containerNumbers: string[];
  bookingRefs: string[];
  cargoDescription: string | null;
};

const CAR_WIDTH = 150; // car body + coupler footprint

function normalizeWagon(w: DiagramWagonInput, freightType?: string | null): NormalizedWagon {
  const allocations = w.allocations ?? [];
  const firstLoad = (
    w.slotLoadType ??
    allocations[0]?.loadType ??
    freightType ??
    ""
  )
    .toString()
    .toUpperCase();
  const isBulk = firstLoad.includes("BULK");
  const containerNumbers: string[] = [];
  const bookingRefs: string[] = [];
  let cargoDescription: string | null = null;
  for (const alloc of allocations) {
    if (alloc.bookingReference) bookingRefs.push(alloc.bookingReference);
    for (const item of alloc.containerItems ?? []) {
      containerNumbers.push(item.containerNumber?.trim() || "—");
    }
    if (alloc.bulkLoad?.cargoDescription) cargoDescription = alloc.bulkLoad.cargoDescription;
  }
  return {
    sequenceNo: w.sequenceNo,
    capacityTons: Number(w.capacityTons) || 0,
    assignedWeightTons: Number(w.assignedWeightTons) || 0,
    wagonTypeCode: w.wagonType?.code ?? w.wagonTypeCode ?? null,
    physicalWagonNumber: w.physicalWagonNumber ?? null,
    isEmpty: allocations.length === 0,
    isBulk,
    containerNumbers,
    bookingRefs,
    cargoDescription,
  };
}

function chunk<T>(items: T[], size: number): T[][] {
  if (size <= 0) return [items];
  const rows: T[][] = [];
  for (let i = 0; i < items.length; i += size) rows.push(items.slice(i, i + size));
  return rows;
}

function Wheels({ count = 2, dark = false }: { count?: number; dark?: boolean }) {
  return (
    <Group gap={count > 2 ? 10 : 18} justify="center" wrap="nowrap" mt={2}>
      {Array.from({ length: count }).map((_, i) => (
        <Box
          key={i}
          style={{
            width: 13,
            height: 13,
            borderRadius: "50%",
            background: dark
              ? "radial-gradient(circle at 35% 35%, #2c4a3a, #0f291b)"
              : "radial-gradient(circle at 35% 35%, var(--mantine-color-gray-5), var(--mantine-color-gray-8))",
            border: "2px solid var(--mantine-color-gray-4)",
            boxShadow: "inset 0 0 0 2px rgba(255,255,255,0.3), 0 1px 2px rgba(0,0,0,0.2)",
          }}
        />
      ))}
    </Group>
  );
}

function Coupler() {
  return (
    <Box style={{ width: 16, height: 78, display: "flex", alignItems: "center", flexShrink: 0 }}>
      <Box
        style={{
          width: "100%",
          height: 6,
          borderRadius: 3,
          background:
            "linear-gradient(90deg, var(--mantine-color-gray-4), var(--mantine-color-gray-6), var(--mantine-color-gray-4))",
          boxShadow: "0 1px 1px rgba(0,0,0,0.15)",
        }}
      />
    </Box>
  );
}

function LocomotiveCar({
  code,
  name,
  maxPullWeightTons,
}: {
  code: string;
  name?: string | null;
  maxPullWeightTons?: number | null;
}) {
  return (
    <Tooltip
      label={`Locomotive ${code}${name ? ` · ${name}` : ""}${
        maxPullWeightTons ? ` · pulls up to ${maxPullWeightTons}T` : ""
      }`}
      withArrow
    >
      <Box style={{ width: 134, flexShrink: 0 }}>
        <Box
          style={{
            position: "relative",
            height: 78,
            borderRadius: "14px 26px 10px 10px",
            background: `linear-gradient(160deg, ${freightBrand.primaryLight} 0%, ${freightBrand.primary} 45%, ${freightBrand.primaryDark} 100%)`,
            boxShadow: `${freightBrand.shadowSm}, inset 0 1px 0 rgba(255,255,255,0.25)`,
            border: "1px solid rgba(0,0,0,0.1)",
            overflow: "hidden",
            padding: "10px 10px 8px",
            color: "white",
          }}
        >
          {/* roofline */}
          <Box
            style={{
              position: "absolute",
              top: 0,
              left: 0,
              right: 14,
              height: 5,
              background: "rgba(0,0,0,0.22)",
              borderRadius: "14px 0 0 0",
            }}
          />
          {/* roof vents */}
          <Box style={{ position: "absolute", top: 1, left: 16, display: "flex", gap: 5 }}>
            {[0, 1, 2].map((i) => (
              <Box
                key={i}
                style={{
                  width: 10,
                  height: 3,
                  borderRadius: 2,
                  background: "rgba(255,255,255,0.35)",
                }}
              />
            ))}
          </Box>
          {/* cab windows */}
          <Box style={{ position: "absolute", top: 10, right: 10, display: "flex", gap: 4 }}>
            <Box
              style={{
                width: 15,
                height: 13,
                borderRadius: "3px 6px 3px 3px",
                background: "linear-gradient(135deg, #E8FBFF 0%, #9ED9E8 100%)",
                border: "1px solid rgba(0,0,0,0.15)",
              }}
            />
            <Box
              style={{
                width: 12,
                height: 13,
                borderRadius: 3,
                background: "linear-gradient(135deg, rgba(232,251,255,0.8), rgba(158,217,232,0.6))",
                border: "1px solid rgba(0,0,0,0.12)",
              }}
            />
          </Box>
          {/* headlight */}
          <Box
            style={{
              position: "absolute",
              bottom: 14,
              right: 5,
              width: 8,
              height: 8,
              borderRadius: "50%",
              background: "#fde68a",
              boxShadow: "0 0 10px 3px rgba(253,230,138,0.9)",
            }}
          />
          {/* hazard stripe on the nose */}
          <Box
            style={{
              position: "absolute",
              bottom: 0,
              left: 0,
              right: 0,
              height: 6,
              background:
                "repeating-linear-gradient(45deg, #fbbf24 0 7px, #1f2937 7px 14px)",
              opacity: 0.9,
            }}
          />
          <Group gap={6} wrap="nowrap" align="center">
            <TrainFront size={18} />
            <Text size="sm" fw={800} style={{ letterSpacing: 0.4 }}>
              {code}
            </Text>
          </Group>
          <Text size="9px" mt={1} style={{ opacity: 0.85 }} lineClamp={1}>
            {name ?? "Locomotive"}
          </Text>
          {maxPullWeightTons ? (
            <Group gap={3} wrap="nowrap" mt={3} style={{ opacity: 0.95 }}>
              <Gauge size={10} />
              <Text size="9px" fw={700}>
                {maxPullWeightTons}T pull
              </Text>
            </Group>
          ) : null}
        </Box>
        <Wheels count={3} dark />
        <Text size="9px" ta="center" c="dimmed" mt={2} fw={700} style={{ letterSpacing: 1 }}>
          HEAD
        </Text>
      </Box>
    </Tooltip>
  );
}

const CONTAINER_GRADIENTS = [
  "linear-gradient(180deg, var(--mantine-color-cyan-5), var(--mantine-color-cyan-7))",
  "linear-gradient(180deg, var(--mantine-color-blue-5), var(--mantine-color-blue-7))",
];
const CONTAINER_BORDERS = [
  "var(--mantine-color-cyan-8)",
  "var(--mantine-color-blue-8)",
];

function WagonCar({ wagon }: { wagon: NormalizedWagon }) {
  const utilization =
    wagon.capacityTons > 0
      ? Math.min(100, Math.round((wagon.assignedWeightTons / wagon.capacityTons) * 100))
      : 0;
  const accent = wagon.isEmpty ? "gray" : wagon.isBulk ? "orange" : "cyan";
  const accentVar = `var(--mantine-color-${accent}-6)`;

  const tooltipLabel = wagon.isEmpty
    ? `Wagon #${wagon.sequenceNo} · empty / available`
    : `Wagon #${wagon.sequenceNo}${wagon.physicalWagonNumber ? ` · ${wagon.physicalWagonNumber}` : ""}\n${
        wagon.bookingRefs.length ? wagon.bookingRefs.join(", ") : ""
      }${
        wagon.containerNumbers.length ? `\nContainers: ${wagon.containerNumbers.join(", ")}` : ""
      }${wagon.cargoDescription ? `\n${wagon.cargoDescription}` : ""}\nLoad: ${wagon.assignedWeightTons}/${wagon.capacityTons}T (${utilization}%)`;

  // container blocks: one per container number (cap visual at 2 = TEU per wagon)
  const blocks = wagon.containerNumbers.slice(0, 2);

  return (
    <Tooltip label={tooltipLabel} withArrow multiline maw={240} style={{ whiteSpace: "pre-line" }}>
      <Box style={{ width: 134, flexShrink: 0 }}>
        <Box
          style={{
            position: "relative",
            height: 78,
            borderRadius: 12,
            background: wagon.isEmpty
              ? "var(--mantine-color-gray-0)"
              : "linear-gradient(180deg, white, var(--mantine-color-gray-0))",
            border: wagon.isEmpty
              ? "1.5px dashed var(--mantine-color-gray-4)"
              : "1px solid var(--mantine-color-gray-3)",
            boxShadow: wagon.isEmpty ? "none" : "0 3px 10px rgba(15,41,27,0.08)",
            overflow: "hidden",
            display: "flex",
            flexDirection: "column",
          }}
        >
          {/* top accent strip */}
          <Box
            style={{
              height: 4,
              background: wagon.isEmpty
                ? "var(--mantine-color-gray-3)"
                : `linear-gradient(90deg, ${accentVar}, var(--mantine-color-${accent}-4))`,
            }}
          />
          {/* header */}
          <Group justify="space-between" px={8} pt={4} wrap="nowrap">
            <Text size="10px" fw={800} c="gray.7">
              #{wagon.sequenceNo}
            </Text>
            {wagon.isEmpty ? (
              <Text size="9px" c="dimmed" fw={700} style={{ letterSpacing: 0.5 }}>
                EMPTY
              </Text>
            ) : (
              <Group gap={3} wrap="nowrap">
                {wagon.isBulk ? <Fuel size={11} color={accentVar} /> : <ContainerIcon size={11} color={accentVar} />}
                <Text size="9px" fw={700} c={`${accent}.7`} style={{ letterSpacing: 0.4 }}>
                  {wagon.isBulk ? "BULK" : "CONT"}
                </Text>
              </Group>
            )}
          </Group>

          {/* body */}
          <Box style={{ flex: 1, padding: "4px 8px 4px", display: "flex", alignItems: "center" }}>
            {wagon.isEmpty ? (
              <Group gap={4} justify="center" style={{ width: "100%" }}>
                <BoxIcon size={14} color="var(--mantine-color-gray-4)" />
                <Text size="9px" c="dimmed">
                  Available
                </Text>
              </Group>
            ) : wagon.isBulk ? (
              <Stack gap={3} style={{ width: "100%" }}>
                <Box
                  style={{
                    height: 18,
                    borderRadius: 6,
                    background: "var(--mantine-color-orange-0)",
                    border: "1px solid var(--mantine-color-orange-2)",
                    overflow: "hidden",
                    position: "relative",
                  }}
                >
                  <Box
                    style={{
                      position: "absolute",
                      inset: 0,
                      width: `${utilization}%`,
                      background:
                        "linear-gradient(90deg, var(--mantine-color-orange-6), var(--mantine-color-orange-4))",
                      boxShadow: "inset 0 1px 0 rgba(255,255,255,0.35)",
                    }}
                  />
                </Box>
                <Text size="9px" c="dimmed" ta="center" fw={600}>
                  {wagon.assignedWeightTons}/{wagon.capacityTons}T
                </Text>
              </Stack>
            ) : (
              <Group gap={4} justify="center" wrap="nowrap" style={{ width: "100%" }}>
                {(blocks.length ? blocks : ["—"]).map((cn, i) => (
                  <Box
                    key={i}
                    style={{
                      flex: 1,
                      minWidth: 0,
                      height: 28,
                      borderRadius: 5,
                      background: CONTAINER_GRADIENTS[i % CONTAINER_GRADIENTS.length],
                      border: `1px solid ${CONTAINER_BORDERS[i % CONTAINER_BORDERS.length]}`,
                      boxShadow: "inset 0 1px 0 rgba(255,255,255,0.3), 0 1px 2px rgba(0,0,0,0.15)",
                      display: "flex",
                      flexDirection: "column",
                      alignItems: "center",
                      justifyContent: "center",
                      padding: "0 3px",
                    }}
                  >
                    {/* corrugation lines */}
                    <Box
                      style={{
                        width: "80%",
                        height: 2,
                        marginBottom: 2,
                        background:
                          "repeating-linear-gradient(90deg, rgba(255,255,255,0.4) 0 3px, transparent 3px 6px)",
                        borderRadius: 1,
                      }}
                    />
                    <Text size="8px" fw={700} c="white" truncate style={{ maxWidth: "100%" }}>
                      {cn}
                    </Text>
                  </Box>
                ))}
              </Group>
            )}
          </Box>

          {/* utilization hairline */}
          {!wagon.isEmpty && !wagon.isBulk ? (
            <Box style={{ height: 3, background: "var(--mantine-color-gray-1)" }}>
              <Box
                style={{
                  width: `${utilization}%`,
                  height: "100%",
                  background:
                    utilization >= 100
                      ? "var(--mantine-color-red-5)"
                      : `var(--mantine-color-${accent}-5)`,
                }}
              />
            </Box>
          ) : null}

          {/* footer */}
          <Box
            style={{
              borderTop: "1px solid var(--mantine-color-gray-1)",
              padding: "2px 8px",
              background: wagon.isEmpty ? "transparent" : "var(--mantine-color-gray-0)",
            }}
          >
            <Group justify="space-between" wrap="nowrap" gap={4}>
              <Text size="8px" c="dimmed" fw={600} truncate>
                {wagon.physicalWagonNumber ?? wagon.wagonTypeCode ?? "Wagon"}
              </Text>
              {!wagon.isEmpty ? (
                <Text size="8px" c="gray.6" fw={700} style={{ whiteSpace: "nowrap" }}>
                  {wagon.assignedWeightTons}T
                </Text>
              ) : null}
            </Group>
          </Box>
        </Box>
        <Wheels count={2} />
      </Box>
    </Tooltip>
  );
}

/** Railway track: two rails over evenly-spaced sleepers. */
function TrackBed() {
  return (
    <Box
      style={{
        position: "absolute",
        left: 4,
        right: 4,
        bottom: 4,
        height: 10,
      }}
    >
      {/* sleepers */}
      <Box
        style={{
          position: "absolute",
          inset: 0,
          background:
            "repeating-linear-gradient(90deg, var(--mantine-color-gray-4) 0 5px, transparent 5px 20px)",
          opacity: 0.6,
          borderRadius: 2,
        }}
      />
      {/* rails */}
      <Box
        style={{
          position: "absolute",
          left: 0,
          right: 0,
          top: 1,
          height: 2,
          borderRadius: 1,
          background: "var(--mantine-color-gray-6)",
        }}
      />
      <Box
        style={{
          position: "absolute",
          left: 0,
          right: 0,
          bottom: 1,
          height: 2,
          borderRadius: 1,
          background: "var(--mantine-color-gray-6)",
        }}
      />
    </Box>
  );
}

export function TrainCompositionDiagram({
  locomotive,
  wagons,
  freightType,
  trainNumber,
  totalLengthMeters,
}: {
  locomotive?: { code?: string | null; name?: string | null; maxPullWeightTons?: number | null } | null;
  wagons: DiagramWagonInput[];
  freightType?: string | null;
  trainNumber?: string | null;
  totalLengthMeters?: number | null;
}) {
  const { ref, width } = useElementSize();

  const normalized = useMemo(
    () => wagons.map((w) => normalizeWagon(w, freightType)),
    [wagons, freightType],
  );

  const stats = useMemo(() => {
    const assigned = normalized.filter((w) => !w.isEmpty).length;
    const totalWeight = normalized.reduce((s, w) => s + w.assignedWeightTons, 0);
    const totalCapacity = normalized.reduce((s, w) => s + w.capacityTons, 0);
    return {
      total: normalized.length,
      assigned,
      empty: normalized.length - assigned,
      totalWeight: Math.round(totalWeight * 100) / 100,
      totalCapacity,
      pullUtil:
        locomotive?.maxPullWeightTons && locomotive.maxPullWeightTons > 0
          ? Math.min(100, Math.round((totalWeight / locomotive.maxPullWeightTons) * 100))
          : null,
    };
  }, [normalized, locomotive]);

  // cars-per-row from measured width; locomotive counts as one car
  const perRow = Math.max(1, Math.floor((width || CAR_WIDTH) / CAR_WIDTH));
  const cars = useMemo(
    () => [{ kind: "loco" as const }, ...normalized.map((w) => ({ kind: "wagon" as const, w }))],
    [normalized],
  );
  const rows = useMemo(() => chunk(cars, perRow), [cars, perRow]);

  if (!locomotive && !wagons.length) return null;

  return (
    <Paper
      radius="lg"
      p="lg"
      withBorder
      style={{
        borderColor: "var(--mantine-color-gray-2)",
        background: "white",
      }}
    >
      <Stack gap="md">
        {/* Header */}
        <Group justify="space-between" align="flex-start" wrap="wrap" gap="sm">
          <Group gap="sm" wrap="nowrap">
            <Box
              style={{
                display: "flex",
                alignItems: "center",
                justifyContent: "center",
                width: 40,
                height: 40,
                borderRadius: 11,
                background: freightBrand.gradient,
                boxShadow: freightBrand.shadowSm,
                color: "white",
              }}
            >
              <TrainFront size={21} />
            </Box>
            <Stack gap={0}>
              <Text fw={800} style={{ letterSpacing: 0.2 }}>
                Train composition
              </Text>
              <Text size="xs" c="dimmed">
                {trainNumber ? `${trainNumber} · ` : ""}
                {stats.total} wagons · {stats.assigned} loaded · {stats.empty} empty
                {totalLengthMeters ? ` · ${totalLengthMeters}m` : ""}
              </Text>
            </Stack>
          </Group>

          <Group gap="md">
            <Group
              gap={6}
              style={{
                padding: "4px 12px",
                borderRadius: 999,
                background: "var(--mantine-color-gray-0)",
                border: "1px solid var(--mantine-color-gray-2)",
              }}
            >
              <Text size="xs" fw={700} c="dark.4">
                {stats.totalWeight}T
              </Text>
              <Text size="xs" c="dimmed">
                of {stats.totalCapacity}T capacity
              </Text>
            </Group>
            <Group gap="xs">
              <LegendDot color="cyan" label="Container" />
              <LegendDot color="orange" label="Bulk" />
              <LegendDot color="gray" label="Empty" />
            </Group>
          </Group>
        </Group>

        {/* Locomotive pull gauge */}
        {stats.pullUtil != null ? (
          <Box
            p="sm"
            style={{
              borderRadius: 12,
              background: "linear-gradient(135deg, var(--mantine-color-edr-green-0), #F2FBF7)",
              border: "1px solid var(--mantine-color-edr-green-1)",
            }}
          >
            <Group justify="space-between" mb={6}>
              <Group gap={6} wrap="nowrap">
                <Gauge size={14} color={freightBrand.primary} />
                <Text size="xs" fw={700} c="edr-green.8">
                  Locomotive load · {stats.totalWeight}T of {locomotive?.maxPullWeightTons}T
                </Text>
              </Group>
              <Text size="sm" fw={800} c={stats.pullUtil > 95 ? "red.7" : "edr-green.7"}>
                {stats.pullUtil}%
              </Text>
            </Group>
            <Progress
              value={stats.pullUtil}
              size="md"
              radius="xl"
              striped={stats.pullUtil > 95}
              animated={stats.pullUtil > 95}
              color={stats.pullUtil > 95 ? "red" : stats.pullUtil > 80 ? "yellow" : "edr-green"}
            />
          </Box>
        ) : null}

        {/* The train */}
        <Box ref={ref} style={{ width: "100%" }}>
          <Stack gap={0}>
            {rows.map((row, rowIndex) => {
              const reversed = rowIndex % 2 === 1;
              const isLast = rowIndex === rows.length - 1;
              // side where this row's track ends / turns down to the next row
              const turnSide: "left" | "right" = rowIndex % 2 === 0 ? "right" : "left";
              return (
                <Box key={rowIndex}>
                  <Box style={{ position: "relative", paddingBottom: 10 }}>
                    <TrackBed />
                    <Group
                      gap={0}
                      wrap="nowrap"
                      justify="flex-start"
                      style={{
                        flexDirection: reversed ? "row-reverse" : "row",
                        position: "relative",
                      }}
                    >
                      {row.map((car, carIndex) => (
                        <Group key={carIndex} gap={0} wrap="nowrap" style={{ flexDirection: reversed ? "row-reverse" : "row" }}>
                          {carIndex > 0 ? <Coupler /> : null}
                          {car.kind === "loco" ? (
                            locomotive ? (
                              <LocomotiveCar
                                code={locomotive.code ?? "LOCO"}
                                name={locomotive.name}
                                maxPullWeightTons={locomotive.maxPullWeightTons}
                              />
                            ) : null
                          ) : (
                            <WagonCar wagon={car.w} />
                          )}
                        </Group>
                      ))}
                    </Group>
                  </Box>

                  {/* serpentine turn connector to the next row */}
                  {!isLast ? (
                    <Box style={{ position: "relative", height: 16 }}>
                      <Box
                        style={{
                          position: "absolute",
                          top: -10,
                          height: 26,
                          width: 22,
                          borderBottom: "4px solid var(--mantine-color-gray-4)",
                          ...(turnSide === "right"
                            ? {
                                right: 4,
                                borderRight: "4px solid var(--mantine-color-gray-4)",
                                borderBottomRightRadius: 16,
                              }
                            : {
                                left: 4,
                                borderLeft: "4px solid var(--mantine-color-gray-4)",
                                borderBottomLeftRadius: 16,
                              }),
                        }}
                      />
                    </Box>
                  ) : null}
                </Box>
              );
            })}
          </Stack>
        </Box>
      </Stack>
    </Paper>
  );
}

function LegendDot({ color, label }: { color: string; label: string }) {
  return (
    <Group gap={5} wrap="nowrap">
      <Box
        style={{
          width: 10,
          height: 10,
          borderRadius: 3,
          background:
            color === "gray"
              ? "var(--mantine-color-gray-2)"
              : `var(--mantine-color-${color}-5)`,
          border: color === "gray" ? "1.5px dashed var(--mantine-color-gray-4)" : "none",
        }}
      />
      <Text size="xs" c="dimmed">
        {label}
      </Text>
    </Group>
  );
}
