import { useMemo, useState } from "react";
import { Check, Flame, ShieldCheck, X } from "lucide-react";
import {
  Stack,
  Group,
  Text,
  Badge,
  Button,
  Box,
  Modal,
  Select,
  Textarea,
} from "@mantine/core";
import type { Freight } from "@edr/types";

import { formatContractApprovalProgress } from "@/features/contracts/contract-approval-progress";
import { HazardDeclarationPanel } from "./HazardDeclarationPanel";
import { SectionCard } from "@/components/bookings/detail/SectionCard";
import type { useContractMutations } from "@/hooks/contracts/useContracts";
import { useAuth } from "@/auth/useAuth";
import {
  canApproveContractStep,
  CONTRACT_APPROVAL_ROLE_LABELS,
  HAZARDOUS_APPROVAL_ROLE_PERMISSION,
} from "@/lib/permissions";

/** Chain roles that exist only because the contract carries dangerous goods. */
const isHazardStep = (requiredRole: string): boolean =>
  requiredRole in HAZARDOUS_APPROVAL_ROLE_PERMISSION;

const roleLabel = (requiredRole: string): string =>
  CONTRACT_APPROVAL_ROLE_LABELS[requiredRole] ?? requiredRole;

type Mutations = ReturnType<typeof useContractMutations>;

interface ContractApprovalStepsCardProps {
  contract: Freight.IContract;
  mutations: Mutations;
}

