"use client";

import { useState } from "react";
import { Download, Loader2 } from "lucide-react";
import { toast } from "sonner";

import { reviewerPaperApi } from "@/lib/api/client";
import { cn } from "@/lib/utils/cn";

import { ConfidentialityAgreementModal } from "./ConfidentialityAgreementModal";

/**
 * Reviewer download button. Gates download on the per-paper
 * confidentiality agreement (Phase 2B-ii §4.3). The click flow is:
 *
 * <ol>
 *   <li>Re-check agreement status server-side — no caching (D26-ish,
 *       §4.3 deliberate non-decision). A stale local cache could let a
 *       reviewer who declined in one tab proceed in another.</li>
 *   <li>If accepted, stream the manuscript Blob and trigger a browser
 *       download with filename {@code review-{referenceNo}.pdf}.</li>
 *   <li>If not accepted, open the {@link ConfidentialityAgreementModal}.
 *       On the modal's onAccept promise: call
 *       {@code reviewerPaperApi.acceptAgreement}, close the modal,
 *       then trigger the download.</li>
 *   <li>On modal cancel: abort — no download, no API write.</li>
 * </ol>
 *
 * <p>The {@code onDownloaded} callback fires only after the download
 * byte stream has been handed to the browser — never after agreement
 * acceptance alone. The parent uses it to unlock
 * {@code AnnotatedPaperUpload} via a {@code hasDownloaded} flag.
 */
export interface DownloadPaperButtonProps {
  paperId: string;
  paperReferenceNo: string;
  /** Fired after a successful download. Parent uses this to unlock the annotation upload UI. */
  onDownloaded?: () => void;
  className?: string;
}

export function DownloadPaperButton({
  paperId,
  paperReferenceNo,
  onDownloaded,
  className,
}: DownloadPaperButtonProps) {
  const [checking, setChecking] = useState(false);
  const [modalOpen, setModalOpen] = useState(false);

  function extractMessage(e: unknown, fallback: string): string {
    return (
      (e as { response?: { data?: { message?: string } } })?.response?.data?.message ??
      (e as { message?: string })?.message ??
      fallback
    );
  }

  async function performDownload() {
    const res = await reviewerPaperApi.downloadManuscript(paperId);
    const blob = res.data;
    // Extract filename from Content-Disposition header if available,
    // otherwise fall back to reference number with no extension
    // (the browser will infer from content type).
    const disposition = res.headers?.["content-disposition"] ?? "";
    const filenameMatch = disposition.match(/filename="?([^";\n]+)"?/);
    const filename = filenameMatch?.[1] ?? `review-${paperReferenceNo}`;
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = filename;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
    onDownloaded?.();
  }

  async function handleClick() {
    setChecking(true);
    try {
      const statusRes = await reviewerPaperApi.getAgreementStatus(paperId);
      if (statusRes.data.accepted) {
        await performDownload();
        return;
      }
      // Agreement not yet accepted — open the modal. We intentionally
      // keep `checking` true while the modal is open so the trigger
      // button stays disabled until the flow resolves one way or the
      // other (accepted + downloaded, or cancelled).
      setModalOpen(true);
    } catch (e) {
      toast.error(extractMessage(e, "Failed to download manuscript"));
      setChecking(false);
    }
  }

  async function handleModalAccept() {
    // Called from inside the modal. Any error bubbles back to the
    // modal's inline error state — it catches the rejection and
    // surfaces it without closing. We only close + download on
    // success.
    try {
      await reviewerPaperApi.acceptAgreement(paperId);
    } catch (e) {
      // Re-throw so the modal's catch handles it. We do NOT clear
      // `checking` here — the modal stays open; the user can retry
      // or cancel.
      throw e;
    }
    setModalOpen(false);
    try {
      await performDownload();
    } catch (e) {
      toast.error(extractMessage(e, "Failed to download manuscript"));
    } finally {
      setChecking(false);
    }
  }

  function handleModalCancel() {
    setModalOpen(false);
    setChecking(false);
  }

  return (
    <>
      <button
        type="button"
        onClick={handleClick}
        disabled={checking}
        className={cn(
          "inline-flex items-center gap-2 rounded-md bg-indigo-600 px-5 py-2.5 text-sm font-semibold text-white shadow hover:bg-indigo-700 transition disabled:opacity-50",
          className
        )}
      >
        {checking ? (
          <Loader2 className="h-4 w-4 animate-spin" aria-hidden="true" />
        ) : (
          <Download className="h-4 w-4" aria-hidden="true" />
        )}
        Download manuscript
      </button>

      <ConfidentialityAgreementModal
        isOpen={modalOpen}
        paperReferenceNo={paperReferenceNo}
        onAccept={handleModalAccept}
        onCancel={handleModalCancel}
      />
    </>
  );
}

export default DownloadPaperButton;
