import {
  Badge,
  Button,
  Card,
  Group,
  SegmentedControl,
  Skeleton,
  Stack,
  Switch,
  Text,
  ThemeIcon,
  Timeline,
  Tooltip,
} from "@mantine/core";
import { useQuery } from "@tanstack/react-query";
import {
  ArrowRight,
  ChevronLeft,
  ChevronRight,
  History,
  Inbox,
  Truck,
} from "lucide-react";
import { useState } from "react";

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

import {
  STATUS_META,
  TransferProgress,
  TransferStatusBadge,
  stripHtmlToText,
  wagonTypeLabel,
  yardLabel,
} from "./wagon-transfer-ui";

const fmtTime = (iso?: string | null) =>
  iso
    ? new Date(iso).toLocaleTimeString("en-GB", {
        hour: "2-digit",
        minute: "2-digit",
        hour12: false,
      })
    : "—";

/** "Today" / "Yesterday" / "Mon 12 Jul 2026" — the header of one timeline block. */
const dayLabel = (iso: string) => {
  const d = new Date(iso);
  const days = Math.round(
    (new Date().setHours(0, 0, 0, 0) - new Date(iso).setHours(0, 0, 0, 0)) /
      86_400_000,
  );
  if (days === 0) return "Today";
  if (days === 1) return "Yesterday";
  return d.toLocaleDateString("en-GB", {
    weekday: "short",
    day: "numeric",
    month: "short",
    year: "numeric",
  });
};

/** Bucket an already-DESC-sorted list into day blocks, order preserved. */
function groupByDay<T>(items: T[], at: (item: T) => string) {
  const groups: Array<{ key: string; label: string; items: T[] }> = [];
  for (const item of items) {
    const iso = at(item);
    const key = new Date(iso).toDateString();
    const last = groups[groups.length - 1];
    if (last?.key === key) last.items.push(item);
    else groups.push({ key, label: dayLabel(iso), items: [item] });
  }
  return groups;
}

const MOVEMENT_KIND_LABEL: Record<string, string> = {
  LOADED: "Carried cargo",
  EMPTY_REPOSITION: "Repositioned empty",
  MANUAL: "Manual move",
};

function EmptyState({ label }: { label: string }) {
  return (
    <Stack align="center" gap={6} py="xl">
      <ThemeIcon variant="light" color="gray" radius="xl" size={44}>
        <History size={20} />
      </ThemeIcon>
      <Text size="sm" c="dimmed">
        {label}
      </Text>
    </Stack>
  );
}

function RequestItem({ request }: { request: WagonTransferRequest }) {
  const meta = STATUS_META[request.status];
  return (
    <Timeline.Item
      bullet={<Inbox size={12} />}
      color={meta?.color ?? "gray"}
      lineVariant="dotted"
    >
      <Group justify="space-between" align="flex-start" gap="md" wrap="wrap">
        <Stack gap={4} style={{ flex: 1, minWidth: 220 }}>
          <Group gap={6} wrap="nowrap">
            <Text size="sm" fw={600}>
              {yardLabel(request.fromYard)}
            </Text>
            <ArrowRight size={13} className="shrink-0 opacity-60" />
            <Text size="sm" fw={600}>
              {yardLabel(request.toYard)}
            </Text>
            <Badge variant="default" radius="sm" size="sm">
              {wagonTypeLabel(request.wagonType)}
            </Badge>
          </Group>
          {stripHtmlToText(request.reason) ? (
            <Text size="xs" c="dimmed" lineClamp={1}>
              {stripHtmlToText(request.reason)}
            </Text>
          ) : null}
        </Stack>
        <Group gap="sm" wrap="nowrap">
          <TransferProgress request={request} />
          <TransferStatusBadge status={request.status} />
          <Text size="xs" c="dimmed" w={38} ta="right">
            {fmtTime(request.createdAt)}
          </Text>
        </Group>
      </Group>
    </Timeline.Item>
  );
}

function MovementItem({ movement }: { movement: WagonMovementRecord }) {
  return (
    <Timeline.Item
      bullet={<Truck size={12} />}
      color={movement.transferRequestId ? "edr-green" : "gray"}
      lineVariant="dotted"
    >
      <Group justify="space-between" align="center" gap="md" wrap="wrap">
        <Group gap={8} wrap="nowrap" style={{ flex: 1, minWidth: 220 }}>
          <Badge variant="light" color="gray" radius="sm" ff="monospace">
            {movement.wagon?.wagonNumber ?? "Wagon"}
          </Badge>
          <Text size="sm" fw={500}>
            {yardLabel(movement.fromYard)}
          </Text>
          <ArrowRight size={13} className="shrink-0 opacity-60" />
          <Text size="sm" fw={500}>
            {yardLabel(movement.toYard)}
          </Text>
        </Group>
        <Group gap="sm" wrap="nowrap">
          {movement.transferRequestId ? (
            <Tooltip label="Delivered against a transfer request" withArrow>
              <Badge variant="dot" color="teal" radius="sm" size="sm">
                Transfer
              </Badge>
            </Tooltip>
          ) : (
            <Badge variant="light" color="gray" radius="sm" size="sm">
              {MOVEMENT_KIND_LABEL[movement.kind] ?? movement.kind}
            </Badge>
          )}
          <Text size="xs" c="dimmed" w={38} ta="right">
            {fmtTime(movement.occurredAt)}
          </Text>
        </Group>
      </Group>
    </Timeline.Item>
  );
}

