import { Freight } from "@edr/types";
import {
  Box,
  Button,
  Card,
  Group,
  Loader,
  Select,
  Stack,
  Switch,
  Tabs,
  Text,
  TextInput,
} from "@mantine/core";
import { useDebouncedValue } from "@mantine/hooks";
import { useQuery } from "@tanstack/react-query";
import {
  ArrowRight,
  History,
  Inbox,
  PackageCheck,
  Plus,
  RefreshCw,
  Search,
  Send,
  Truck,
  XCircle,
} from "lucide-react";
import { useMemo, useState } from "react";
import toast from "react-hot-toast";
import { useMutation } from "@tanstack/react-query";

import { useAuth } from "@/auth/useAuth";
import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
import { api } from "@/services/api";
import type {
  TransferRequestListFilter,
  WagonTransferRequest,
} from "@/services/wagon.service";
import {
  DataTable,
  DataTableFooter,
  usePagination,
  type ColumnDef,
} from "@edr/ui-common";

import TransferFulfillModal from "./TransferFulfillModal";
import {
  TransferCloseShortModal,
  TransferRequestFormModal,
} from "./TransferRequestModals";
import {
  TransferProgress,
  TransferStatusBadge,
  fmtDateTime,
  isOpenRequest,
  outstandingOn,
  wagonTypeLabel,
  yardLabel,
} from "./wagon-transfer-ui";

const S = Freight.WagonTransferRequestStatus;

/** "Open" is the working set: nothing delivered yet OR part-delivered. */
const OPEN_STATUSES = `${S.Pending},${S.PartiallyFulfilled}`;

const STATUS_FILTER_OPTIONS = [
  { value: OPEN_STATUSES, label: "Open (awaiting wagons)" },
  { value: S.Pending, label: "Not started" },
  { value: S.PartiallyFulfilled, label: "Partly delivered" },
  { value: S.Fulfilled, label: "Complete" },
  { value: S.ClosedShort, label: "Closed short" },
  { value: S.Cancelled, label: "Cancelled" },
];

/**
 * The wagon-transfer desk.
 *
 * A request is a count, not a wagon list: someone asks for 50 gondolas from
 * Dire Dawa, and OCC sends whatever that yard can spare, whenever it can. The
 * table is built around that — every row shows delivered-vs-asked, and a
 * request only leaves the queue when it is fully supplied or explicitly closed
 * short (which tells the requester to try another yard).
 */
