import { useState } from "react";
import {
  Badge,
  Button,
  Card,
  Collapse,
  Group,
  Stack,
  Text,
  Textarea,
  Tooltip,
} from "@mantine/core";
import type { UseMutationResult } from "@tanstack/react-query";
import { ArrowRight, CheckCircle2, Clock, XCircle } from "lucide-react";

import type { RateChangeRequest } from "@/services/ruleEngine/ruleEngine.service";

/** Field labels for the diff — anything not listed falls back to the raw key. */
const FIELD_LABELS: Record<string, string> = {
  rateValue: "Rate",
  currency: "Currency",
  rateUnit: "Unit",
  appliesTo: "Applies to",
  trigger: "Trigger",
  tradeDirection: "Direction",
  containerTypeId: "Container type",
  cargoTypeId: "Cargo type",
  originYardId: "Origin yard",
  destinationYardId: "Destination yard",
};

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

const fmtValue = (
  field: string,
  value: unknown,
  labels?: Record<string, string>,
): string => {
  if (value === null || value === undefined || value === "") return "—";
  if (field === "rateValue") {
    const num = Number(value);
    return Number.isNaN(num) ? String(value) : num.toLocaleString();
  }
  // Yard ids are unreadable — an approver decides on the route, not a UUID.
  if (field === "originYardId" || field === "destinationYardId") {
    return labels?.[String(value)] ?? String(value);
  }
  return String(value).replace(/_/g, " ");
};

/** "Ocean freight · 40HC" — what rate this change targets. */
const rateSummary = (r: RateChangeRequest): string => {
  const rate = (r.rate ?? {}) as Record<string, unknown>;
  const parts = [
    rate.rateType ? String(rate.rateType).replace(/_/g, " ") : null,
    rate.appliesTo ? String(rate.appliesTo) : null,
    rate.trigger && rate.trigger !== "ALWAYS" ? String(rate.trigger) : null,
  ].filter(Boolean);
  return parts.join(" · ") || "Rate";
};

/** The headline change, so the queue is scannable without expanding: "100 → 200 USD". */
const headline = (r: RateChangeRequest): string | null => {
  if (!("rateValue" in r.payload)) return null;
  const currency = String(r.payload.currency ?? r.previousValues.currency ?? (r.rate as Record<string, unknown> | undefined)?.currency ?? "");
  const before = fmtValue("rateValue", r.previousValues.rateValue);
  const after = fmtValue("rateValue", r.payload.rateValue);
  return `${before} → ${after}${currency ? ` ${currency}` : ""}`;
};

type Decide = UseMutationResult<
  RateChangeRequest,
  unknown,
  { id: string; decisionNote?: string }
>;

interface RateApprovalsSectionProps {
  requests: RateChangeRequest[];
  /** Whether this user holds the rates approve permission. */
  canDecide: boolean;
  approve: Decide;
  reject: Decide;
  /** yardId → label, so a re-routed rate reads as yards, not UUIDs. */
  yardLabels?: Record<string, string>;
}

/**
 * Pending edits to LIVE rates. Each row is a before→after diff: the left value
 * is what pricing charges right now and keeps charging until someone approves.
 * Rendered above the rates table.
 */
