import { Freight } from "@edr/types";
import {
  Badge,
  Button,
  Checkbox,
  Group,
  ScrollArea,
  Select,
  Stack,
  Text,
  TextInput,
} from "@mantine/core";
import { useQuery } from "@tanstack/react-query";
import { Plus, Search } from "lucide-react";
import { useMemo, useState } from "react";

import { api } from "@/services/api";

/**
 * AVAILABLE wagons standing in the train's own yard — the only ones that can
 * be coupled. Pick any number and append them to the consist.
 */
export default function AvailableWagonsPanel({
  yardId,
  yardLabel,
  onAssign,
  assigning,
  exportTrainNumber,
  importTrainNumber,
}: AvailableWagonsPanelProps) {
  const [search, setSearch] = useState("");
  const [typeFilter, setTypeFilter] = useState<string>("ALL");
  const [runOnly, setRunOnly] = useState(false);
  const [selected, setSelected] = useState<string[]>([]);

  // The train's own run, e.g. "8001-8002" — only offered when the train has one.
  const runLabel = exportTrainNumber
    ? `${exportTrainNumber}${importTrainNumber ? `-${importTrainNumber}` : ""}`
    : null;

  const wagonsQuery = useQuery(
    api.wagons.list.queryOptions({
      input: {
        filters: { status: Freight.WagonStatus.Available, currentYardId: yardId },
      },
      enabled: Boolean(yardId),
    }),
  );

  const wagons = useMemo(() => {
    const q = search.trim().toLowerCase();
    return (wagonsQuery.data ?? []).filter((wagon) => {
      if (typeFilter !== "ALL" && wagon.wagonTypeId !== typeFilter) return false;
      // Rostered to this train's run — match on the export run, which fixes the
      // import run anyway.
      if (runOnly && wagon.exportTrainNumber !== exportTrainNumber) return false;
      if (q && !wagon.wagonNumber.toLowerCase().includes(q)) return false;
      return true;
    });
  }, [wagonsQuery.data, search, typeFilter, runOnly, exportTrainNumber]);

  const runMatchCount = useMemo(
    () =>
      exportTrainNumber
        ? (wagonsQuery.data ?? []).filter(
            (w) => w.exportTrainNumber === exportTrainNumber,
          ).length
        : 0,
    [wagonsQuery.data, exportTrainNumber],
  );

  const typeOptions = useMemo(() => {
    const byId = new Map<string, string>();
    for (const wagon of wagonsQuery.data ?? []) {
      if (wagon.wagonType) {
        // e.g. "Flat wagon (NW5)" — name with its type code.
        byId.set(
          wagon.wagonType.id,
          wagon.wagonType.code
            ? `${wagon.wagonType.name} (${wagon.wagonType.code})`
            : wagon.wagonType.name,
        );
      }
    }
    return [
      { value: "ALL", label: "All types" },
      ...[...byId.entries()].map(([value, label]) => ({ value, label })),
    ];
  }, [wagonsQuery.data]);

  const toggle = (wagonId: string, checked: boolean) => {
    setSelected((prev) =>
      checked ? [...prev, wagonId] : prev.filter((id) => id !== wagonId),
    );
  };

  const allSelected =
    wagons.length > 0 && wagons.every((w) => selected.includes(w.id));
  const someSelected = wagons.some((w) => selected.includes(w.id));

  const toggleAll = (checked: boolean) => {
    setSelected((prev) => {
      if (checked) {
        const ids = new Set(prev);
        wagons.forEach((w) => ids.add(w.id));
        return [...ids];
      }
      const visible = new Set(wagons.map((w) => w.id));
      return prev.filter((id) => !visible.has(id));
    });
  };

  const handleAssign = () => {
    if (!selected.length) return;
    onAssign(selected);
    setSelected([]);
  };

  return (
    <Stack gap="sm">
      <Group gap="xs" grow>
        <TextInput
          size="sm"
          placeholder="Search wagon number…"
          leftSection={<Search size={14} />}
          value={search}
          onChange={(e) => setSearch(e.currentTarget.value)}
        />
        <Select
          size="sm"
          data={typeOptions}
          value={typeFilter}
          onChange={(v) => setTypeFilter(v ?? "ALL")}
        />
      </Group>

      {runLabel ? (
        <Checkbox
          size="sm"
          label={`Only wagons on this train's run (${runLabel}) — ${runMatchCount} here`}
          checked={runOnly}
          onChange={(e) => setRunOnly(e.currentTarget.checked)}
        />
      ) : null}

      {wagons.length ? (
        <Checkbox
          size="sm"
          label={`Select all (${wagons.length})`}
          checked={allSelected}
          indeterminate={!allSelected && someSelected}
          onChange={(e) => toggleAll(e.currentTarget.checked)}
        />
      ) : null}

      <ScrollArea.Autosize mah={380} type="auto">
        <Stack gap={6}>
          {wagonsQuery.isLoading ? (
            <Text py="md" ta="center" c="dimmed" size="sm">
              Loading wagons…
            </Text>
          ) : !wagons.length ? (
            <Text py="md" ta="center" c="dimmed" size="sm">
              No available wagons in {yardLabel ?? "this yard"}
            </Text>
          ) : (
            wagons.map((wagon) => (
              <Group
                key={wagon.id}
                gap="sm"
                wrap="nowrap"
                p="xs"
                style={{
                  border: "1px solid var(--mantine-color-gray-2)",
                  borderRadius: "var(--mantine-radius-md)",
                }}
              >
                <Checkbox
                  size="sm"
                  checked={selected.includes(wagon.id)}
                  onChange={(e) => toggle(wagon.id, e.currentTarget.checked)}
                  aria-label={`Select wagon ${wagon.wagonNumber}`}
                />
                <Stack gap={0} style={{ flex: 1, minWidth: 0 }}>
                  <Group gap={6} wrap="nowrap">
                    <Text size="sm" fw={600} ff="monospace" truncate>
                      {wagon.wagonNumber}
                    </Text>
                    {wagon.exportTrainNumber ? (
                      <Badge
                        size="xs"
                        radius="sm"
                        variant="light"
                        color={
                          wagon.exportTrainNumber === exportTrainNumber ? "edr-green" : "gray"
                        }
                      >
                        {wagon.exportTrainNumber}
                        {wagon.importTrainNumber ? `-${wagon.importTrainNumber}` : ""}
                      </Badge>
                    ) : null}
                  </Group>
                  <Text size="xs" c="dimmed" truncate>
                    {wagon.wagonType
                      ? `${wagon.wagonType.name} · ${wagon.wagonType.capacityTons ?? "—"}T cap`
                      : "Unknown type"}
                  </Text>
                </Stack>
              </Group>
            ))
          )}
        </Stack>
      </ScrollArea.Autosize>

      <Button
        leftSection={<Plus size={16} />}
        disabled={!selected.length}
        loading={assigning}
        onClick={handleAssign}
      >
        Add {selected.length ? `${selected.length} wagon${selected.length > 1 ? "s" : ""}` : "wagons"} to consist
      </Button>
    </Stack>
  );
}

export interface AvailableWagonsPanelProps {
  yardId: string;
  yardLabel?: string | null;
  onAssign: (wagonIds: string[]) => void;
  assigning: boolean;
  /** This train's odd EXPORT run — drives the "only this run" filter. */
  exportTrainNumber?: string | null;
  /** This train's even IMPORT run — label only; the export run does the matching. */
  importTrainNumber?: string | null;
}