export default function WagonTransfersPage() {
  const { user } = useAuth();
  const canRequest = hasPermission(user, FREIGHT_PERMS.wagons.transferRequest);
  const canFulfil = hasPermission(user, FREIGHT_PERMS.wagons.transferFulfill);
  const canCloseShort =
    canFulfil || hasPermission(user, FREIGHT_PERMS.wagons.transferCloseShort);
  const canCancel =
    canRequest || hasPermission(user, FREIGHT_PERMS.wagons.transferCancel);

  const { pagination, setPagination } = usePagination({ pageSize: 10 });
  const [status, setStatus] = useState<string | null>(OPEN_STATUSES);
  const [fromYardId, setFromYardId] = useState<string | null>(null);
  const [toYardId, setToYardId] = useState<string | null>(null);
  const [wagonTypeId, setWagonTypeId] = useState<string | null>(null);
  const [search, setSearch] = useState("");
  const [debouncedSearch] = useDebouncedValue(search, 300);

  const [formOpen, setFormOpen] = useState(false);
  const [carryOver, setCarryOver] = useState<WagonTransferRequest | null>(null);
  const [fulfilling, setFulfilling] = useState<WagonTransferRequest | null>(null);
  const [closingShort, setClosingShort] = useState<WagonTransferRequest | null>(
    null,
  );

  const filter: TransferRequestListFilter = useMemo(
    () => ({
      page: pagination.pageIndex + 1,
      pageSize: pagination.pageSize,
      ...(status ? { status } : {}),
      ...(fromYardId ? { fromYardId } : {}),
      ...(toYardId ? { toYardId } : {}),
      ...(wagonTypeId ? { wagonTypeId } : {}),
      ...(debouncedSearch.trim() ? { search: debouncedSearch.trim() } : {}),
    }),
    [
      pagination.pageIndex,
      pagination.pageSize,
      status,
      fromYardId,
      toYardId,
      wagonTypeId,
      debouncedSearch,
    ],
  );

  const { data, isLoading, isError, refetch, isFetching } = useQuery(
    api.wagonTransferRequests.list.queryOptions({ input: { filter } }),
  );
  const rows = data?.items ?? [];
  const meta = data?.meta;

  const { data: yards = [] } = useQuery(
    api.routes.yards.queryOptions({ staleTime: 5 * 60_000 }),
  );
  const { data: wagonTypes = [] } = useQuery(api.wagonTypes.list.queryOptions());
  const yardOptions = yards.map((y) => ({
    value: y.id,
    label: y.label ?? y.code ?? y.id,
  }));
  const typeOptions = wagonTypes.map((t) => ({
    value: t.id,
    label: [t.code, t.name].filter(Boolean).join(" · "),
  }));

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

  const resetPage = () =>
    setPagination({ pageIndex: 0, pageSize: pagination.pageSize });

  const clearFilters = () => {
    setStatus(OPEN_STATUSES);
    setFromYardId(null);
    setToYardId(null);
    setWagonTypeId(null);
    setSearch("");
    resetPage();
  };

  const columns: ColumnDef<WagonTransferRequest>[] = [
    {
      id: "route",
      header: () => <span>Route</span>,
      cell: ({ row }) => {
        const r = row.original;
        return (
          <Group gap={6} wrap="nowrap">
            <Text size="sm" fw={600}>
              {yardLabel(r.fromYard)}
            </Text>
            <ArrowRight size={13} className="shrink-0 opacity-60" />
            <Text size="sm" fw={600}>
              {yardLabel(r.toYard)}
            </Text>
          </Group>
        );
      },
    },
    {
      id: "type",
      header: () => <span>Wagon type</span>,
      cell: ({ row }) => (
        <Text size="sm">{wagonTypeLabel(row.original.wagonType)}</Text>
      ),
    },
    {
      id: "progress",
      header: () => <span>Delivered</span>,
      cell: ({ row }) => <TransferProgress request={row.original} />,
    },
    {
      id: "reason",
      header: () => <span>Reason</span>,
      cell: ({ row }) => (
        <Text size="sm" c="dimmed" lineClamp={2} maw={260}>
          {row.original.reason || "—"}
        </Text>
      ),
    },
    {
      id: "filed",
      header: () => <span>Filed</span>,
      cell: ({ row }) => (
        <Text size="xs" c="dimmed">
          {fmtDateTime(row.original.createdAt)}
        </Text>
      ),
    },
    {
      id: "status",
      header: () => <span>Status</span>,
      cell: ({ row }) => <TransferStatusBadge status={row.original.status} />,
    },
    {
      id: "actions",
      header: () => <span />,
      cell: ({ row }) => {
        const r = row.original;
        const open = isOpenRequest(r);
        const short =
          r.status === S.ClosedShort && outstandingOn(r) > 0;
        return (
          <Group gap={6} justify="flex-end" wrap="nowrap">
            {open && canFulfil ? (
              <Button
                size="xs"
                radius="md"
                color="edr-green"
                leftSection={<Truck size={13} />}
                onClick={() => setFulfilling(r)}
              >
                Transfer
              </Button>
            ) : null}
            {open && r.fulfilledQuantity > 0 && canCloseShort ? (
              <Button
                size="xs"
                radius="md"
                variant="light"
                color="orange"
                leftSection={<XCircle size={13} />}
                onClick={() => setClosingShort(r)}
              >
                Close short
              </Button>
            ) : null}
            {short && canRequest ? (
              <Button
                size="xs"
                radius="md"
                variant="light"
                color="grape"
                leftSection={<Send size={13} />}
                onClick={() => {
                  setCarryOver(r);
                  setFormOpen(true);
                }}
              >
                Ask another yard
              </Button>
            ) : null}
            {r.status === S.Pending && canCancel ? (
              <Button
                size="xs"
                radius="md"
                variant="subtle"
                color="red"
                loading={cancel.isPending}
                onClick={async () => {
                  try {
                    await cancel.mutateAsync({ id: r.id });
                    toast.success("Request withdrawn");
                  } catch {
                    // interceptor surfaces the reason
                  }
                }}
              >
                Withdraw
              </Button>
            ) : null}
          </Group>
        );
      },
    },
  ];

  const openCount = rows.filter(isOpenRequest).length;
  const outstandingWagons = rows.reduce(
    (sum: number, r: WagonTransferRequest) =>
      sum + (isOpenRequest(r) ? outstandingOn(r) : 0),
    0,
  );

  return (
    <PageContainer>
      <Stack gap="lg">
        <PageHeader
          title="Wagon transfers"
          subtitle="Requests for wagons to move between yards — delivered in instalments until the full count is met"
          breadcrumbs={[
            { label: "Wagons", href: "/dashboard/wagons" },
            { label: "Transfers" },
          ]}
          action={
            <Group gap="sm">
              <Button
                variant="default"
                radius="md"
                leftSection={<RefreshCw size={15} />}
                loading={isFetching}
                onClick={() => void refetch()}
              >
                Refresh
              </Button>
              {canRequest ? (
                <Button
                  color="edr-green"
                  radius="md"
                  leftSection={<Plus size={15} />}
                  onClick={() => {
                    setCarryOver(null);
                    setFormOpen(true);
                  }}
                >
                  New request
                </Button>
              ) : null}
            </Group>
          }
        />

        <KpiStrip
          items={[
            {
              label: "Open on this page",
              value: openCount,
              icon: Inbox,
            },
            {
              label: "Wagons still owed",
              value: outstandingWagons,
              icon: Truck,
            },
            {
              label: "Requests matched",
              value: meta?.total ?? 0,
              icon: PackageCheck,
            },
          ]}
        />

        <Tabs defaultValue="requests" keepMounted={false}>
          <Tabs.List>
            <Tabs.Tab value="requests" leftSection={<Inbox size={15} />}>
              Requests
            </Tabs.Tab>
            <Tabs.Tab value="history" leftSection={<History size={15} />}>
              History
            </Tabs.Tab>
          </Tabs.List>

          <Tabs.Panel value="requests" pt="md">
            <Card withBorder radius="md" p="md">
              <Stack gap="md">
                <Group gap="sm" wrap="wrap">
                  <TextInput
                    placeholder="Search the reason…"
                    leftSection={<Search size={15} />}
                    value={search}
                    onChange={(e) => {
                      setSearch(e.currentTarget.value);
                      resetPage();
                    }}
                    w={240}
                    radius="md"
                  />
                  <Select
                    placeholder="Status"
                    data={STATUS_FILTER_OPTIONS}
                    value={status}
                    onChange={(v) => {
                      setStatus(v);
                      resetPage();
                    }}
                    clearable
                    w={200}
                    radius="md"
                  />
                  <Select
                    placeholder="From yard"
                    data={yardOptions}
                    value={fromYardId}
                    onChange={(v) => {
                      setFromYardId(v);
                      resetPage();
                    }}
                    searchable
                    clearable
                    w={180}
                    radius="md"
                  />
                  <Select
                    placeholder="To yard"
                    data={yardOptions}
                    value={toYardId}
                    onChange={(v) => {
                      setToYardId(v);
                      resetPage();
                    }}
                    searchable
                    clearable
                    w={180}
                    radius="md"
                  />
                  <Select
                    placeholder="Wagon type"
                    data={typeOptions}
                    value={wagonTypeId}
                    onChange={(v) => {
                      setWagonTypeId(v);
                      resetPage();
                    }}
                    searchable
                    clearable
                    w={180}
                    radius="md"
                  />
                  <Button variant="subtle" radius="md" onClick={clearFilters}>
                    Clear
                  </Button>
                </Group>

                <Box style={{ overflowX: "auto" }} w="100%">
                  <DataTable
                    columns={columns}
                    data={rows}
                    status={
                      isLoading ? "loading" : isError ? "error" : "success"
                    }
                    pagination={{
                      pageIndex: pagination.pageIndex,
                      pageSize: pagination.pageSize,
                      pageCount: meta?.totalPages ?? 1,
                      totalCount: meta?.total ?? 0,
                    }}
                    tableOptions={{
                      state: { pagination },
                      onPaginationChange: setPagination,
                      manualPagination: true,
                      pageCount: meta?.totalPages ?? 1,
                    }}
                    containerClassName="border-0 shadow-none bg-transparent"
                    footer={DataTableFooter}
                  />
                </Box>
              </Stack>
            </Card>
          </Tabs.Panel>

          <Tabs.Panel value="history" pt="md">
            <TransferHistoryPanel />
          </Tabs.Panel>
        </Tabs>
      </Stack>

      <TransferRequestFormModal
        opened={formOpen}
        prefillFrom={carryOver}
        onClose={() => {
          setFormOpen(false);
          setCarryOver(null);
        }}
        onCreated={() => void refetch()}
      />
      <TransferFulfillModal
        request={fulfilling}
        onClose={() => setFulfilling(null)}
        onDone={() => void refetch()}
      />
      <TransferCloseShortModal
        request={closingShort}
        onClose={() => setClosingShort(null)}
        onClosed={(r) => {
          void refetch();
          // Straight into the re-ask: the shortfall is the whole reason this
          // request was closed, so offer the other-yard form immediately.
          if (canRequest) {
            setCarryOver(r);
            setFormOpen(true);
          }
        }}
      />
    </PageContainer>
  );
}