const RateApprovalsSection = ({
  requests,
  canDecide,
  approve,
  reject,
  yardLabels,
}: RateApprovalsSectionProps) => {
  const [openId, setOpenId] = useState<string | null>(null);
  const [notes, setNotes] = useState<Record<string, string>>({});

  if (requests.length === 0) return null;

  const decidingId = approve.variables?.id ?? reject.variables?.id ?? null;

  return (
    <Card withBorder radius="md" padding="md" mb="md">
      <Group gap={8} mb={4}>
        <Clock size={16} />
        <Text fw={700}>Pending rate changes</Text>
        <Badge variant="light" color="yellow">
          {requests.length}
        </Badge>
      </Group>
      <Text size="xs" c="dimmed" mb="sm">
        Each rate below still charges its current value. Nothing changes until approved.
      </Text>

      <Stack gap={8}>
        {requests.map((r) => {
          const isOpen = openId === r.id;
          const fields = Object.keys(r.payload);
          const summaryLine = headline(r);
          // Only the row being decided shows a spinner — the mutation's
          // isPending is shared across every row.
          const busy = decidingId === r.id;

          return (
            <Card key={r.id} withBorder radius="md" padding="sm">
              <Group justify="space-between" wrap="nowrap" align="flex-start">
                <Stack gap={4} style={{ minWidth: 0 }}>
                  <Group gap={8} wrap="nowrap">
                    <Badge variant="light" color="blue" radius="sm">
                      update
                    </Badge>
                    <Text size="sm" fw={600} truncate>
                      {rateSummary(r)}
                    </Text>
                  </Group>

                  {summaryLine ? (
                    <Group gap={6} wrap="nowrap">
                      <Text size="sm" c="dimmed" td="line-through">
                        {fmtValue("rateValue", r.previousValues.rateValue)}
                      </Text>
                      <ArrowRight size={13} />
                      <Text size="sm" fw={700} c="edr-green">
                        {fmtValue("rateValue", r.payload.rateValue)}
                      </Text>
                      <Text size="sm" c="dimmed">
                        {String(
                          r.payload.currency ??
                            r.previousValues.currency ??
                            (r.rate as Record<string, unknown> | undefined)?.currency ??
                            "",
                        )}
                      </Text>
                    </Group>
                  ) : null}

                  <Group gap={6}>
                    <Text size="xs" c="dimmed">
                      Submitted {fmtDateTime(r.createdAt)} · {fields.length}{" "}
                      {fields.length === 1 ? "field" : "fields"} changed
                    </Text>
                    <Button
                      size="compact-xs"
                      variant="subtle"
                      onClick={() => setOpenId(isOpen ? null : r.id)}
                    >
                      {isOpen ? "Hide details" : "See all changes"}
                    </Button>
                  </Group>
                </Stack>

                {canDecide ? (
                  <Group gap={8} wrap="nowrap">
                    <Button
                      size="compact-sm"
                      variant="subtle"
                      color="red"
                      leftSection={<XCircle size={14} />}
                      loading={busy && reject.isPending}
                      disabled={busy && approve.isPending}
                      onClick={() =>
                        reject.mutate({ id: r.id, decisionNote: notes[r.id] || undefined })
                      }
                    >
                      Reject
                    </Button>
                    <Button
                      size="compact-sm"
                      color="edr-green"
                      leftSection={<CheckCircle2 size={14} />}
                      loading={busy && approve.isPending}
                      disabled={busy && reject.isPending}
                      onClick={() =>
                        approve.mutate({ id: r.id, decisionNote: notes[r.id] || undefined })
                      }
                    >
                      Approve &amp; apply
                    </Button>
                  </Group>
                ) : (
                  <Tooltip label="You need the rates approve permission to decide this">
                    <Badge variant="light" color="gray" radius="sm">
                      Awaiting approver
                    </Badge>
                  </Tooltip>
                )}
              </Group>

              <Collapse in={isOpen}>
                <Stack gap={6} mt="sm" pt="sm" style={{ borderTop: "1px solid var(--mantine-color-default-border)" }}>
                  {fields.map((field) => (
                    <Group key={field} gap={8} wrap="nowrap">
                      <Text size="xs" c="dimmed" w={110} style={{ flexShrink: 0 }}>
                        {FIELD_LABELS[field] ?? field}
                      </Text>
                      <Text size="sm" c="dimmed" td="line-through">
                        {fmtValue(field, r.previousValues[field], yardLabels)}
                      </Text>
                      <ArrowRight size={13} />
                      <Text size="sm" fw={600}>
                        {fmtValue(field, r.payload[field], yardLabels)}
                      </Text>
                    </Group>
                  ))}
                  {canDecide ? (
                    <Textarea
                      mt={4}
                      size="xs"
                      autosize
                      minRows={2}
                      label="Decision note (optional)"
                      placeholder="Shown to the requester with your decision"
                      value={notes[r.id] ?? ""}
                      onChange={(e) =>
                        setNotes((prev) => ({ ...prev, [r.id]: e.currentTarget.value }))
                      }
                    />
                  ) : null}
                </Stack>
              </Collapse>
            </Card>
          );
        })}
      </Stack>
    </Card>
  );
};

export default RateApprovalsSection;
