import {
  Alert,
  Anchor,
  Badge,
  Box,
  Button,
  Card,
  Group,
  Modal,
  SimpleGrid,
  Stack,
  Text,
  Textarea,
} from "@mantine/core";
import { useQuery, useMutation } from "@tanstack/react-query";
import {
  AlertTriangle,
  ClipboardCheck,
  Clock,
  FilePlus2,
  FileX2,
} from "lucide-react";
import { useState } from "react";
import { useFileViewer } from "@edr/ui-common";

import { useAuth } from "@/auth/useAuth";
import { FREIGHT_PERMS, hasPermission } from "@/lib/permissions";
import { fetchViewableFile } from "@/services/files.service";
import { api } from "@/services/api";
import type { Company, CompanyChangeRequest } from "@/types/customer";
import { formatDate, humanize } from "./format";

/** Friendly labels for the proposed-change snapshot keys (UpdateProfileDto). */
const FIELD_LABELS: Record<string, string> = {
  companyName: "Company name",
  companyEmail: "Company email",
  companyPhone: "Company phone",
  companyLocation: "Location",
  companyAddress: "Address",
  tin: "TIN",
  vatNumber: "VAT number",
  fanNumber: "FAN number",
  nationality: "Nationality",
  licenceNumber: "Licence number",
  contactPersonName: "Contact person",
  contactPersonPosition: "Contact position",
  contactPersonEmail: "Contact email",
  contactPersonPhone: "Contact phone",
  generalManagerName: "General manager",
  generalManagerEmail: "GM email",
  generalManagerPhone: "GM phone",
  poaName: "PoA name",
  poaPhone: "PoA phone",
  poaEmail: "PoA email",
  poaLocation: "PoA location",
  poaAddress: "PoA address",
  region: "Region",
  zone: "Zone",
  woreda: "Woreda",
  kebele: "Kebele",
  houseNo: "House no.",
};

/** Best-effort current value on the live company for a proposed field key. */
function currentValue(company: Company, key: string): string {
  const c = company as unknown as Record<string, unknown>;
  const attrs = (company.attributes ?? {}) as Record<string, unknown>;
  const map: Record<string, unknown> = {
    companyName: c.name,
    companyEmail: c.email,
    companyPhone: c.phone,
    companyLocation: c.country,
    companyAddress: c.address,
    tin: c.tin,
    vatNumber: c.vatNumber,
    fanNumber: c.fanNumber,
    nationality: c.nationality,
    contactPersonName: c.contactPersonName ?? attrs.contactPersonName,
    contactPersonPhone: c.contactPersonPhone ?? attrs.contactPersonPhone,
    generalManagerName: c.generalManagerName ?? attrs.generalManagerName,
    generalManagerEmail: c.generalManagerEmail ?? attrs.generalManagerEmail,
    generalManagerPhone: c.generalManagerPhone ?? attrs.generalManagerPhone,
  };
  const v = key in map ? map[key] : (c[key] ?? attrs[key]);
  return v === null || v === undefined || v === "" ? "—" : String(v);
}

function DiffRow({
  label,
  from,
  to,
}: {
  label: string;
  from: string;
  to: string;
}) {
  const changed = from !== to;
  return (
    <Stack gap={2}>
      <Text size="xs" fw={600} c="edr-muted" tt="uppercase">
        {label}
      </Text>
      <Group gap={8} wrap="nowrap" align="center">
        <Text
          size="sm"
          c="dimmed"
          td={changed ? "line-through" : undefined}
          style={{ wordBreak: "break-word" }}
        >
          {from}
        </Text>
        {changed && (
          <>
            <Text size="sm" c="edr-muted">
              →
            </Text>
            <Text size="sm" fw={600} c="edr-text">
              {to}
            </Text>
          </>
        )}
      </Group>
    </Stack>
  );
}

/**
 * Backoffice review surface for a customer's staged profile edits. Shows the
 * pending change request as a proposed-vs-current diff with Approve / Reject
 * (with note) actions, plus a short history of past decisions.
 */
