import { useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import {
  ActionIcon,
  Badge,
  Box,
  Button,
  CloseButton,
  Group,
  Modal,
  Paper,
  SegmentedControl,
  Select,
  Stack,
  Text,
  Textarea,
  TextInput,
} from "@mantine/core";
import { DateInput } from "@mantine/dates";
import {
  ArrowUpDown,
  FilterX,
  Inbox,
  PackageSearch,
  RefreshCw,
  Search,
} from "lucide-react";
import { DataTable, type ColumnDef } from "@edr/ui-common";
import type { Freight } from "@edr/types";

import { PageContainer } from "@/components/page/PageContainer";
import { PageHeader } from "@/components/page/PageHeader";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import {
  getShipmentRejectAction,
  getShipmentStaffRowAction,
  type ShipmentListRow,
} from "@/features/contracts/mapShipmentListRow";
import { contractsService } from "@/services/contracts.service";

const cellMeta = {
  headerClassName: ruleEngineTable.headerCell,
  cellClassName: ruleEngineTable.bodyCell,
};

const fmtDate = (iso?: string | null) =>
  iso
    ? new Intl.DateTimeFormat("en-GB", {
        day: "2-digit",
        month: "short",
        year: "numeric",
      }).format(new Date(iso))
    : "—";

const fmtDateTime = (iso?: string | null) =>
  iso
    ? new Intl.DateTimeFormat("en-GB", {
        day: "2-digit",
        month: "short",
        year: "numeric",
        hour: "2-digit",
        minute: "2-digit",
      }).format(new Date(iso))
    : "—";

function summarizeLines(lines: Freight.RequestedShipmentLines): string {
  if (lines.containers?.length) {
    return lines.containers
      .map((c) => `${c.quantity}× ${c.containerSize}`)
      .join(", ");
  }
  if (lines.bulk) {
    const b = lines.bulk;
    if (b.cargoWeightTons) return `${b.cargoWeightTons} t bulk`;
    if (b.itemCount) return `${b.itemCount} items`;
    return "Bulk";
  }
  return "—";
}

const STATUS_META: Record<
  Freight.BookingRequestStatus,
  { label: string; color: string }
> = {
  PENDING: { label: "Pending", color: "yellow" },
  ACCEPTED: { label: "Accepted", color: "edr-green" },
  REJECTED: { label: "Rejected", color: "red" },
  CANCELLED: { label: "Cancelled", color: "gray" },
};

type StatusFilter = "ALL" | Freight.BookingRequestStatus;
type CargoFilter = "ALL" | "CONTAINER" | "BULK";
type SortKey =
  | "submitted-desc"
  | "submitted-asc"
  | "preferred-asc"
  | "preferred-desc"
  | "reference";

const SORT_OPTIONS: Array<{ value: SortKey; label: string }> = [
  { value: "submitted-desc", label: "Newest first" },
  { value: "submitted-asc", label: "Oldest first" },
  { value: "preferred-asc", label: "Preferred date (soonest)" },
  { value: "preferred-desc", label: "Preferred date (latest)" },
  { value: "reference", label: "Reference A–Z" },
];

const time = (iso?: string | null) => (iso ? new Date(iso).getTime() : 0);

export default function ShipmentRequestsPage() {
  const navigate = useNavigate();
  const queryClient = useQueryClient();

  const [query, setQuery] = useState("");
  const [status, setStatus] = useState<StatusFilter>("PENDING");
  const [cargo, setCargo] = useState<CargoFilter>("ALL");
  const [preferredFrom, setPreferredFrom] = useState<Date | null>(null);
  const [preferredTo, setPreferredTo] = useState<Date | null>(null);
  const [sort, setSort] = useState<SortKey>("submitted-desc");

  const [rejectTarget, setRejectTarget] = useState<ShipmentListRow | null>(null);
  const [rejectNote, setRejectNote] = useState("");
  const [acceptTarget, setAcceptTarget] = useState<ShipmentListRow | null>(null);

  const { data, isLoading, isError, isFetching, refetch } = useQuery({
    queryKey: ["shipment-request-queue"],
    queryFn: () => contractsService.getBookingRequestQueue(),
    refetchInterval: 30_000,
  });

  const reject = useMutation({
    mutationFn: () =>
      contractsService.rejectBookingRequest(rejectTarget!.id, rejectNote),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["shipment-request-queue"] });
      setRejectTarget(null);
      setRejectNote("");
    },
  });

  const allRows = useMemo<ShipmentListRow[]>(
    () =>
      (data ?? []).map((r) => {
        const lines = r.requestedLines ?? {};
        return {
          id: r.id,
          reference: r.reference || r.id.slice(0, 8),
          contractId: r.contractId,
          contractReference: r.contract?.reference ?? r.contractId,
          scheduledDate: r.scheduledDate,
          summary: summarizeLines(lines),
          status: r.status,
          createdBookingId: r.createdBookingId,
          createdAt: r.createdAt,
          customerName: r.contract?.company?.name ?? null,
          freightKind: lines.containers?.length
            ? "CONTAINER"
            : lines.bulk
              ? "BULK"
              : r.contract?.freightType === "BULK"
                ? "BULK"
                : "CONTAINER",
          hazardous:
            (lines.containers ?? []).some((c) => (c.hazardousQuantity ?? 0) > 0) ||
            (lines.bulk?.hazardousQuantity ?? 0) > 0,
          reefer: (lines.containers ?? []).some(
            (c) => (c.reeferQuantity ?? 0) > 0,
          ),
        };
      }),
    [data],
  );

  // Status counts always reflect the whole queue so the segmented control
  // reads as a live overview, independent of the other filters.
  const counts = useMemo(() => {
    const c: Record<StatusFilter, number> = {
      ALL: allRows.length,
      PENDING: 0,
      ACCEPTED: 0,
      REJECTED: 0,
      CANCELLED: 0,
    };
    allRows.forEach((r) => {
      c[r.status] += 1;
    });
    return c;
  }, [allRows]);

  const rows = useMemo<ShipmentListRow[]>(() => {
    let out = allRows;

    if (status !== "ALL") out = out.filter((r) => r.status === status);
    if (cargo !== "ALL") out = out.filter((r) => r.freightKind === cargo);

    // Preferred-date range: rows without a preferred day drop out once a bound
    // is set — a date filter that keeps dateless rows reads as broken.
    if (preferredFrom || preferredTo) {
      const from = preferredFrom ? preferredFrom.getTime() : -Infinity;
      const to = preferredTo
        ? preferredTo.getTime() + 24 * 60 * 60 * 1000 - 1
        : Infinity;
      out = out.filter((r) => {
        if (!r.scheduledDate) return false;
        const t = time(r.scheduledDate);
        return t >= from && t <= to;
      });
    }

    const q = query.trim().toLowerCase();
    if (q) {
      out = out.filter(
        (r) =>
          r.reference.toLowerCase().includes(q) ||
          r.contractReference.toLowerCase().includes(q) ||
          (r.customerName ?? "").toLowerCase().includes(q) ||
          r.summary.toLowerCase().includes(q),
      );
    }

    const sorted = [...out];
    switch (sort) {
      case "submitted-asc":
        sorted.sort((a, b) => time(a.createdAt) - time(b.createdAt));
        break;
      case "preferred-asc":
        // Requests without a preferred day sink to the bottom in both orders.
        sorted.sort(
          (a, b) =>
            (a.scheduledDate ? time(a.scheduledDate) : Infinity) -
            (b.scheduledDate ? time(b.scheduledDate) : Infinity),
        );
        break;
      case "preferred-desc":
        sorted.sort(
          (a, b) =>
            (b.scheduledDate ? time(b.scheduledDate) : -Infinity) -
            (a.scheduledDate ? time(a.scheduledDate) : -Infinity),
        );
        break;
      case "reference":
        sorted.sort((a, b) => a.reference.localeCompare(b.reference));
        break;
      default:
        // Newest submitted on top.
        sorted.sort((a, b) => time(b.createdAt) - time(a.createdAt));
    }
    return sorted;
  }, [allRows, status, cargo, preferredFrom, preferredTo, query, sort]);

  const filtersActive =
    query.trim() !== "" ||
    status !== "PENDING" ||
    cargo !== "ALL" ||
    preferredFrom !== null ||
    preferredTo !== null ||
    sort !== "submitted-desc";

  const clearFilters = () => {
    setQuery("");
    setStatus("PENDING");
    setCargo("ALL");
    setPreferredFrom(null);
    setPreferredTo(null);
    setSort("submitted-desc");
  };

  const columns = useMemo<ColumnDef<ShipmentListRow>[]>(
    () => [
      {
        id: "reference",
        header: "Request",
        meta: cellMeta,
        cell: ({ row }) => (
          <Box>
            <Text size="sm" fw={700} c="dark.5">
              {row.original.reference}
            </Text>
            <Text size="xs" c="dimmed" mt={2}>
              Submitted {fmtDateTime(row.original.createdAt)}
            </Text>
          </Box>
        ),
      },
      {
        id: "contract",
        header: "Contract",
        meta: cellMeta,
        cell: ({ row }) => (
          <Box>
            <Text size="sm" c="gray.7">
              {row.original.contractReference}
            </Text>
            {row.original.customerName ? (
              <Text size="xs" c="dimmed" mt={2}>
                {row.original.customerName}
              </Text>
            ) : null}
          </Box>
        ),
      },
      {
        id: "summary",
        header: "Requested",
        meta: cellMeta,
        cell: ({ row }) => (
          <Group gap={6} wrap="wrap">
            <Badge variant="light" color="edr-green" radius="sm">
              {row.original.summary}
            </Badge>
            {row.original.hazardous ? (
              <Badge variant="light" color="red" radius="sm">
                Hazardous
              </Badge>
            ) : null}
            {row.original.reefer ? (
              <Badge variant="light" color="blue" radius="sm">
                Reefer
              </Badge>
            ) : null}
          </Group>
        ),
      },
      {
        id: "date",
        header: "Preferred date",
        meta: cellMeta,
        cell: ({ row }) => (
          <Text size="sm">{fmtDate(row.original.scheduledDate)}</Text>
        ),
      },
      {
        id: "status",
        header: "Status",
        meta: cellMeta,
        cell: ({ row }) => {
          const meta = STATUS_META[row.original.status];
          return (
            <Badge variant="light" color={meta.color} radius="sm">
              {meta.label}
            </Badge>
          );
        },
      },
      {
        id: "actions",
        header: () => <span className={ruleEngineTable.headerCell}>Action</span>,
        meta: cellMeta,
        cell: ({ row }) => {
          const primary = getShipmentStaffRowAction(row.original);
          const rejectAction = getShipmentRejectAction(row.original);
          return (
            <Group gap={6} wrap="nowrap" justify="flex-end">
              {rejectAction ? (
                <Button
                  size="compact-sm"
                  radius="md"
                  variant="light"
                  color="red"
                  onClick={(e) => {
                    e.stopPropagation();
                    setRejectTarget(row.original);
                  }}
                >
                  {rejectAction.label}
                </Button>
              ) : null}
              {primary.kind === "navigate" ? (
                <Button
                  size="compact-sm"
                  radius="md"
                  variant={primary.variant === "filled" ? "filled" : primary.variant}
                  color="edr-green"
                  onClick={(e) => {
                    e.stopPropagation();
                    if (
                      primary.label === "Accept" &&
                      row.original.status === "PENDING"
                    ) {
                      setAcceptTarget(row.original);
                    } else {
                      navigate(primary.to(row.original));
                    }
                  }}
                >
                  {primary.label}
                </Button>
              ) : null}
            </Group>
          );
        },
      },
    ],
    [navigate],
  );

  const hasAnyRequests = allRows.length > 0;

  return (
    <PageContainer>
      <Stack gap="lg">
        <PageHeader
          title="Shipment Requests"
          subtitle="Customer requests to ship under general customs contracts. Each request starts its booking's clearance immediately — complete the booking from the clearance page once it is ready."
          meta={
            <Badge
              variant="light"
              color="edr-green"
              radius="sm"
              leftSection={<PackageSearch size={13} />}
            >
              {counts.PENDING} pending
            </Badge>
          }
          action={
            <ActionIcon
              variant="default"
              size="lg"
              radius="md"
              onClick={() => refetch()}
              loading={isFetching}
              aria-label="Refresh"
            >
              <RefreshCw size={16} />
            </ActionIcon>
          }
        />

        <Paper withBorder radius="lg" p="md" style={{ borderColor: "#E6ECF2" }}>
          <Stack gap="sm">
            <Group gap="sm" wrap="wrap">
              <TextInput
                radius="md"
                style={{ flex: 1, minWidth: 220 }}
                placeholder="Search request, contract, customer, cargo…"
                leftSection={<Search size={15} />}
                rightSection={
                  query ? (
                    <CloseButton
                      size="sm"
                      aria-label="Clear search"
                      onClick={() => setQuery("")}
                    />
                  ) : null
                }
                value={query}
                onChange={(e) => setQuery(e.currentTarget.value)}
              />
              <Select
                radius="md"
                w={150}
                value={cargo}
                onChange={(v) => setCargo((v as CargoFilter) ?? "ALL")}
                data={[
                  { value: "ALL", label: "All cargo" },
                  { value: "CONTAINER", label: "Containers" },
                  { value: "BULK", label: "Bulk" },
                ]}
                allowDeselect={false}
                aria-label="Cargo type"
              />
              <DateInput
                radius="md"
                w={150}
                placeholder="Preferred from"
                value={preferredFrom}
                onChange={(v) => setPreferredFrom(v ? new Date(v) : null)}
                maxDate={preferredTo ?? undefined}
                clearable
                aria-label="Preferred date from"
              />
              <DateInput
                radius="md"
                w={150}
                placeholder="Preferred to"
                value={preferredTo}
                onChange={(v) => setPreferredTo(v ? new Date(v) : null)}
                minDate={preferredFrom ?? undefined}
                clearable
                aria-label="Preferred date to"
              />
              <Select
                radius="md"
                w={215}
                leftSection={<ArrowUpDown size={14} />}
                value={sort}
                onChange={(v) => setSort((v as SortKey) ?? "submitted-desc")}
                data={SORT_OPTIONS}
                allowDeselect={false}
                aria-label="Sort by"
              />
            </Group>

            <Group justify="space-between" gap="sm" wrap="wrap">
              <SegmentedControl
                radius="md"
                size="xs"
                value={status}
                onChange={(v) => setStatus(v as StatusFilter)}
                data={[
                  { value: "ALL", label: `All · ${counts.ALL}` },
                  { value: "PENDING", label: `Pending · ${counts.PENDING}` },
                  { value: "ACCEPTED", label: `Accepted · ${counts.ACCEPTED}` },
                  { value: "REJECTED", label: `Rejected · ${counts.REJECTED}` },
                  { value: "CANCELLED", label: `Cancelled · ${counts.CANCELLED}` },
                ]}
              />
              <Group gap="sm">
                <Text size="sm" c="dimmed">
                  {rows.length} of {allRows.length} request
                  {allRows.length === 1 ? "" : "s"}
                </Text>
                {filtersActive ? (
                  <Button
                    variant="subtle"
                    color="gray"
                    size="compact-sm"
                    radius="md"
                    leftSection={<FilterX size={14} />}
                    onClick={clearFilters}
                  >
                    Clear filters
                  </Button>
                ) : null}
              </Group>
            </Group>
          </Stack>
        </Paper>

        {rows.length === 0 && !isLoading && !isError ? (
          <Box
            py={56}
            style={{
              borderRadius: 14,
              border: "1px dashed var(--mantine-color-gray-3)",
              textAlign: "center",
            }}
          >
            <Inbox size={26} className="text-muted-foreground" />
            {hasAnyRequests ? (
              <>
                <Text c="dimmed" mt="sm">
                  No requests match the current filters.
                </Text>
                <Button
                  variant="subtle"
                  color="gray"
                  size="compact-sm"
                  radius="md"
                  mt="xs"
                  leftSection={<FilterX size={14} />}
                  onClick={clearFilters}
                >
                  Clear filters
                </Button>
              </>
            ) : (
              <Text c="dimmed" mt="sm">
                No shipment requests yet.
              </Text>
            )}
          </Box>
        ) : (
          <DataTable
            columns={columns}
            data={rows}
            status={isLoading ? "loading" : isError ? "error" : "success"}
            onRowClick={(row) =>
              navigate(`/dashboard/shipment-requests/${row.id}`)
            }
            containerClassName="overflow-x-auto rounded-lg border border-edr-border"
          />
        )}
      </Stack>

      <Modal
        opened={rejectTarget !== null}
        onClose={() => {
          if (!reject.isPending) {
            setRejectTarget(null);
            setRejectNote("");
          }
        }}
        title="Reject shipment request"
        radius="md"
        centered
      >
        <Stack gap="md">
          <Text size="sm" c="dimmed">
            Reject request{" "}
            <Text span fw={600}>
              {rejectTarget?.reference}
            </Text>
            ? The customer will be notified.
          </Text>
          <Textarea
            label="Reason"
            placeholder="Explain why this request cannot be accepted…"
            value={rejectNote}
            onChange={(e) => setRejectNote(e.currentTarget.value)}
            minRows={3}
            radius="md"
          />
          <Group justify="flex-end" gap="sm">
            <Button
              variant="default"
              radius="md"
              onClick={() => {
                setRejectTarget(null);
                setRejectNote("");
              }}
            >
              Cancel
            </Button>
            <Button
              color="red"
              radius="md"
              loading={reject.isPending}
              disabled={!rejectNote.trim()}
              onClick={() => reject.mutate()}
            >
              Reject request
            </Button>
          </Group>
        </Stack>
      </Modal>

      <Modal
        opened={acceptTarget !== null}
        onClose={() => setAcceptTarget(null)}
        title="Accept shipment request"
        radius="md"
        centered
      >
        <Stack gap="md">
          <Text size="sm" c="dimmed">
            Proceed to create a booking for request{" "}
            <Text span fw={600}>
              {acceptTarget?.reference}
            </Text>
            ? You will confirm the shipment price before submitting.
          </Text>
          <Group justify="flex-end" gap="sm">
            <Button variant="default" radius="md" onClick={() => setAcceptTarget(null)}>
              Cancel
            </Button>
            <Button
              color="edr-green"
              radius="md"
              onClick={() => {
                if (!acceptTarget) return;
                const to = getShipmentStaffRowAction(acceptTarget);
                if (to.kind === "navigate") {
                  navigate(to.to(acceptTarget));
                }
                setAcceptTarget(null);
              }}
            >
              Continue
            </Button>
          </Group>
        </Stack>
      </Modal>
    </PageContainer>
  );
}
