import { useEffect, useRef, useState } from "react";
import {
  GlobalWorkerOptions,
  getDocument,
  type PDFDocumentLoadingTask,
  type RenderTask,
} from "pdfjs-dist";
// Vite 通过 ?url 后缀把 worker 文件作为 URL 资源返回，保证打包后路径正确。
import workerUrl from "pdfjs-dist/build/pdf.worker.min.js?url";

GlobalWorkerOptions.workerSrc = workerUrl;

type RenderStatus = "loading" | "done" | "error";

/**
 * 自托管 PDF 渲染组件。
 *
 * 设计要点：
 * - 适应宽度：用 `containerWidth / pageWidth` 计算缩放比，按容器宽度全宽渲染。
 * - 单页填不满 → 上下居中：靠 flex 子项的 `margin: auto` 实现。
 *   flex 的内置行为是：内容超出容器时 `margin: auto` 退化为 0（不会让顶部被裁剪），
 *   因此多页或刚好填满时自然顶对齐，无需额外判断。
 */
export function PdfViewer({ blob, documentName }: { blob: Blob; documentName: string }) {
  const containerRef = useRef<HTMLDivElement>(null);
  const wrapperRef = useRef<HTMLDivElement>(null);
  const [status, setStatus] = useState<RenderStatus>("loading");
  const [errorMessage, setErrorMessage] = useState("");

  useEffect(() => {
    let cancelled = false;
    let loadingTask: PDFDocumentLoadingTask | null = null;
    let renderTask: RenderTask | null = null;

    const render = async () => {
      try {
        setStatus("loading");
        const arrayBuffer = await blob.arrayBuffer();
        if (cancelled) return;

        loadingTask = getDocument({ data: new Uint8Array(arrayBuffer) });
        const pdf = await loadingTask.promise;
        if (cancelled) return;

        const container = containerRef.current;
        const wrapper = wrapperRef.current;
        if (!container || !wrapper) return;

        // 等浏览器完成布局，避免读到 clientWidth=0。
        await new Promise<void>((resolve) => requestAnimationFrame(() => resolve()));
        if (cancelled) return;

        const containerWidth = Math.floor(container.clientWidth);
        if (containerWidth <= 0) {
          throw new Error("预览容器宽度为 0，无法渲染 PDF");
        }

        wrapper.replaceChildren();

        for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {
          if (cancelled) return;
          const page = await pdf.getPage(pageNum);
          const baseViewport = page.getViewport({ scale: 1 });
          const scale = containerWidth / baseViewport.width;
          const viewport = page.getViewport({ scale });

          const canvas = document.createElement("canvas");
          canvas.width = Math.floor(viewport.width);
          canvas.height = Math.floor(viewport.height);
          canvas.style.width = `${Math.floor(viewport.width)}px`;
          canvas.style.height = `${Math.floor(viewport.height)}px`;
          canvas.style.display = "block";
          canvas.style.background = "#fff";
          canvas.style.boxShadow = "0 1px 4px rgba(0,0,0,.15)";
          canvas.setAttribute("aria-label", `${documentName} 第 ${pageNum} 页`);

          const ctx = canvas.getContext("2d");
          if (!ctx) continue;

          renderTask = page.render({ canvasContext: ctx, viewport });
          await renderTask.promise;
          renderTask = null;
          if (cancelled) return;

          wrapper.appendChild(canvas);
        }

        if (!cancelled) setStatus("done");
      } catch (e) {
        if (cancelled) return;
        setStatus("error");
        setErrorMessage(e instanceof Error ? e.message : "PDF 加载失败");
      }
    };

    void render();

    return () => {
      cancelled = true;
      if (renderTask) {
        try {
          renderTask.cancel();
        } catch {
          /* ignore */
        }
      }
      if (loadingTask) {
        try {
          void loadingTask.destroy();
        } catch {
          /* ignore */
        }
      }
    };
  }, [blob, documentName]);

  return (
    <div
      ref={containerRef}
      className="w-full h-full overflow-auto flex flex-col"
      style={{ background: "#d8e8f5" }}
    >
      <div
        ref={wrapperRef}
        className="flex flex-col items-center my-auto"
        style={{ gap: "12px", paddingTop: "12px", paddingBottom: "12px" }}
      />
      {status === "loading" && (
        <div
          className="text-center text-sm font-black py-6"
          style={{ color: "#1A5299" }}
        >
          正在渲染 PDF…
        </div>
      )}
      {status === "error" && (
        <div className="text-center text-sm py-6 text-red-600">{errorMessage}</div>
      )}
    </div>
  );
}