/**
 * Who moved what. A staffer sees their own activity; holders of
 * `transfer_history_all` can widen it to every staffer (the backend enforces
 * the scope regardless of the toggle).
 */
export default function TransferHistoryPanel() {
  const { user } = useAuth();
  const canSeeAll = hasPermission(user, FREIGHT_PERMS.wagons.transferHistoryAll);
  const [allStaff, setAllStaff] = useState(false);
  const [view, setView] = useState<"requests" | "movements">("requests");
  const [page, setPage] = useState(1);
  const scopeAll = canSeeAll && allStaff;

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

  const showingRequests = view === "requests";
  const total = showingRequests
    ? (meta?.requestsTotal ?? 0)
    : (meta?.movementsTotal ?? 0);
  // Each list pages independently on the server; the pager follows the one on screen.
  const pageSize = meta?.pageSize ?? 20;
  const totalPages = Math.max(1, Math.ceil(total / pageSize));
  const groups = showingRequests
    ? groupByDay(requests, (r) => r.createdAt)
    : groupByDay(movements, (m) => m.occurredAt);

  return (
    <Card withBorder radius="md" p="md">
      <Stack gap="md">
        <Group justify="space-between" align="flex-start" gap="md" wrap="wrap">
          <Stack gap={2}>
            <Text fw={600}>Transfer history</Text>
            <Text size="xs" c="dimmed">
              {scopeAll
                ? "Every staffer's requests and wagon moves"
                : "Requests you filed or fulfilled, and the wagons you moved"}
            </Text>
          </Stack>
          <Group gap="sm" wrap="wrap">
            <SegmentedControl
              size="xs"
              radius="md"
              value={view}
              onChange={(v) => {
                setView(v as "requests" | "movements");
                setPage(1);
              }}
              data={[
                {
                  value: "requests",
                  label: `Requests ${meta?.requestsTotal ?? 0}`,
                },
                {
                  value: "movements",
                  label: `Wagons moved ${meta?.movementsTotal ?? 0}`,
                },
              ]}
            />
            {canSeeAll ? (
              <Switch
                label="All staff"
                checked={allStaff}
                onChange={(e) => {
                  setAllStaff(e.currentTarget.checked);
                  setPage(1);
                }}
              />
            ) : null}
          </Group>
        </Group>

        {source.isLoading ? (
          <Stack gap="sm">
            {[0, 1, 2, 3].map((i) => (
              <Skeleton key={i} height={44} radius="md" />
            ))}
          </Stack>
        ) : groups.length === 0 ? (
          <EmptyState
            label={
              showingRequests
                ? "No transfer requests recorded yet."
                : "No wagon moves recorded yet."
            }
          />
        ) : (
          <Stack gap="lg">
            {groups.map((group) => (
              <Stack key={group.key} gap="xs">
                <Group gap="xs" wrap="nowrap">
                  <Text size="xs" fw={700} c="dimmed" tt="uppercase">
                    {group.label}
                  </Text>
                  <Text size="xs" c="dimmed">
                    · {group.items.length}
                  </Text>
                </Group>
                <Timeline
                  bulletSize={22}
                  lineWidth={2}
                  active={group.items.length}
                >
                  {showingRequests
                    ? (group.items as WagonTransferRequest[]).map((r) => (
                        <RequestItem key={r.id} request={r} />
                      ))
                    : (group.items as WagonMovementRecord[]).map((m) => (
                        <MovementItem key={m.id} movement={m} />
                      ))}
                </Timeline>
              </Stack>
            ))}
          </Stack>
        )}

        <Group justify="space-between" gap="sm" wrap="wrap">
          <Text size="xs" c="dimmed">
            {total} {showingRequests ? "request(s)" : "move(s)"} · page{" "}
            {meta?.page ?? page} of {totalPages}
          </Text>
          <Group gap="xs">
            <Button
              variant="default"
              size="xs"
              radius="md"
              leftSection={<ChevronLeft size={14} />}
              disabled={page <= 1}
              onClick={() => setPage((p) => Math.max(1, p - 1))}
            >
              Previous
            </Button>
            <Button
              variant="default"
              size="xs"
              radius="md"
              rightSection={<ChevronRight size={14} />}
              disabled={page >= totalPages}
              onClick={() => setPage((p) => p + 1)}
            >
              Next
            </Button>
          </Group>
        </Group>
      </Stack>
    </Card>
  );
}
