import { Freight } from "@edr/types";
import {
  Badge,
  Button,
  Card,
  Checkbox,
  Divider,
  Group,
  Loader,
  Modal,
  ScrollArea,
  Stack,
  Switch,
  Tabs,
  Text,
  ThemeIcon,
} from "@mantine/core";
import { useMutation, useQuery } from "@tanstack/react-query";
import {
  ArrowRight,
  ChevronLeft,
  History,
  Inbox,
  PackageCheck,
  Warehouse,
  X,
} from "lucide-react";
import { useMemo, useState } from "react";

import { api } from "@/services/api";
import { useAuth } from "@/auth/useAuth";
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
import { useToast } from "@/hooks/use-toast";
import type {
  WagonMovementRecord,
  WagonTransferRequest,
} from "@/services/wagon.service";

export interface WagonTransferRequestsModalProps {
  opened: boolean;
  onClose: () => void;
}

const PENDING = Freight.WagonTransferRequestStatus.Pending;
const AVAILABLE = Freight.WagonStatus.Available;

const yardLabel = (y?: { label?: string; code?: string } | null) =>
  y?.label || y?.code || "—";
const typeLabel = (t?: { code?: string; name?: string } | null) =>
  t ? `${t.code ?? ""}${t.name ? ` · ${t.name}` : ""}` : "—";

/** Requester → destination + type + count summary line, reused in list and picker. */
const RequestSummary = ({ r }: { r: WagonTransferRequest }) => (
  <Group gap={8} wrap="nowrap">
    <Text fw={600} size="sm" truncate>
      {yardLabel(r.fromYard)}
    </Text>
    <ArrowRight size={14} style={{ flexShrink: 0 }} />
    <Text fw={600} size="sm" truncate>
      {yardLabel(r.toYard)}
    </Text>
    <Badge variant="light" color="grape" radius="sm">
      {r.quantity}× {typeLabel(r.wagonType)}
    </Badge>
  </Group>
);

const STATUS_COLOR: Record<string, string> = {
  PENDING: "gray",
  FULFILLED: "teal",
  CANCELLED: "red",
};

const fmtDateTime = (iso: string) =>
  new Date(iso).toLocaleString("en-GB", {
    day: "numeric",
    month: "short",
    hour: "2-digit",
    minute: "2-digit",
    hour12: false,
  });

/**
 * Per-user transfer history. A staffer sees their OWN activity — the requests
 * they filed or fulfilled, and the individual wagons they moved. Holders of
 * `transfer_history_all` get an "All staff" toggle that widens the view; the
 * backend enforces the scope regardless of the toggle.
 */
