import {
  Alert,
  Badge,
  Button,
  Card,
  Grid,
  Group,
  Menu,
  Modal,
  Progress,
  Stack,
  Text,
} from "@mantine/core";
import { useMutation, useQuery } from "@tanstack/react-query";
import { isAxiosError } from "axios";
import {
  AlertTriangle,
  CalendarClock,
  MapPin,
  MoreHorizontal,
  Power,
  PowerOff,
  Replace,
  Ruler,
  Trash2,
  Train as TrainIcon,
  TrainFront,
  Weight,
} from "lucide-react";
import { useState } from "react";
import { useNavigate, useParams } from "react-router-dom";

import AvailableWagonsPanel from "@/components/trainBuilder/AvailableWagonsPanel";
import ChangeLocomotivesModal from "@/components/trainBuilder/ChangeLocomotivesModal";
import ChangeYardModal from "@/components/trainBuilder/ChangeYardModal";
import ConsistWagonList from "@/components/trainBuilder/ConsistWagonList";
import {
  directionColor,
  locomotiveStatusColor,
  locomotiveStatusLabel,
  trainStatusColor,
  trainStatusLabel,
  UNFIT_LOCOMOTIVE_STATUSES,
} from "@/components/trainBuilder/trainStatus";
import { TrainCompositionDiagram } from "@/components/trainScheduling/TrainCompositionDiagram";
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import { api } from "@/services/api";
import { useAuth } from "@/auth/useAuth";
import { canFleetAction, FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
import { useToast } from "@/hooks/use-toast";

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

/** Utilization bar color: green while safe, amber when close, red when over. */
const utilizationColor = (pct: number | null) => {
  if (pct == null) return "gray";
  if (pct > 100) return "red";
  if (pct > 85) return "yellow";
  return "edr-green";
};

/**
 * Train Builder workspace for one train: the visual consist, the wagon yard
 * panel, and the locomotive set — everything needed to (re)compose the train.
 */
export default function TrainBuilderDetailPage() {
  const { id = "" } = useParams();
  const navigate = useNavigate();
  const { toast } = useToast();
  const [locoModalOpen, setLocoModalOpen] = useState(false);
  const [yardModalOpen, setYardModalOpen] = useState(false);
  const [disbandOpen, setDisbandOpen] = useState(false);
  const [deactivateOpen, setDeactivateOpen] = useState(false);
  const { user } = useAuth();
  const canUpdate = canFleetAction(user, "trains", "update");
  const canDelete = canFleetAction(user, "trains", "delete");
  const canAssign =
    hasPermission(user, FREIGHT_PERMS.trains.assignWagons) ||
    hasPermission(user, FREIGHT_PERMS.fleet.manage);

  const compositionQuery = useQuery(
    api.trainBuilder.composition.queryOptions({ input: { id }, enabled: Boolean(id) }),
  );
  const assignWagons = useMutation(api.trainBuilder.assignWagons.mutationOptions());
  const removeWagon = useMutation(api.trainBuilder.removeWagon.mutationOptions());
  const maintenanceWagon = useMutation(
    api.trainBuilder.sendWagonToMaintenance.mutationOptions(),
  );
  const reorderWagons = useMutation(api.trainBuilder.reorderWagons.mutationOptions());
  const disband = useMutation(api.trainBuilder.disband.mutationOptions());
  const deactivate = useMutation(api.trainBuilder.deactivate.mutationOptions());
  const activate = useMutation(api.trainBuilder.activate.mutationOptions());

  const composition = compositionQuery.data;
  const busy =
    assignWagons.isPending ||
    removeWagon.isPending ||
    maintenanceWagon.isPending ||
    reorderWagons.isPending;

  const withToast = async (action: () => Promise<unknown>, failTitle: string) => {
    try {
      await action();
    } catch (err) {
      toast({
        title: failTitle,
        description: parseError(err, "Something went wrong"),
        variant: "destructive",
      });
    }
  };

  if (compositionQuery.isLoading) {
    return (
      <PageContainer>
        <Text py="xl" ta="center" c="dimmed">
          Loading train…
        </Text>
      </PageContainer>
    );
  }

  if (compositionQuery.isError || !composition) {
    return (
      <PageContainer>
        <Alert color="red" icon={<AlertTriangle size={16} />}>
          Failed to load this train.{" "}
          <Button variant="subtle" size="compact-sm" onClick={() => compositionQuery.refetch()}>
            Retry
          </Button>
        </Alert>
      </PageContainer>
    );
  }

  const { totals } = composition;
  const yard = composition.currentYard;
  const blockingLocomotives = composition.locomotives.filter((loco) =>
    UNFIT_LOCOMOTIVE_STATUSES.has(loco.status),
  );

  return (
    <PageContainer>
      <PageHeader
        title={`Train ${composition.code}`}
        subtitle={
          composition.trainName
            ? `${composition.trainName} · built in ${yard?.label ?? "unknown yard"}`
            : `Built in ${yard?.label ?? "unknown yard"}`
        }
        backTo="/dashboard/train-builder"
        meta={
          <Group gap="xs">
            <Badge color={trainStatusColor(composition.status)} variant="light">
              {trainStatusLabel(composition.status)}
            </Badge>
            <Badge color="blue" variant="light" ff="monospace">
              IMP {composition.importTrainNumber ?? "—"}
            </Badge>
            <Badge color="orange" variant="light" ff="monospace">
              EXP {composition.exportTrainNumber ?? "—"}
            </Badge>
          </Group>
        }
        action={
          canUpdate || canDelete ? (
            <Menu position="bottom-end" withinPortal shadow="md" width={220}>
              <Menu.Target>
                <Button variant="default" rightSection={<MoreHorizontal size={16} />}>
                  Actions
                </Button>
              </Menu.Target>
              <Menu.Dropdown>
                {canUpdate ? (
                  <>
                    <Menu.Item
                      leftSection={<Replace size={15} />}
                      disabled={!composition.editable}
                      onClick={() => setLocoModalOpen(true)}
                    >
                      Change locomotives
                    </Menu.Item>
                    <Menu.Item
                      leftSection={<MapPin size={15} />}
                      disabled={!composition.editable}
                      onClick={() => setYardModalOpen(true)}
                    >
                      Change yard
                    </Menu.Item>
                    {composition.status === "DEACTIVATED" ? (
                      <Menu.Item
                        leftSection={<Power size={15} />}
                        disabled={blockingLocomotives.length > 0}
                        onClick={() =>
                          void withToast(async () => {
                            await activate.mutateAsync(composition.id);
                            toast({ title: `Train ${composition.code} reactivated` });
                          }, "Could not reactivate train")
                        }
                      >
                        Reactivate train
                      </Menu.Item>
                    ) : (
                      <Menu.Item
                        leftSection={<PowerOff size={15} />}
                        disabled={composition.activeSchedules.length > 0}
                        onClick={() => setDeactivateOpen(true)}
                      >
                        Deactivate train
                      </Menu.Item>
                    )}
                  </>
                ) : null}
                {canDelete ? (
                  <Menu.Item
                    color="red"
                    leftSection={<Trash2 size={15} />}
                    disabled={composition.activeSchedules.length > 0}
                    onClick={() => setDisbandOpen(true)}
                  >
                    Disband train
                  </Menu.Item>
                ) : null}
              </Menu.Dropdown>
            </Menu>
          ) : undefined
        }
      />

      <KpiStrip
        items={[
          { label: "Locomotives", value: composition.locomotives.length, icon: TrainFront },
          { label: "Wagons", value: totals.wagonCount, icon: TrainIcon },
          {
            label: "Tare weight / haul limit",
            value: `${totals.totalTareTons}T of ${totals.maxPullWeightTons}T`,
            icon: Weight,
          },
          {
            label: "Length / limit",
            value: `${totals.totalLengthMeters}m / ${totals.maxTrainLengthMeters}m`,
            icon: Ruler,
          },
        ]}
      />

      {!composition.editable ? (
        <Alert color="yellow" icon={<AlertTriangle size={16} />}>
          This train is out on a dispatched run — its composition is frozen until arrival.
        </Alert>
      ) : null}

      {composition.status === "DEACTIVATED" && blockingLocomotives.length > 0 ? (
        <Alert color="red" icon={<AlertTriangle size={16} />}>
          <Stack gap="xs">
            <Text size="sm">
              Cannot reactivate — {blockingLocomotives.length > 1 ? "these locomotives are" : "this locomotive is"}{" "}
              not fit for service:{" "}
              {blockingLocomotives.map((loco, i) => (
                <span key={loco.id}>
                  {i > 0 ? ", " : ""}
                  <Text span fw={600} ff="monospace">
                    {loco.code}
                  </Text>{" "}
                  ({locomotiveStatusLabel(loco.status)})
                </span>
              ))}
              .
            </Text>
            <Group gap="xs">
              {canUpdate ? (
                <Button
                  size="compact-sm"
                  variant="light"
                  color="red"
                  leftSection={<Replace size={14} />}
                  disabled={!composition.editable}
                  onClick={() => setLocoModalOpen(true)}
                >
                  Detach & replace locomotives
                </Button>
              ) : null}
              <Button
                size="compact-sm"
                variant="subtle"
                onClick={() => navigate(`/dashboard/locomotives`)}
              >
                Go to locomotives
              </Button>
            </Group>
          </Stack>
        </Alert>
      ) : null}

      <Group gap="xs">
        {composition.locomotives.map((loco) => (
          <Badge
            key={loco.id}
            variant="light"
            color={locomotiveStatusColor(loco.status)}
            leftSection={<TrainFront size={12} />}
          >
            {loco.code} · {locomotiveStatusLabel(loco.status)}
          </Badge>
        ))}
      </Group>

      <Stack gap="sm">
        <TrainCompositionDiagram
          locomotives={composition.locomotives.map((loco) => ({
            code: loco.code,
            name: loco.name,
            maxPullWeightTons: loco.maxPullWeightTons,
          }))}
          wagons={composition.wagons.map((wagon, index) => ({
            sequenceNo: wagon.sequenceNumber ?? index + 1,
            capacityTons: wagon.wagonType?.capacityTons ?? 0,
            // No bookings at build time — wagons ride empty until allocation.
            assignedWeightTons: 0,
            tareWeightTons: wagon.wagonType?.tareWeightTons ?? 0,
            wagonTypeCode: wagon.wagonType?.code ?? null,
            physicalWagonNumber: wagon.wagonNumber,
            allocations: [],
          }))}
          trainNumber={composition.code}
          totalLengthMeters={totals.totalLengthMeters}
        />
        <Card>
          <Grid gap="lg">
            <Grid.Col span={{ base: 12, sm: 6 }}>
              <UtilizationBar label="Length utilization" pct={totals.lengthUtilizationPct} />
            </Grid.Col>
            <Grid.Col span={{ base: 12, sm: 6 }}>
              <Text size="xs" c="dimmed" mt={4}>
                The real weight check happens at allocation: booked cargo weight plus
                wagon tare (gross) must stay within the locomotives' haul limit.
              </Text>
            </Grid.Col>
          </Grid>
        </Card>
      </Stack>

      <Grid gap="lg" align="stretch">
        {composition.editable && canAssign ? (
          <Grid.Col span={{ base: 12, md: 5 }}>
            <Card h="100%">
              <Stack gap="sm">
                <Text fw={600}>Available wagons — {yard?.label ?? "yard"}</Text>
                <Text size="xs" c="dimmed">
                  Only AVAILABLE wagons standing in the train's own yard can be coupled.
                </Text>
                <AvailableWagonsPanel
                  yardId={yard?.id ?? ""}
                  yardLabel={yard?.label}
                  exportTrainNumber={composition.exportTrainNumber}
                  importTrainNumber={composition.importTrainNumber}
                  assigning={assignWagons.isPending}
                  onAssign={(wagonIds) =>
                    void withToast(
                      () => assignWagons.mutateAsync({ id: composition.id, wagonIds }),
                      "Could not add wagons",
                    )
                  }
                />
              </Stack>
            </Card>
          </Grid.Col>
        ) : null}
        <Grid.Col span={{ base: 12, md: composition.editable && canAssign ? 7 : 12 }}>
          <Card h="100%">
            <Stack gap="sm">
              <Text fw={600}>Wagon order</Text>
              <Text size="xs" c="dimmed">
                Drag to reorder — position 1 couples right behind the locomotives.
              </Text>
              <ConsistWagonList
                wagons={composition.wagons}
                editable={composition.editable && canAssign}
                busy={busy}
                onReorder={(wagonIds) =>
                  void withToast(
                    () => reorderWagons.mutateAsync({ id: composition.id, wagonIds }),
                    "Could not reorder wagons",
                  )
                }
                onRemove={(wagonId) =>
                  void withToast(
                    () => removeWagon.mutateAsync({ id: composition.id, wagonId }),
                    "Could not detach wagon",
                  )
                }
                onMaintenance={(wagonId) =>
                  void withToast(
                    () => maintenanceWagon.mutateAsync({ id: composition.id, wagonId }),
                    "Could not send wagon to maintenance",
                  )
                }
              />
            </Stack>
          </Card>
        </Grid.Col>
      </Grid>

      {composition.activeSchedules.length ? (
        <Card>
          <Stack gap="sm">
            <Text fw={600}>Upcoming runs</Text>
            {composition.activeSchedules.map((schedule) => (
              <Group key={schedule.id} justify="space-between">
                <Group gap="sm">
                  <CalendarClock size={15} color="var(--mantine-color-gray-6)" />
                  <Text size="sm" ff="monospace" fw={600}>
                    {schedule.reference ?? schedule.id.slice(0, 8)}
                  </Text>
                  {schedule.trainNumber ? (
                    <Text size="sm" ff="monospace" fw={700}>
                      {schedule.trainNumber}
                    </Text>
                  ) : null}
                  {schedule.direction ? (
                    <Badge size="sm" variant="light" color={directionColor(schedule.direction)}>
                      {schedule.direction}
                    </Badge>
                  ) : null}
                  <Badge size="sm" variant="light">
                    {schedule.status}
                  </Badge>
                </Group>
                <Button
                  variant="subtle"
                  size="compact-sm"
                  onClick={() =>
                    navigate(`/dashboard/operations/train-scheduling-v2/${schedule.id}`)
                  }
                >
                  Open schedule
                </Button>
              </Group>
            ))}
          </Stack>
        </Card>
      ) : null}

      <ChangeLocomotivesModal
        composition={composition}
        opened={locoModalOpen}
        onClose={() => setLocoModalOpen(false)}
      />

      <ChangeYardModal
        composition={composition}
        opened={yardModalOpen}
        onClose={() => setYardModalOpen(false)}
      />

      <Modal
        opened={deactivateOpen}
        onClose={() => setDeactivateOpen(false)}
        title={<Text fw={600}>Deactivate train {composition.code}?</Text>}
        radius="lg"
        centered
      >
        <Stack gap="md">
          <Text size="sm" c="dimmed">
            The train is parked and cannot be picked for new schedules until it is
            reactivated. Its locomotives and wagons stay coupled.
          </Text>
          <Group justify="flex-end">
            <Button variant="default" onClick={() => setDeactivateOpen(false)}>
              Keep active
            </Button>
            <Button
              color="gray"
              loading={deactivate.isPending}
              onClick={() =>
                void withToast(async () => {
                  await deactivate.mutateAsync(composition.id);
                  toast({ title: `Train ${composition.code} deactivated` });
                  setDeactivateOpen(false);
                }, "Could not deactivate train")
              }
            >
              Deactivate
            </Button>
          </Group>
        </Stack>
      </Modal>

      <Modal
        opened={disbandOpen}
        onClose={() => setDisbandOpen(false)}
        title={<Text fw={600}>Disband train {composition.code}?</Text>}
        radius="lg"
        centered
      >
        <Stack gap="md">
          <Text size="sm" c="dimmed">
            All wagons and locomotives are released back to{" "}
            {yard?.label ?? "their yard"} and the train is deleted. This cannot be undone.
          </Text>
          <Group justify="flex-end">
            <Button variant="default" onClick={() => setDisbandOpen(false)}>
              Keep train
            </Button>
            <Button
              color="red"
              loading={disband.isPending}
              onClick={() =>
                void withToast(async () => {
                  await disband.mutateAsync(composition.id);
                  toast({ title: `Train ${composition.code} disbanded` });
                  navigate("/dashboard/train-builder");
                }, "Could not disband train")
              }
            >
              Disband
            </Button>
          </Group>
        </Stack>
      </Modal>
    </PageContainer>
  );
}

function UtilizationBar({ label, pct }: { label: string; pct: number | null }) {
  return (
    <Stack gap={4}>
      <Group justify="space-between">
        <Text size="xs" c="dimmed">
          {label}
        </Text>
        <Text size="xs" fw={600} c={pct != null && pct > 100 ? "red" : undefined}>
          {pct != null ? `${pct}%` : "—"}
        </Text>
      </Group>
      <Progress
        value={Math.min(pct ?? 0, 100)}
        color={utilizationColor(pct)}
        size="sm"
        radius="xl"
      />
    </Stack>
  );
}