/** Approval chain with inline approve on the next pending step. */
export function ContractApprovalStepsCard({
  contract,
  mutations,
}: ContractApprovalStepsCardProps) {
  const { user } = useAuth();
  const [confirmOpen, setConfirmOpen] = useState(false);
  const [pendingStep, setPendingStep] =
    useState<Freight.IContractApprovalStep | null>(null);
  const [rejectOpen, setRejectOpen] = useState(false);
  const [rejectStepRow, setRejectStepRow] =
    useState<Freight.IContractApprovalStep | null>(null);
  const [rejectReason, setRejectReason] = useState("");
  // Where the rejection lands: "CUSTOMER" (terminal, resubmit) or the id of an
  // earlier APPROVED step to send the chain back to. First approver has no
  // choice — customer only.
  const [rejectTarget, setRejectTarget] = useState<string>("CUSTOMER");

  const steps = useMemo(
    () =>
      [...(contract.approvalSteps ?? [])].sort(
        (a, b) => a.stepOrder - b.stepOrder,
      ),
    [contract.approvalSteps],
  );

  const nextPending = steps.find((s) => s.status === "PENDING");
  const summary = formatContractApprovalProgress(contract.status, steps);
  // The card also renders read-only trails (e.g. a REJECTED contract) — only
  // offer approve/reject while the backend accepts step actions.
  const actionable =
    contract.status === "PENDING_APPROVAL" ||
    contract.status === "APPROVED_PENDING_SIGNATURE";

  // Approvers review a live preview of the document; there is no PDF to
  // generate first — the final approval is what produces it.
  const openApprove = (step: Freight.IContractApprovalStep) => {
    setPendingStep(step);
    setConfirmOpen(true);
  };

  const closeApprove = () => {
    setConfirmOpen(false);
    setPendingStep(null);
  };

  const runApprove = () => {
    if (!pendingStep) return;
    mutations.approveStep.mutate(
      { stepId: pendingStep.id },
      { onSuccess: () => closeApprove() },
    );
  };

  const openReject = (step: Freight.IContractApprovalStep) => {
    setRejectStepRow(step);
    setRejectReason("");
    setRejectTarget("CUSTOMER");
    setRejectOpen(true);
  };

  const closeReject = () => {
    setRejectOpen(false);
    setRejectStepRow(null);
    setRejectReason("");
    setRejectTarget("CUSTOMER");
  };

  const trimmedReason = rejectReason.trim();

  // Earlier stages this rejection can be returned to — only stages that have
  // already approved. Empty for the first approver, whose only target is the
  // customer.
  const returnableSteps = rejectStepRow
    ? steps.filter(
        (s) =>
          s.stepOrder < rejectStepRow.stepOrder && s.status === "APPROVED",
      )
    : [];

  const sendBack = rejectTarget !== "CUSTOMER";
  const targetStep = sendBack
    ? returnableSteps.find((s) => s.id === rejectTarget)
    : undefined;

  const runReject = () => {
    if (!rejectStepRow || !trimmedReason) return;
    mutations.rejectStep.mutate(
      {
        stepId: rejectStepRow.id,
        reason: trimmedReason,
        returnToStepId: sendBack ? rejectTarget : undefined,
      },
      { onSuccess: () => closeReject() },
    );
  };

  const subtitle =
    summary.detail ||
    (nextPending
      ? `Next: ${roleLabel(nextPending.requiredRole)} · step ${nextPending.stepOrder}`
      : steps.length
        ? "All steps complete"
        : "Accept submission to begin");

  return (
    <>
      <SectionCard
        icon={ShieldCheck}
        title="Approval chain"
        extra={
          <Badge color="edr-green" variant="light" radius="sm">
            {steps.filter((s) => s.status === "APPROVED").length}/{steps.length}
          </Badge>
        }
      >
        <Text size="xs" c="dimmed" mb="sm">
          {subtitle}
        </Text>

        {steps.length === 0 ? (
          <Text
            size="sm"
            c="dimmed"
            ta="center"
            py="lg"
            px="md"
            style={{
              borderRadius: 8,
              border: "1px dashed var(--mantine-color-gray-3)",
              background: "var(--mantine-color-gray-0)",
            }}
          >
            Use <strong>Accept for approval</strong> in staff actions to
            instantiate steps.
          </Text>
        ) : (
          <Stack gap="xs">
            {steps.map((step) => (
              <StepRow
                key={step.id}
                step={step}
                isNext={actionable && nextPending?.id === step.id}
                // Buttons show only to the step's actual approver (matching
                // position type): a chief step never offers Approve/Reject to a
                // marketing officer. Everyone still sees the "next" highlight.
                canAct={canApproveContractStep(user, step.requiredRole)}
                isPending={
                  mutations.approveStep.isPending ||
                  mutations.rejectStep.isPending
                }
                onApprove={() => openApprove(step)}
                onReject={() => openReject(step)}
              />
            ))}
          </Stack>
        )}
      </SectionCard>

      <Modal
        opened={confirmOpen}
        onClose={closeApprove}
        title="Approve this step?"
        radius="md"
        centered
      >
        <Stack gap="md">
          <Text size="sm" c="dimmed">
            You are about to approve the{" "}
            <Text span fw={600} c="dark">
              {roleLabel(pendingStep?.requiredRole ?? "")}
            </Text>{" "}
            step for contract{" "}
            <Text span fw={600} c="dark">
              {contract.reference}
            </Text>
            . This action cannot be undone from this screen.
          </Text>
          {pendingStep && isHazardStep(pendingStep.requiredRole) && (
            <HazardDeclarationPanel contract={contract} />
          )}
          <Group justify="flex-end" gap="sm">
            <Button variant="default" radius="md" onClick={closeApprove}>
              Cancel
            </Button>
            <Button
              color="edr-green"
              radius="md"
              leftSection={<Check size={16} />}
              loading={mutations.approveStep.isPending}
              onClick={runApprove}
            >
              Confirm approval
            </Button>
          </Group>
        </Stack>
      </Modal>


      <Modal
        opened={rejectOpen}
        onClose={closeReject}
        title="Reject this step?"
        radius="md"
        centered
      >
        <Stack gap="md">
          {returnableSteps.length > 0 && (
            <Select
              label="Send rejection to"
              description="Return the contract to an earlier approver to fix and re-approve, or reject it to the customer."
              allowDeselect={false}
              value={rejectTarget}
              onChange={(v) => setRejectTarget(v ?? "CUSTOMER")}
              data={[
                { value: "CUSTOMER", label: "Customer — must resubmit" },
                ...returnableSteps.map((s) => ({
                  value: s.id,
                  label: `${roleLabel(s.requiredRole)} — step ${s.stepOrder} re-approves`,
                })),
              ]}
            />
          )}
          {sendBack ? (
            <Text size="sm" c="dimmed">
              Contract{" "}
              <Text span fw={600} c="dark">
                {contract.reference}
              </Text>{" "}
              will go back to the{" "}
              <Text span fw={600} c="dark">
                {roleLabel(targetStep?.requiredRole ?? "")}
              </Text>{" "}
              step. That approver fixes the contract and approves again, and
              every later step re-approves in order. The customer is not
              notified.
            </Text>
          ) : (
            <Text size="sm" c="dimmed">
              Rejecting the{" "}
              <Text span fw={600} c="dark">
                {roleLabel(rejectStepRow?.requiredRole ?? "")}
              </Text>{" "}
              step rejects contract{" "}
              <Text span fw={600} c="dark">
                {contract.reference}
              </Text>{" "}
              outright. The customer must resubmit — this cannot be undone.
            </Text>
          )}
          <Textarea
            label="Reason for rejection"
            description={
              sendBack
                ? "Shared with the approval chain (not the customer)."
                : "Shared with the customer and the approval chain."
            }
            placeholder="Explain why this contract is rejected…"
            minRows={3}
            autosize
            withAsterisk
            value={rejectReason}
            onChange={(e) => setRejectReason(e.currentTarget.value)}
          />
          <Group justify="flex-end" gap="sm">
            <Button variant="default" radius="md" onClick={closeReject}>
              Cancel
            </Button>
            <Button
              color={sendBack ? "orange" : "red"}
              radius="md"
              leftSection={<X size={16} />}
              loading={mutations.rejectStep.isPending}
              disabled={!trimmedReason}
              onClick={runReject}
            >
              {sendBack
                ? `Send back to ${targetStep ? roleLabel(targetStep.requiredRole) : "step"}`
                : "Reject contract"}
            </Button>
          </Group>
        </Stack>
      </Modal>
    </>
  );
}

