import type { Freight } from "@edr/types";
import {
  Badge,
  Button,
  Group,
  Modal,
  Stack,
  Text,
  Textarea,
  Tooltip,
} from "@mantine/core";
import { useMutation } from "@tanstack/react-query";
import { useState } from "react";
import { useAuth } from "@/auth/useAuth";
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
import { api } from "@/services/api";

import type {
  CompanyNationality,
  CompanyProfile,
  CompanyStatus,
  CompanyType,
  CustomerBookingStatus,
  CustomerPaymentStatus,
  ProfileStatus,
  ProfileType,
} from "@/types/customer";

import { humanize } from "./format";

const badgeStyle = {
  fontSize: "0.7rem",
  letterSpacing: "0.04em",
  whiteSpace: "nowrap" as const,
};

/** Shared status palette — active/paid green, pending amber, terminal red. */
const STATUS_COLOR: Record<CompanyStatus | ProfileStatus, string> = {
  active: "edr-green",
  pending: "yellow",
  rejected: "red",
  suspended: "orange",
  blacklisted: "red",
};

const COMPANY_TYPE_COLOR: Record<CompanyType, string> = {
  customer: "edr-green",
  freight_forwarder: "blue",
  dj_freight_forwarder: "indigo",
  transporter: "grape",
};

const PROFILE_TYPE_COLOR: Record<ProfileType, string> = {
  importer: "teal",
  exporter: "cyan",
  freight_forwarder: "blue",
  dj_freight_forwarder: "indigo",
  transporter: "grape",
  transit_agent: "lime",
};