function HistoryPanel({ opened }: { opened: boolean }) {
  const { user } = useAuth();
  const canSeeAll = hasPermission(
    user,
    FREIGHT_PERMS.wagons.transferHistoryAll,
  );
  const myId = (user as { id?: string } | null | undefined)?.id;
  const [allStaff, setAllStaff] = useState(false);
  const scopeAll = canSeeAll && allStaff;

  const mine = useQuery({
    ...api.wagonTransferRequests.history.queryOptions(),
    enabled: opened && !scopeAll,
  });
  const all = useQuery({
    ...api.wagonTransferRequests.historyAll.queryOptions({ input: {} }),
    enabled: opened && scopeAll,
  });
  const source = scopeAll ? all : mine;
  const requests = source.data?.requests ?? [];
  const movements: WagonMovementRecord[] = source.data?.movements ?? [];

  const roleBadge = (r: WagonTransferRequest) => {
    if (myId && r.fulfilledByUserId === myId)
      return (
        <Badge size="xs" variant="light" color="blue">
          fulfilled
        </Badge>
      );
    if (myId && r.requestedByUserId === myId)
      return (
        <Badge size="xs" variant="light" color="grape">
          requested
        </Badge>
      );
    return null;
  };

  return (
    <Stack gap="lg">
      {canSeeAll ? (
        <Group justify="flex-end">
          <Switch
            checked={allStaff}
            onChange={(e) => setAllStaff(e.currentTarget.checked)}
            label="All staff"
            color="edr-green"
          />
        </Group>
      ) : null}

      {source.isLoading ? (
        <Group justify="center" p="xl">
          <Loader />
        </Group>
      ) : (
        <>
          <div>
            <Text fw={700} size="sm" mb={8}>
              Requests{scopeAll ? "" : " you touched"}
            </Text>
            {requests.length === 0 ? (
              <Text size="sm" c="dimmed">
                No requests yet.
              </Text>
            ) : (
              <Stack gap={6}>
                {requests.map((r) => (
                  <Card key={r.id} withBorder radius="md" padding="xs">
                    <Group justify="space-between" wrap="nowrap">
                      <RequestSummary r={r} />
                      <Group gap={8} wrap="nowrap">
                        {roleBadge(r)}
                        <Badge
                          size="sm"
                          variant="light"
                          color={STATUS_COLOR[r.status] ?? "gray"}
                        >
                          {r.status.toLowerCase()}
                        </Badge>
                      </Group>
                    </Group>
                  </Card>
                ))}
              </Stack>
            )}
          </div>

          <Divider />

          <div>
            <Text fw={700} size="sm" mb={8}>
              Wagons moved
            </Text>
            {movements.length === 0 ? (
              <Text size="sm" c="dimmed">
                No wagon moves yet.
              </Text>
            ) : (
              <ScrollArea.Autosize mah={260}>
                <Stack gap={6}>
                  {movements.map((m) => (
                    <Card key={m.id} withBorder radius="md" padding="xs">
                      <Group justify="space-between" wrap="nowrap">
                        <Group gap={8} wrap="nowrap" style={{ minWidth: 0 }}>
                          <Text fw={600} size="sm">
                            {m.wagon?.wagonNumber ?? "Wagon"}
                          </Text>
                          <Text size="xs" c="dimmed" truncate>
                            {yardLabel(m.fromYard)} → {yardLabel(m.toYard)}
                          </Text>
                          {m.transferRequestId ? (
                            <Badge size="xs" variant="light" color="teal">
                              from request
                            </Badge>
                          ) : null}
                        </Group>
                        <Text size="xs" c="dimmed" style={{ flexShrink: 0 }}>
                          {fmtDateTime(m.occurredAt)}
                        </Text>
                      </Group>
                    </Card>
                  ))}
                </Stack>
              </ScrollArea.Autosize>
            )}
          </div>
        </>
      )}
    </Stack>
  );
}

/**
 * OCC fulfilment queue for wagon-transfer requests. Lists PENDING requests; open
 * one to hand-pick exactly the requested number of wagons from the source yard
 * (of the requested type) and execute the move, or cancel the request.
 * A second tab shows per-user transfer history.
 */
