import {
  Badge,
  Button,
  Group,
  Loader,
  Modal,
  Paper,
  Stack,
  Text,
  Textarea,
} from "@mantine/core";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { Download, Eye, History, Upload } from "lucide-react";
import { useState } from "react";
import toast from "react-hot-toast";

import { PhasedFileDropzone } from "@/components/contracts/PhasedFileDropzone";
import { QUERY_KEYS } from "@/constants/QUERY_KEYS";
import { contractsService } from "@/services/contracts.service";
import { isViewable } from "@edr/ui-common";

import { downloadBookingFile, fetchViewableFile } from "@/services/files.service";

export interface ClearanceDocumentVersionsModalProps {
  contractId: string;
  /** The document being inspected; null closes the modal. */
  doc: { fileKey: string; label: string } | null;
  onClose: () => void;
  /** Hide the replace form (finalized clearance, read-only viewers). */
  canReplace?: boolean;
  onReplaced?: () => void;
  onView?: (file: { name: string; url: string }) => void;
}

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

/**
 * Version history of one clearance document, and the way to add a version.
 *
 * Staff can correct a document without bouncing it back to the customer, but
 * the customer's original is never overwritten — it drops down this list as a
 * superseded version, stamped with who replaced it and why. The corrected file
 * comes back unreviewed, so it still has to be approved before finalizing.
 */
export function ClearanceDocumentVersionsModal({
  contractId,
  doc,
  onClose,
  canReplace = false,
  onReplaced,
  onView,
}: ClearanceDocumentVersionsModalProps) {
  const queryClient = useQueryClient();
  const [file, setFile] = useState<File | null>(null);
  const [reason, setReason] = useState("");

  const { data: versions = [], isLoading } = useQuery({
    queryKey: ["contracts", "clearance-doc-versions", contractId, doc?.fileKey],
    queryFn: () =>
      contractsService.getClearanceDocumentVersions(contractId, doc!.fileKey),
    enabled: Boolean(doc),
  });

  const replace = useMutation({
    mutationFn: () =>
      contractsService.replaceClearanceDocument(
        contractId,
        doc!.fileKey,
        file!,
        reason.trim(),
      ),
    onSuccess: async () => {
      toast.success("Document replaced — the previous version is kept on file");
      setFile(null);
      setReason("");
      await queryClient.invalidateQueries({
        queryKey: ["contracts", "clearance-doc-versions", contractId, doc?.fileKey],
      });
      await queryClient.invalidateQueries({
        queryKey: QUERY_KEYS.CONTRACTS.clearance(contractId),
      });
      onReplaced?.();
    },
  });

  const close = () => {
    setFile(null);
    setReason("");
    onClose();
  };

  return (
    <Modal
      opened={Boolean(doc)}
      onClose={close}
      size="lg"
      radius="md"
      title={
        <Group gap={8}>
          <History size={16} />
          <Text fw={700}>{doc?.label ?? "Document"} — version history</Text>
        </Group>
      }
    >
      <Stack gap="md">
        {isLoading ? (
          <Group justify="center" py="lg">
            <Loader size="sm" />
          </Group>
        ) : versions.length === 0 ? (
          <Text size="sm" c="dimmed">
            Nothing uploaded under this document yet.
          </Text>
        ) : (
          <Stack gap={8}>
            {versions.map((v, index) => (
              <Paper
                key={v.id}
                withBorder
                radius="md"
                p="sm"
                bg={v.isCurrent ? "var(--mantine-color-edr-green-0)" : undefined}
              >
                <Group justify="space-between" wrap="nowrap" align="flex-start">
                  <Stack gap={2} style={{ minWidth: 0 }}>
                    <Group gap={6} wrap="nowrap">
                      <Text size="sm" fw={600} truncate>
                        {v.name}
                      </Text>
                      {v.isCurrent ? (
                        <Badge size="xs" color="edr-green" variant="light">
                          Current
                        </Badge>
                      ) : index === versions.length - 1 ? (
                        <Badge size="xs" color="blue" variant="light">
                          Original
                        </Badge>
                      ) : (
                        <Badge size="xs" color="gray" variant="light">
                          Superseded
                        </Badge>
                      )}
                    </Group>
                    <Text size="xs" c="dimmed">
                      Uploaded {fmt(v.uploadedAt)}
                      {v.replacedAt ? ` · replaced ${fmt(v.replacedAt)}` : ""}
                    </Text>
                    {v.replaceReason ? (
                      <Text size="xs" c="orange.8">
                        Reason: {v.replaceReason}
                      </Text>
                    ) : null}
                  </Stack>
                  <Group gap={6} wrap="nowrap">
                    {isViewable({ name: v.name, url: "" }) && onView ? (
                      <Button
                        size="compact-xs"
                        variant="default"
                        radius="md"
                        leftSection={<Eye size={13} />}
                        onClick={() =>
                          void fetchViewableFile(v.id, v.name).then(onView)
                        }
                      >
                        View
                      </Button>
                    ) : null}
                    <Button
                      size="compact-xs"
                      variant="default"
                      radius="md"
                      leftSection={<Download size={13} />}
                      onClick={() => void downloadBookingFile(v.id, v.name)}
                    >
                      Download
                    </Button>
                  </Group>
                </Group>
              </Paper>
            ))}
          </Stack>
        )}

        {canReplace ? (
          <Paper withBorder radius="md" p="md" bg="var(--mantine-color-gray-0)">
            <Stack gap="sm">
              <Text size="sm" fw={700}>
                Replace this document
              </Text>
              <Text size="xs" c="dimmed">
                Use this for a correction you can make yourself. The customer&apos;s
                copy stays in the history above, and the new file has to be
                approved before clearance is finalized.
              </Text>
              <PhasedFileDropzone
                label="Corrected document"
                value={file}
                onChange={setFile}
                replaceMode
              />
              <Textarea
                label="Why is it being replaced?"
                placeholder="e.g. customer sent page 2 only — attached the full signed copy"
                value={reason}
                onChange={(e) => setReason(e.currentTarget.value)}
                autosize
                minRows={2}
              />
              <Group justify="flex-end">
                <Button
                  color="edr-green"
                  radius="md"
                  leftSection={<Upload size={15} />}
                  loading={replace.isPending}
                  disabled={!file || !reason.trim()}
                  onClick={() => replace.mutate()}
                >
                  Replace document
                </Button>
              </Group>
            </Stack>
          </Paper>
        ) : null}
      </Stack>
    </Modal>
  );
}

export default ClearanceDocumentVersionsModal;
