import { useMemo, useState } from "react";
import { Check, 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 { SectionCard } from "@/components/bookings/detail/SectionCard";
import type { useContractMutations } from "@/hooks/contracts/useContracts";

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 [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: ${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}
                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">
              {pendingStep?.requiredRole}
            </Text>{" "}
            step for contract{" "}
            <Text span fw={600} c="dark">
              {contract.reference}
            </Text>
            . This action cannot be undone from this screen.
          </Text>
          <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: `${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">
                {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">
                {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?.requiredRole ?? "step"}`
                : "Reject contract"}
            </Button>
          </Group>
        </Stack>
      </Modal>
    </>
  );
}

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

  return (
    <Group
      justify="space-between"
      wrap="nowrap"
      gap="sm"
      px="sm"
      py="xs"
      style={{
        borderRadius: 8,
        border: "1px solid var(--mantine-color-gray-2)",
        borderLeft: isNext
          ? "3px solid var(--freight-brand)"
          : "1px solid var(--mantine-color-gray-2)",
        background: 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 }}>
          <Text size="sm" fw={600}>
            {step.requiredRole}
          </Text>
          {step.note && (
            <Text size="xs" c="dimmed" truncate>
              {step.note}
            </Text>
          )}
        </Box>
      </Group>
      <Group gap="xs" wrap="nowrap" style={{ flexShrink: 0 }}>
        {isNext && 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>
  );
}