const WagonTransferRequestsModal = ({
  opened,
  onClose,
}: WagonTransferRequestsModalProps) => {
  const { toast } = useToast();
  const [tab, setTab] = useState<string | null>("queue");
  const [active, setActive] = useState<WagonTransferRequest | null>(null);
  const [picked, setPicked] = useState<Set<string>>(new Set());

  const { data: requests = [], isLoading } = useQuery({
    ...api.wagonTransferRequests.list.queryOptions({ input: { status: PENDING } }),
    enabled: opened,
  });

  // Available wagons of the requested type sitting in the request's source yard.
  const { data: wagons = [], isLoading: wagonsLoading } = useQuery({
    ...api.wagons.list.queryOptions({
      input: {
        filters: active
          ? {
              currentYardId: active.fromYardId,
              wagonTypeId: active.wagonTypeId,
              status: AVAILABLE,
            }
          : {},
      },
    }),
    enabled: opened && Boolean(active),
  });

  const fulfill = useMutation(api.wagonTransferRequests.fulfill.mutationOptions());
  const cancel = useMutation(api.wagonTransferRequests.cancel.mutationOptions());

  const showError = (err: unknown, fallback: string) => {
    const message =
      (err as { response?: { data?: { message?: string } } })?.response?.data
        ?.message ?? fallback;
    toast({ title: fallback, description: String(message), variant: "destructive" });
  };

  const openPicker = (r: WagonTransferRequest) => {
    setActive(r);
    setPicked(new Set());
  };
  const closePicker = () => {
    setActive(null);
    setPicked(new Set());
  };

  const toggle = (id: string) =>
    setPicked((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else if (active && next.size >= active.quantity) return prev; // cap at quantity
      else next.add(id);
      return next;
    });

  const need = active?.quantity ?? 0;
  const shortfall = active ? Math.max(0, need - wagons.length) : 0;

  const handleFulfill = async () => {
    if (!active || picked.size !== need) return;
    try {
      await fulfill.mutateAsync({ id: active.id, wagonIds: [...picked] });
      toast({
        title: `Transferred ${need} wagon(s) · ${yardLabel(active.fromYard)} → ${yardLabel(
          active.toYard,
        )}`,
      });
      closePicker();
    } catch (err) {
      showError(err, "Transfer failed");
    }
  };

  const handleCancel = async (r: WagonTransferRequest) => {
    try {
      await cancel.mutateAsync({ id: r.id });
      toast({ title: "Request cancelled" });
    } catch (err) {
      showError(err, "Cancel failed");
    }
  };

  const sortedWagons = useMemo(
    () => [...wagons].sort((a, b) => a.wagonNumber.localeCompare(b.wagonNumber)),
    [wagons],
  );

  return (
    <Modal
      opened={opened}
      onClose={onClose}
      size="min(760px, 96vw)"
      radius="lg"
      centered
      overlayProps={{ blur: 2 }}
      title={
        <Group gap="sm">
          <ThemeIcon variant="light" color="edr-green" radius="md" size="lg">
            <Inbox size={18} />
          </ThemeIcon>
          <div>
            <Text fw={700}>Wagon Transfer Requests</Text>
            <Text size="xs" c="dimmed">
              {active
                ? "Pick the wagons to move, then transfer"
                : "OCC queue — pick wagons and complete each move"}
            </Text>
          </div>
        </Group>
      }
    >
      <Tabs value={tab} onChange={setTab} keepMounted={false}>
        <Tabs.List mb="md">
          <Tabs.Tab value="queue" leftSection={<Inbox size={14} />}>
            Queue
          </Tabs.Tab>
          <Tabs.Tab value="history" leftSection={<History size={14} />}>
            History
          </Tabs.Tab>
        </Tabs.List>

        <Tabs.Panel value="queue">
      {!active ? (
        // ---- Pending queue ----
        isLoading ? (
          <Group justify="center" p="xl">
            <Loader />
          </Group>
        ) : requests.length === 0 ? (
          <Card withBorder radius="md" padding="xl">
            <Stack align="center" gap={6}>
              <ThemeIcon variant="light" color="gray" radius="xl" size={48}>
                <Inbox size={22} />
              </ThemeIcon>
              <Text fw={600}>No pending transfer requests</Text>
              <Text size="sm" c="dimmed" ta="center" maw={420}>
                When staff request a yard-to-yard wagon move, it appears here for
                you to fulfil.
              </Text>
            </Stack>
          </Card>
        ) : (
          <Stack gap="sm">
            {requests.map((r) => (
              <Card key={r.id} withBorder radius="md" padding="md">
                <Group justify="space-between" wrap="nowrap" align="flex-start">
                  <Stack gap={6} style={{ minWidth: 0 }}>
                    <RequestSummary r={r} />
                    {r.note ? (
                      <Text size="xs" c="dimmed">
                        “{r.note}”
                      </Text>
                    ) : null}
                  </Stack>
                  <Group gap={8} wrap="nowrap">
                    <Button
                      size="compact-sm"
                      variant="subtle"
                      color="gray"
                      leftSection={<X size={14} />}
                      loading={cancel.isPending}
                      onClick={() => handleCancel(r)}
                    >
                      Cancel
                    </Button>
                    <Button
                      size="compact-sm"
                      color="edr-green"
                      leftSection={<PackageCheck size={14} />}
                      onClick={() => openPicker(r)}
                    >
                      Fulfil
                    </Button>
                  </Group>
                </Group>
              </Card>
            ))}
          </Stack>
        )
      ) : (
        // ---- Wagon picker for the active request ----
        <Stack gap="md">
          <Card withBorder radius="md" padding="sm" bg="var(--mantine-color-gray-0)">
            <RequestSummary r={active} />
          </Card>

          <Group justify="space-between">
            <Text size="sm" fw={600}>
              Select wagons in {yardLabel(active.fromYard)}
            </Text>
            <Badge
              color={picked.size === need ? "teal" : "gray"}
              variant={picked.size === need ? "filled" : "light"}
            >
              {picked.size} / {need} selected
            </Badge>
          </Group>

          {wagonsLoading ? (
            <Group justify="center" p="lg">
              <Loader size="sm" />
            </Group>
          ) : sortedWagons.length === 0 ? (
            <Card withBorder radius="md" padding="lg">
              <Group gap={8} justify="center">
                <Warehouse size={16} />
                <Text size="sm" c="dimmed">
                  No available wagons of this type in {yardLabel(active.fromYard)}.
                </Text>
              </Group>
            </Card>
          ) : (
            <>
              {shortfall > 0 ? (
                <Text size="xs" c="orange.7">
                  Only {sortedWagons.length} available — {shortfall} short of the{" "}
                  {need} requested.
                </Text>
              ) : null}
              <ScrollArea.Autosize mah={320}>
                <Stack gap={6}>
                  {sortedWagons.map((w) => {
                    const checked = picked.has(w.id);
                    const atCap = !checked && picked.size >= need;
                    return (
                      <Card
                        key={w.id}
                        withBorder
                        radius="md"
                        padding="xs"
                        onClick={() => !atCap && toggle(w.id)}
                        style={{
                          cursor: atCap ? "not-allowed" : "pointer",
                          borderColor: checked
                            ? "var(--mantine-color-edr-green-4)"
                            : undefined,
                          opacity: atCap ? 0.55 : 1,
                        }}
                      >
                        <Group gap="sm" wrap="nowrap">
                          {/* Visual only — the Card's onClick owns the toggle so a
                              click on the box doesn't fire both and cancel out. */}
                          <Checkbox
                            checked={checked}
                            readOnly
                            disabled={atCap}
                            color="edr-green"
                            tabIndex={-1}
                            aria-hidden
                          />
                          <Text fw={600} size="sm">
                            {w.wagonNumber}
                          </Text>
                        </Group>
                      </Card>
                    );
                  })}
                </Stack>
              </ScrollArea.Autosize>
            </>
          )}

          <Divider />
          <Group justify="space-between">
            <Button
              variant="subtle"
              color="gray"
              leftSection={<ChevronLeft size={16} />}
              onClick={closePicker}
            >
              Back to queue
            </Button>
            <Button
              color="edr-green"
              leftSection={<PackageCheck size={16} />}
              loading={fulfill.isPending}
              disabled={picked.size !== need}
              onClick={handleFulfill}
            >
              Transfer {need} wagon{need === 1 ? "" : "s"}
            </Button>
          </Group>
        </Stack>
      )}
        </Tabs.Panel>

        <Tabs.Panel value="history">
          <HistoryPanel opened={opened} />
        </Tabs.Panel>
      </Tabs>
    </Modal>
  );
};

export default WagonTransferRequestsModal;