export function ChangeRequestReview({ company }: { company: Company }) {
  const { user } = useAuth();
  const canReview = hasPermission(user, FREIGHT_PERMS.customers.verify);
  const query = useQuery(
    api.customers.changeRequests.queryOptions({ input: { id: company.id } }),
  );
  const approve = useMutation(
    api.customers.approveChangeRequest.mutationOptions(),
  );
  const reject = useMutation(
    api.customers.rejectChangeRequest.mutationOptions(),
  );

  const { view, viewer } = useFileViewer();
  const [rejectId, setRejectId] = useState<string | null>(null);
  const [note, setNote] = useState("");

  const requests = query.data ?? [];
  const pending = requests.find((r) => r.status === "pending");
  const history = requests.filter((r) => r.status !== "pending").slice(0, 5);

  if (!pending && history.length === 0) return null;

  const proposedKeys = pending
    ? Object.keys(pending.snapshot ?? {})
    : ([] as string[]);
  const docCount = pending?.documentFileIds?.length ?? 0;
  const licenseChanges = pending?.licenseChanges ?? [];
  const documentChanges = pending?.documentChanges ?? [];

  const confirmReject = () => {
    if (!rejectId) return;
    reject.mutate(
      { id: rejectId, note: note.trim() },
      {
        onSuccess: () => {
          setRejectId(null);
          setNote("");
        },
      },
    );
  };

  return (
    <>
      {pending && (
        <Card withBorder>
          <Stack gap="md">
            <Group justify="space-between">
              <Group gap="sm">
                <ClipboardCheck size={18} className="text-edr-muted" />
                <Text fw={600} c="edr-text">
                  Profile changes awaiting review
                </Text>
                <Badge color="yellow" variant="light" radius="md">
                  Pending
                </Badge>
              </Group>
              <Text size="xs" c="dimmed">
                Submitted {formatDate(pending.submittedAt ?? pending.createdAt)}
              </Text>
            </Group>

            {proposedKeys.length > 0 ? (
              <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="lg">
                {proposedKeys.map((key) => (
                  <DiffRow
                    key={key}
                    label={FIELD_LABELS[key] ?? humanize(key)}
                    from={currentValue(company, key)}
                    to={
                      pending.snapshot[key] === null ||
                      pending.snapshot[key] === undefined ||
                      pending.snapshot[key] === ""
                        ? "—"
                        : String(pending.snapshot[key])
                    }
                  />
                ))}
              </SimpleGrid>
            ) : (
              <Text size="sm" c="dimmed">
                No field changes — document uploads only.
              </Text>
            )}

            {documentChanges.length > 0 && (
              <Stack gap={8}>
                <Text size="sm" fw={600} c="edr-text">
                  Document changes
                </Text>
                {documentChanges.map((c, i) => (
                  <Group key={`${c.fileId}-${i}`} gap={8} wrap="nowrap">
                    {c.op === "add" ? (
                      <FilePlus2 size={15} className="text-edr-muted" />
                    ) : (
                      <FileX2 size={15} className="text-edr-muted" />
                    )}
                    <Badge
                      size="sm"
                      radius="sm"
                      variant="light"
                      color={c.op === "add" ? "green" : "red"}
                    >
                      {c.op === "add" ? "Add" : "Remove"}
                    </Badge>
                    <Anchor
                      component="button"
                      type="button"
                      size="sm"
                      onClick={() =>
                        void fetchViewableFile(
                          c.fileId,
                          c.fileName ?? humanize(c.code),
                        ).then(view)
                      }
                      style={{
                        textDecoration:
                          c.op === "remove" ? "line-through" : undefined,
                      }}
                    >
                      {c.fileName ?? humanize(c.code)}
                    </Anchor>
                    <Text size="xs" c="dimmed">
                      {humanize(c.code)}
                    </Text>
                  </Group>
                ))}
              </Stack>
            )}

            {docCount > 0 && (
              <Stack gap={8}>
                <Text size="sm" fw={600} c="edr-text">
                  Documents uploaded with this request
                </Text>
                {pending!.documentFileIds.map((fileId, i) => (
                  <Group key={fileId} gap={8} wrap="nowrap">
                    <FilePlus2 size={15} className="text-edr-muted" />
                    <Anchor
                      component="button"
                      type="button"
                      size="sm"
                      onClick={() =>
                        void fetchViewableFile(fileId, `Document ${i + 1}`).then(
                          view,
                        )
                      }
                    >
                      Document {i + 1}
                    </Anchor>
                  </Group>
                ))}
              </Stack>
            )}

            {licenseChanges.length > 0 && (
              <Stack gap={8}>
                <Text size="sm" fw={600} c="edr-text">
                  Business license changes
                </Text>
                {licenseChanges.map((c, i) => (
                  <Group key={`${c.fileId}-${i}`} gap={8} wrap="nowrap">
                    {c.op === "add" ? (
                      <FilePlus2 size={15} className="text-edr-muted" />
                    ) : (
                      <FileX2 size={15} className="text-edr-muted" />
                    )}
                    <Badge
                      size="sm"
                      radius="sm"
                      variant="light"
                      color={c.op === "add" ? "green" : "red"}
                    >
                      {c.op === "add" ? "Add" : "Remove"}
                    </Badge>
                    <Anchor
                      component="button"
                      type="button"
                      size="sm"
                      onClick={() =>
                        void fetchViewableFile(
                          c.fileId,
                          c.fileName ?? "License document",
                        ).then(view)
                      }
                      style={{
                        textDecoration:
                          c.op === "remove" ? "line-through" : undefined,
                      }}
                    >
                      {c.fileName ?? "License document"}
                    </Anchor>
                  </Group>
                ))}
              </Stack>
            )}

            {/* Reviewing the diff is `customers:view`; deciding on it is
                `customers:verify`. Without it the request stays readable but
                un-actionable. */}
            {canReview && (
              <Group justify="flex-end" gap="sm">
                <Button
                  variant="light"
                  color="red"
                  onClick={() => {
                    setRejectId(pending.id);
                    setNote("");
                  }}
                >
                  Reject
                </Button>
                <Button
                  color="edr-green"
                  loading={approve.isPending}
                  onClick={() => approve.mutate({ id: pending.id })}
                >
                  Approve changes
                </Button>
              </Group>
            )}
          </Stack>
        </Card>
      )}

      {history.length > 0 && (
        <Card withBorder>
          <Stack gap="sm">
            <Text fw={600} c="edr-text">
              Review history
            </Text>
            {history.map((r: CompanyChangeRequest) => (
              <Group key={r.id} gap="sm" wrap="nowrap" align="flex-start">
                <Badge
                  color={r.status === "approved" ? "edr-green" : "red"}
                  variant="light"
                  radius="md"
                  tt="capitalize"
                >
                  {r.status}
                </Badge>
                <Box style={{ flex: 1 }}>
                  <Text size="sm" c="edr-text">
                    {formatDate(r.reviewedAt ?? r.updatedAt)}
                  </Text>
                  {r.note && (
                    <Text size="xs" c="dimmed">
                      Note: {r.note}
                    </Text>
                  )}
                </Box>
              </Group>
            ))}
          </Stack>
        </Card>
      )}

      <Modal
        opened={rejectId !== null}
        onClose={() => setRejectId(null)}
        title="Reject changes"
        centered
        radius="lg"
      >
        <Stack gap="md">
          <Alert color="red" variant="light" icon={<AlertTriangle size={18} />}>
            The customer will see this note and can amend and resubmit.
          </Alert>
          <Textarea
            label="Reason for rejection"
            placeholder="e.g. The company address doesn't match the trade license."
            autosize
            minRows={3}
            value={note}
            onChange={(e) => setNote(e.currentTarget.value)}
            required
          />
          <Group justify="flex-end" gap="sm">
            <Button
              variant="default"
              onClick={() => setRejectId(null)}
              disabled={reject.isPending}
            >
              Cancel
            </Button>
            <Button
              color="red"
              loading={reject.isPending}
              disabled={note.trim().length === 0}
              onClick={confirmReject}
            >
              Reject changes
            </Button>
          </Group>
        </Stack>
      </Modal>

      {viewer}
    </>
  );
}

/** Compact "N changes pending" pill for the customer list/detail header. */
export function ChangeRequestPendingBadge({ companyId }: { companyId: string }) {
  const query = useQuery(
    api.customers.changeRequests.queryOptions({ input: { id: companyId } }),
  );
  const pending = (query.data ?? []).some((r) => r.status === "pending");
  if (!pending) return null;
  return (
    <Badge
      color="yellow"
      variant="light"
      radius="md"
      leftSection={<Clock size={12} />}
    >
      Changes pending review
    </Badge>
  );
}