function StepRow({
  step,
  isNext,
  canAct,
  isPending,
  onApprove,
  onReject,
}: {
  step: Freight.IContractApprovalStep;
  isNext: boolean;
  canAct: boolean;
  isPending: boolean;
  onApprove: () => void;
  onReject: () => void;
}) {
  const statusColor =
    step.status === "APPROVED"
      ? "edr-green"
      : step.status === "REJECTED"
        ? "red"
        : isNext
          ? "edr-green"
          : "gray";
  const hazard = isHazardStep(step.requiredRole);

  return (
    <Group
      justify="space-between"
      wrap="nowrap"
      gap="sm"
      px="sm"
      py="xs"
      style={{
        borderRadius: 8,
        border: hazard
          ? "1px solid #F3D5D0"
          : "1px solid var(--mantine-color-gray-2)",
        borderLeft: isNext
          ? `3px solid ${hazard ? "#C0392B" : "var(--freight-brand)"}`
          : hazard
            ? "1px solid #F3D5D0"
            : "1px solid var(--mantine-color-gray-2)",
        background: hazard
          ? "#FEF7F6"
          : isNext
            ? "var(--mantine-color-gray-0)"
            : "white",
      }}
    >
      <Group gap="sm" wrap="nowrap" style={{ minWidth: 0 }}>
        <Box
          style={{
            display: "flex",
            alignItems: "center",
            justifyContent: "center",
            width: 28,
            height: 28,
            borderRadius: 8,
            flexShrink: 0,
            fontSize: 12,
            fontWeight: 700,
            background: "var(--mantine-color-gray-1)",
            color: isNext
              ? "var(--mantine-color-gray-7)"
              : "var(--mantine-color-gray-6)",
          }}
        >
          {step.stepOrder}
        </Box>
        <Box style={{ minWidth: 0 }}>
          <Group gap={6} wrap="nowrap" align="center">
            <Text size="sm" fw={600} truncate>
              {roleLabel(step.requiredRole)}
            </Text>
            {hazard && (
              <Badge
                color="red"
                variant="light"
                size="xs"
                radius="sm"
                leftSection={<Flame size={10} />}
                style={{ flexShrink: 0 }}
              >
                Hazmat
              </Badge>
            )}
          </Group>
          {step.note && (
            <Text size="xs" c="dimmed" truncate>
              {step.note}
            </Text>
          )}
        </Box>
      </Group>
      {/* One element type per row: action buttons on the active step (they
          already imply "pending & actionable"), a status badge otherwise.
          Mixing compact buttons + a badge here made them read as misaligned. */}
      <Group gap="xs" wrap="nowrap" align="center" style={{ flexShrink: 0 }}>
        {isNext && canAct && step.status === "PENDING" ? (
          <>
            <Button
              size="compact-sm"
              color="edr-green"
              leftSection={<Check size={14} />}
              disabled={isPending}
              onClick={onApprove}
            >
              Approve
            </Button>
            <Button
              size="compact-sm"
              variant="light"
              color="red"
              leftSection={<X size={14} />}
              disabled={isPending}
              onClick={onReject}
            >
              Reject
            </Button>
          </>
        ) : (
          <Badge
            variant="light"
            color={statusColor}
            size="sm"
            radius="sm"
            tt="uppercase"
          >
            {step.status}
          </Badge>
        )}
      </Group>
    </Group>
  );
}