/**
 * 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).
 */
function TransferHistoryPanel() {
  const { user } = useAuth();
  const canSeeAll = hasPermission(user, FREIGHT_PERMS.wagons.transferHistoryAll);
  const [allStaff, setAllStaff] = useState(false);
  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;

  return (
    <Card withBorder radius="md" p="md">
      <Stack gap="md">
        <Group justify="space-between" wrap="wrap">
          <Text fw={600}>Transfer history</Text>
          {canSeeAll ? (
            <Switch
              label="All staff"
              checked={allStaff}
              onChange={(e) => {
                setAllStaff(e.currentTarget.checked);
                setPage(1);
              }}
            />
          ) : null}
        </Group>

        {source.isLoading ? (
          <Group justify="center" py="lg">
            <Loader size="sm" />
          </Group>
        ) : (
          <Group align="flex-start" grow gap="lg" wrap="wrap">
            <Stack gap={6} miw={280}>
              <Text size="sm" fw={700} c="dimmed" tt="uppercase">
                Requests ({meta?.requestsTotal ?? 0})
              </Text>
              {requests.length === 0 ? (
                <Text size="sm" c="dimmed">
                  Nothing yet.
                </Text>
              ) : (
                requests.map((r) => (
                  <Group key={r.id} gap={8} wrap="nowrap" justify="space-between">
                    <Text size="sm" truncate>
                      {yardLabel(r.fromYard)} → {yardLabel(r.toYard)} ·{" "}
                      {r.fulfilledQuantity}/{r.quantity}
                    </Text>
                    <TransferStatusBadge status={r.status} />
                  </Group>
                ))
              )}
            </Stack>

            <Stack gap={6} miw={280}>
              <Text size="sm" fw={700} c="dimmed" tt="uppercase">
                Wagons moved ({meta?.movementsTotal ?? 0})
              </Text>
              {movements.length === 0 ? (
                <Text size="sm" c="dimmed">
                  Nothing yet.
                </Text>
              ) : (
                movements.map((m) => (
                  <Group key={m.id} gap={8} wrap="nowrap" justify="space-between">
                    <Text size="sm" truncate>
                      {m.wagon?.wagonNumber ?? "Wagon"} · {yardLabel(m.fromYard)} →{" "}
                      {yardLabel(m.toYard)}
                    </Text>
                    <Text size="xs" c="dimmed">
                      {fmtDateTime(m.occurredAt)}
                    </Text>
                  </Group>
                ))
              )}
            </Stack>
          </Group>
        )}

        <Group justify="center" gap="sm">
          <Button
            variant="default"
            size="xs"
            radius="md"
            disabled={page <= 1}
            onClick={() => setPage((p) => Math.max(1, p - 1))}
          >
            Previous
          </Button>
          <Text size="sm" c="dimmed">
            Page {meta?.page ?? page} of {meta?.totalPages ?? 1}
          </Text>
          <Button
            variant="default"
            size="xs"
            radius="md"
            disabled={page >= (meta?.totalPages ?? 1)}
            onClick={() => setPage((p) => p + 1)}
          >
            Next
          </Button>
        </Group>
      </Stack>
    </Card>
  );
}
