import { useCallback, useEffect, useMemo, useState } from "react";
import {
  Alert,
  Badge,
  Button,
  Group,
  Paper,
  Progress,
  Select,
  SimpleGrid,
  Stack,
  Text,
  ThemeIcon,
} from "@mantine/core";
import { AlertTriangle, Link2, Wand2 } from "lucide-react";

import { Freight } from "@edr/types";

import type { PinWagonAssignment, TrainScheduleDetail } from "@/types/trainScheduling";
import type { Wagon } from "@/services/wagon.service";
import { wagonMatchesScheduleOrigin } from "@/utils/wagonAvailability";

import { autoFillWagonAssignments, countFilledSlots } from "./pinWagons.util";

export function PinWagonsForm({
  schedule,
  availableWagons,
  isSubmitting,
  onSubmit,
  autoFillOnMount = true,
}: {
  schedule: TrainScheduleDetail;
  availableWagons: Wagon[];
  isSubmitting?: boolean;
  onSubmit: (assignments: PinWagonAssignment[]) => void;
  autoFillOnMount?: boolean;
}) {
  const originYardId = schedule.originStation?.id;
  const slots = schedule.trainSet?.wagons ?? [];
  const [assignments, setAssignments] = useState<Record<string, string>>({});

  const wagonOptionsByType = useMemo(() => {
    const map = new Map<string, Array<{ value: string; label: string }>>();
    for (const wagon of availableWagons) {
      const isPinnedOnSlot = slots.some((s) => s.physicalWagonId === wagon.id);
      if (
        !wagonMatchesScheduleOrigin(wagon, originYardId, {
          allowPinned: isPinnedOnSlot,
        })
      ) {
        continue;
      }
      if (wagon.status !== Freight.WagonStatus.Available && !isPinnedOnSlot) {
        continue;
      }
      const typeId = wagon.wagonTypeId;
      const list = map.get(typeId) ?? [];
      list.push({ value: wagon.id, label: wagon.wagonNumber });
      map.set(typeId, list);
    }
    return map;
  }, [availableWagons, originYardId, slots]);

  const runAutoFill = useCallback(
    (preserveManual = false) => {
      const existing = preserveManual ? assignments : {};
      setAssignments(autoFillWagonAssignments(slots, wagonOptionsByType, existing));
    },
    [assignments, slots, wagonOptionsByType],
  );

  useEffect(() => {
    if (!autoFillOnMount || !slots.length) return;
    setAssignments(autoFillWagonAssignments(slots, wagonOptionsByType));
  }, [schedule.id, slots, wagonOptionsByType, autoFillOnMount]);

  const fillStats = useMemo(
    () => countFilledSlots(slots, assignments),
    [slots, assignments],
  );

  const progress =
    fillStats.total > 0 ? Math.round((fillStats.filled / fillStats.total) * 100) : 0;

  const handleSubmit = () => {
    const payload: PinWagonAssignment[] = Object.entries(assignments)
      .filter(([, wagonId]) => Boolean(wagonId))
      .map(([trainSetWagonId, physicalWagonId]) => ({ trainSetWagonId, physicalWagonId }));
    onSubmit(payload);
  };

  if (!slots.length) {
    return (
      <Text size="sm" c="dimmed">
        Assign bookings first to create wagon slots.
      </Text>
    );
  }

  return (
    <Stack gap="md">
      <Paper p="md" radius="xl" withBorder>
        <Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
          <Stack gap={4}>
            <Group gap="xs">
              <Link2 size={18} />
              <Text fw={600} size="sm">
                Pin physical wagons
              </Text>
            </Group>
            <Text size="xs" c="dimmed">
              Match each train slot to a fleet wagon. Slots are auto-filled when possible.
            </Text>
          </Stack>
          <Button
            variant="light"
            size="compact-sm"
            leftSection={<Wand2 size={14} />}
            onClick={() => runAutoFill(false)}
          >
            Auto-fill all slots
          </Button>
        </Group>

        <Stack gap={6} mt="md">
          <Group justify="space-between">
            <Text size="xs" c="dimmed">
              {fillStats.filled} of {fillStats.total} slots filled
            </Text>
            <Badge variant="light" color={progress === 100 ? "teal" : "yellow"}>
              {progress}%
            </Badge>
          </Group>
          <Progress value={progress} size="sm" radius="xl" color={progress === 100 ? "teal" : "yellow"} />
        </Stack>
      </Paper>

      {fillStats.unfilledSlotNumbers.length > 0 ? (
        <Alert
          color="yellow"
          variant="light"
          radius="lg"
          icon={<AlertTriangle size={16} />}
          title="Some slots could not be auto-filled"
        >
          <Text size="sm">
            No matching fleet wagon for slot
            {fillStats.unfilledSlotNumbers.length === 1 ? "" : "s"} #
            {fillStats.unfilledSlotNumbers.join(", #")}. Select manually or add wagons to the fleet.
          </Text>
        </Alert>
      ) : null}

      <SimpleGrid cols={{ base: 1, md: 2 }} spacing="md">
        {slots.map((slot) => {
          const typeId = slot.wagonType?.id ?? "";
          const options =
            wagonOptionsByType.get(typeId) ??
            availableWagons.map((w) => ({
              value: w.id,
              label: w.wagonNumber,
            }));

          return (
            <Paper key={slot.id} p="md" radius="lg" withBorder>
              <Group align="flex-end" wrap="nowrap" gap="md">
                <Stack gap={2} style={{ minWidth: 90 }}>
                  <Group gap={6}>
                    <ThemeIcon size="sm" radius="md" variant="light" color="teal">
                      <Text size="xs" fw={700}>
                        {slot.sequenceNo}
                      </Text>
                    </ThemeIcon>
                    <Text size="sm" fw={600}>
                      Slot #{slot.sequenceNo}
                    </Text>
                  </Group>
                  <Text size="xs" c="dimmed">
                    {slot.wagonType?.code ?? "—"} · {slot.capacityTons}T
                  </Text>
                </Stack>
                <Select
                  style={{ flex: 1 }}
                  placeholder="Select physical wagon"
                  data={options}
                  value={assignments[slot.id] ?? null}
                  onChange={(value) =>
                    setAssignments((current) => ({
                      ...current,
                      [slot.id]: value ?? "",
                    }))
                  }
                  searchable
                />
              </Group>
            </Paper>
          );
        })}
      </SimpleGrid>

      <Group justify="flex-end">
        <Button color="teal" loading={isSubmitting} onClick={handleSubmit}>
          Pin wagons
        </Button>
      </Group>
    </Stack>
  );
}