export function CompanyStatusBadge({ status }: { status: CompanyStatus }) {
  return (
    <Badge
      color={STATUS_COLOR[status] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      tt="capitalize"
      fw={600}
      style={badgeStyle}
    >
      {status}
    </Badge>
  );
}

export function CompanyTypeBadge({ type }: { type: CompanyType }) {
  return (
    <Badge
      color={COMPANY_TYPE_COLOR[type] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      fw={600}
      style={badgeStyle}
    >
      {humanize(type)}
    </Badge>
  );
}

const NATIONALITY_COLOR: Record<CompanyNationality, string> = {
  ethiopian: "edr-green",
  foreign: "blue",
};

export function CompanyNationalityBadge({
  nationality,
}: {
  nationality?: CompanyNationality | null;
}) {
  if (!nationality) return null;
  return (
    <Badge
      color={NATIONALITY_COLOR[nationality] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      fw={600}
      style={badgeStyle}
    >
      {humanize(nationality)}
    </Badge>
  );
}

/**
 * The company's registration was typed, not fetched from eTrade — nothing in it
 * has been checked against a licence. Loud on purpose: it is the one thing a
 * reviewer must not miss about this customer. Two kinds of company land here
 * for different reasons, and the badge names which.
 */
export function ManualRegistrationBadge({
  cooperative,
  investorLicence,
}: {
  cooperative?: boolean | null;
  investorLicence?: boolean | null;
}) {
  if (!cooperative && !investorLicence) return null;
  return (
    <Badge
      color="orange"
      variant="light"
      size="sm"
      radius="md"
      fw={600}
      style={badgeStyle}
    >
      {cooperative
        ? "Manual entry · co-operative"
        : "Manual entry · investment licence"}
    </Badge>
  );
}

/**
 * Profile chips for a company row: one chip per role (Importer / Exporter / …)
 * carrying its reference code, colored by the profile's status (green active,
 * amber pending, red rejected/blacklisted). Caps at three (a company has at
 * most three profiles); any extra collapse into a `+N` chip.
 */
export function ProfileChips({
  profiles,
  max = 3,
}: {
  profiles: CompanyProfile[];
  max?: number;
}) {
  if (!profiles.length) {
    return (
      <Badge
        color="gray"
        variant="light"
        size="sm"
        radius="md"
        style={badgeStyle}
      >
        No profiles
      </Badge>
    );
  }

  const shown = profiles.slice(0, max);
  const extra = profiles.length - shown.length;

  return (
    <Group gap={6} wrap="wrap">
      {shown.map((profile) => (
        <Tooltip
          key={profile.id}
          label={`${humanize(profile.type)} · ${humanize(profile.status)}`}
          withArrow
        >
          <Badge
            color={STATUS_COLOR[profile.status] ?? "gray"}
            variant="light"
            size="sm"
            radius="md"
            fw={600}
            style={badgeStyle}
          >
            {humanize(profile.type)}
            {profile.reference ? ` · ${profile.reference}` : ""}
          </Badge>
        </Tooltip>
      ))}
      {extra > 0 ? (
        <Badge
          color="gray"
          variant="light"
          size="sm"
          radius="md"
          style={badgeStyle}
        >
          +{extra}
        </Badge>
      ) : null}
    </Group>
  );
}

export function ProfileTypeBadge({ type }: { type: ProfileType }) {
  return (
    <Badge
      color={PROFILE_TYPE_COLOR[type] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      fw={600}
      style={badgeStyle}
    >
      {humanize(type)}
    </Badge>
  );
}

export function ProfileStatusBadge({ status }: { status: ProfileStatus }) {
  return (
    <Badge
      color={STATUS_COLOR[status] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      tt="capitalize"
      fw={600}
      style={badgeStyle}
    >
      {status}
    </Badge>
  );
}

const BOOKING_STATUS_COLOR: Record<CustomerBookingStatus, string> = {
  DRAFT: "gray",
  SUBMITTED: "yellow",
  PENDING_APPROVAL: "yellow",
  APPROVED: "cyan",
  PAID: "edr-green",
  IN_TRANSIT: "blue",
  ARRIVED: "teal",
  COMPLETED: "indigo",
  REJECTED: "red",
  CANCELLED: "red",
};

export function BookingStatusBadge({
  status,
}: {
  status: CustomerBookingStatus;
}) {
  return (
    <Badge
      color={BOOKING_STATUS_COLOR[status] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      tt="uppercase"
      fw={600}
      style={badgeStyle}
    >
      {humanize(status)}
    </Badge>
  );
}

const PAYMENT_STATUS_COLOR: Record<CustomerPaymentStatus, string> = {
  "action-required": "orange",
  processing: "yellow",
  success: "edr-green",
  failed: "red",
  canceled: "gray",
  refunded: "grape",
};

export function PaymentStatusBadge({
  status,
}: {
  status: CustomerPaymentStatus;
}) {
  return (
    <Badge
      color={PAYMENT_STATUS_COLOR[status] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      tt="capitalize"
      fw={600}
      style={badgeStyle}
    >
      {humanize(status)}
    </Badge>
  );
}

const INVOICE_STATUS_COLOR: Record<Freight.InvoiceStatus, string> = {
  DRAFT: "gray",
  ISSUED: "cyan",
  PENDING: "yellow",
  PAYMENT_PROCESSING: "indigo",
  PARTIALLY_PAID: "orange",
  PAID: "edr-green",
  OVERDUE: "red",
  CANCELLED: "gray",
  REFUNDED: "grape",
  EXPIRED: "red",
};

export function InvoiceStatusBadge({
  status,
}: {
  status: Freight.InvoiceStatus;
}) {
  return (
    <Badge
      color={INVOICE_STATUS_COLOR[status] ?? "gray"}
      variant="light"
      size="sm"
      radius="md"
      tt="capitalize"
      fw={600}
      style={badgeStyle}
    >
      {humanize(status)}
    </Badge>
  );
}

/**
 * Inline approval action buttons for a profile row.
 * Transitions: pending → approve / reject-with-note | rejected → undo-rejection (→ pending) |
 * active → suspend | suspended → reactivate/blacklist | blacklisted → reinstate.
 * Rejecting captures a note the customer sees so they can fix and reapply — a
 * rejected role is theirs to resubmit, so it cannot be approved from here until
 * they do (the API refuses it); undoing the rejection is the only way back.
 *
 * `locked` (customer hasn't submitted onboarding) withholds the review decision
 * only — there's no application to judge yet, and the API rejects the call
 * regardless (setCompanyProfileStatus). Suspend/blacklist/reinstate stay live so
 * an already-active profile is still managable.
 */
/**
 * Which permission each status write needs. Mirrors `STATUS_PERM` in the API's
 * `companies.controller.ts` — approving is a different authority from
 * suspending, and both go through the same endpoint. Keep the two in step.
 */
const STATUS_PERM: Record<ProfileStatus, string> = {
  active: FREIGHT_PERMS.customers.verify,
  pending: FREIGHT_PERMS.customers.verify,
  rejected: FREIGHT_PERMS.customers.verify,
  suspended: FREIGHT_PERMS.customers.deactivate,
  blacklisted: FREIGHT_PERMS.customers.deactivate,
};

export function ProfileApprovalActions({
  profileId,
  status,
  locked = false,
}: {
  profileId: string;
  status: ProfileStatus;
  locked?: boolean;
}) {
  const { user } = useAuth();
  /** The API rejects these anyway — hide rather than offer a button that 403s. */
  const canSet = (next: ProfileStatus) =>
    hasPermission(user, STATUS_PERM[next]);
  const { mutate, isPending } = useMutation(
    api.customers.setProfileStatus.mutationOptions(),
  );
  const [decision, setDecision] = useState<
    "reject" | "suspend" | "reactivate" | null
  >(null);
  const [note, setNote] = useState("");

  const act = (next: ProfileStatus) => mutate({ profileId, status: next });

  // Decisions the customer must be given a reason for. Reject/suspend/reactivate
  // all capture a required message through the same modal; the API refuses
  // suspend/reactivate without one.
  const DECISIONS = {
    reject: {
      title: "Reject profile",
      intro:
        "Tell the customer what needs fixing. They'll see this note and can " +
        "amend and resubmit the role for approval.",
      label: "Reason for rejection",
      placeholder: "e.g. The uploaded business license is expired.",
      confirmLabel: "Reject profile",
      color: "red",
      status: "rejected" as ProfileStatus,
    },
    suspend: {
      title: "Suspend role",
      intro:
        "Explain why this role is being suspended. The customer will see this " +
        "message and cannot operate under the role until it is reactivated.",
      label: "Reason for suspension",
      placeholder: "e.g. Outstanding invoices unpaid for over 90 days.",
      confirmLabel: "Suspend role",
      color: "orange",
      status: "suspended" as ProfileStatus,
    },
    reactivate: {
      title: "Reactivate role",
      intro:
        "Explain why this role is being reactivated. The customer will see " +
        "this message and can operate under the role again.",
      label: "Reactivation message",
      placeholder: "e.g. Outstanding payments have been settled.",
      confirmLabel: "Reactivate role",
      color: "edr-green",
      status: "active" as ProfileStatus,
    },
  } as const;

  const openDecision = (kind: keyof typeof DECISIONS) => {
    setNote("");
    setDecision(kind);
  };

  const active = decision ? DECISIONS[decision] : null;

  const confirmDecision = () => {
    if (!active) return;
    mutate(
      { profileId, status: active.status, note: note.trim() },
      { onSuccess: () => setDecision(null) },
    );
  };

  const decisionModal = active && (
    <Modal
      opened
      onClose={() => setDecision(null)}
      title={active.title}
      centered
      radius="lg"
    >
      <Stack gap="md">
        <Text size="sm" c="dimmed">
          {active.intro}
        </Text>
        <Textarea
          label={active.label}
          placeholder={active.placeholder}
          autosize
          minRows={3}
          value={note}
          onChange={(e) => setNote(e.currentTarget.value)}
          required
        />
        <Group justify="flex-end" gap="sm">
          <Button
            variant="default"
            onClick={() => setDecision(null)}
            disabled={isPending}
          >
            Cancel
          </Button>
          <Button
            color={active.color}
            loading={isPending}
            disabled={note.trim().length === 0}
            onClick={confirmDecision}
          >
            {active.confirmLabel}
          </Button>
        </Group>
      </Stack>
    </Modal>
  );

  // Pending/rejected are the two states awaiting a reviewer's decision — the
  // exact pair the API gates on until the customer submits.
  if (locked && (status === "pending" || status === "rejected")) {
    return (
      <Tooltip label="Available once the customer submits their onboarding application">
        <Text size="xs" c="dimmed" fs="italic">
          Awaiting submission
        </Text>
      </Tooltip>
    );
  }

  if (status === "pending") {
    if (!canSet("active") && !canSet("rejected")) return null;
    return (
      <>
        {decisionModal}
        <Group gap={6} wrap="nowrap">
          {canSet("active") && (
            <Button
              size="xs"
              variant="light"
              color="edr-green"
              radius="md"
              loading={isPending}
              onClick={() => act("active")}
            >
              Approve
            </Button>
          )}
          {canSet("rejected") && (
            <Button
              size="xs"
              variant="light"
              color="red"
              radius="md"
              onClick={() => openDecision("reject")}
            >
              Reject
            </Button>
          )}
        </Group>
      </>
    );
  }

  if (status === "rejected") {
    // No Approve here: the role is waiting on the customer to fix what was
    // flagged and resubmit it, and the API refuses rejected → active outright.
    // All that's left is undoing a rejection that shouldn't have happened,
    // which puts the role back in the queue rather than into service.
    if (!canSet("pending")) return null;
    return (
      <Group gap={8} wrap="nowrap">
        <Text size="xs" c="dimmed" fs="italic">
          Awaiting customer resubmission
        </Text>
        <Tooltip
          multiline
          w={260}
          label="Puts the role back in the pending queue and clears the rejection note. Use only if the rejection itself was a mistake — it does not approve the role."
        >
          <Button
            size="xs"
            variant="subtle"
            color="gray"
            radius="md"
            loading={isPending}
            onClick={() => act("pending")}
          >
            Undo rejection
          </Button>
        </Tooltip>
      </Group>
    );
  }

  if (status === "active") {
    if (!canSet("suspended")) return null;
    return (
      <>
        {decisionModal}
        <Button
          size="xs"
          variant="light"
          color="orange"
          radius="md"
          loading={isPending}
          onClick={() => openDecision("suspend")}
        >
          Suspend
        </Button>
      </>
    );
  }

  if (status === "suspended") {
    if (!canSet("active") && !canSet("blacklisted")) return null;
    return (
      <Group gap={6} wrap="nowrap">
        {decisionModal}
        {canSet("active") && (
          <Button
            size="xs"
            variant="light"
            color="edr-green"
            radius="md"
            loading={isPending}
            onClick={() => openDecision("reactivate")}
          >
            Reactivate
          </Button>
        )}
        {canSet("blacklisted") && (
          <Button
            size="xs"
            variant="light"
            color="red"
            radius="md"
            loading={isPending}
            onClick={() => act("blacklisted")}
          >
            Blacklist
          </Button>
        )}
      </Group>
    );
  }

  if (status === "blacklisted") {
    if (!canSet("pending")) return null;
    return (
      <Button
        size="xs"
        variant="light"
        color="gray"
        radius="md"
        loading={isPending}
        onClick={() => act("pending")}
      >
        Reinstate
      </Button>
    );
  }

  return null;
}
