/* Renders an uploaded PDF or Word file as-is, with draggable signature + text fields. */
(function () {
  const { useState, useEffect, useRef } = React;

  /* ---- data helpers ---- */
  function dataUrlToArrayBuffer(dataUrl) {
    const b64 = dataUrl.split(",")[1];
    const bin = atob(b64);
    const len = bin.length;
    const bytes = new Uint8Array(len);
    for (let i = 0; i < len; i++) bytes[i] = bin.charCodeAt(i);
    return bytes.buffer;
  }
  function dataUrlToBlob(dataUrl) {
    return new Blob([dataUrlToArrayBuffer(dataUrl)]);
  }

  /* ---- renderers ---- */
  async function renderPdf(host, dataUrl) {
    const pdfjsLib = window.pdfjsLib;
    pdfjsLib.GlobalWorkerOptions.workerSrc =
      "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";
    const data = dataUrlToArrayBuffer(dataUrl);
    const pdf = await pdfjsLib.getDocument({ data }).promise;
    const SCALE = 2;
    for (let i = 1; i <= pdf.numPages; i++) {
      const page = await pdf.getPage(i);
      const vp = page.getViewport({ scale: SCALE });
      const wrap = document.createElement("div");
      wrap.className = "fpage";
      wrap.style.maxWidth = vp.width / SCALE + "px";
      const canvas = document.createElement("canvas");
      canvas.width = vp.width;
      canvas.height = vp.height;
      canvas.style.width = "100%";
      canvas.style.height = "auto";
      canvas.style.display = "block";
      wrap.appendChild(canvas);
      host.appendChild(wrap);
      await page.render({ canvasContext: canvas.getContext("2d"), viewport: vp }).promise;
    }
  }

  async function renderDocx(host, dataUrl) {
    const blob = dataUrlToBlob(dataUrl);
    await window.docx.renderAsync(blob, host, null, {
      className: "docxr",
      inWrapper: true,
      ignoreWidth: false,
      ignoreHeight: false,
      breakPages: true,
      experimental: true,
    });
  }

  const clamp = (v, lo, hi) => Math.max(lo, Math.min(hi, v));

  function pageNodes(stage) {
    if (!stage) return [];
    return Array.from(stage.querySelectorAll(".fpage, .docxr-wrapper section"));
  }

  /* ---- a single placed field (signature or text), anchored inside a page ---- */
  function Stamp({ stamp, profile, editing, onChange, onRemove, onEdit, pageEl }) {
    const font = window.fontById(profile.sigFont);
    const isSig = stamp.kind === "sig";
    const elRef = useRef();
    const spanRef = useRef();
    const latest = useRef(stamp);
    latest.current = stamp;

    useEffect(() => {
      if (editing && spanRef.current) {
        spanRef.current.focus();
        const sel = window.getSelection();
        const range = document.createRange();
        range.selectNodeContents(spanRef.current);
        range.collapse(false);
        sel.removeAllRanges();
        sel.addRange(range);
      }
    }, [editing]);

    const onPointerDown = (e) => {
      if (editing) return;
      if (e.target.closest(".psig-controls")) return;
      e.preventDefault();
      elRef.current.classList.add("dragging");
      const move = (ev) => {
        const r = pageEl.getBoundingClientRect();
        const x = clamp((ev.clientX - r.left) / r.width, 0.01, 0.99);
        const y = clamp((ev.clientY - r.top) / r.height, 0.005, 0.995);
        onChange(latest.current.id, { xPct: x, yPct: y });
      };
      const up = () => {
        if (elRef.current) elRef.current.classList.remove("dragging");
        window.removeEventListener("pointermove", move);
        window.removeEventListener("pointerup", up);
      };
      window.addEventListener("pointermove", move);
      window.addEventListener("pointerup", up);
    };

    const step = isSig ? 6 : 2;
    const resize = (d) => {
      const lo = isSig ? 18 : 9, hi = isSig ? 130 : 44;
      onChange(stamp.id, { size: clamp(stamp.size + d, lo, hi) });
    };

    return (
      <div
        ref={elRef}
        className={"placed-sig" + (editing ? " editing" : "")}
        style={{ left: stamp.xPct * 100 + "%", top: stamp.yPct * 100 + "%" }}
        onPointerDown={onPointerDown}
        onDoubleClick={() => !isSig && onEdit(stamp.id)}
        title={isSig ? "Drag to move" : "Drag to move · double-click to edit"}
      >
        <div className="psig-controls no-print" onPointerDown={(e) => e.stopPropagation()}>
          <button onClick={() => resize(-step)} title="Smaller" aria-label="Smaller">
            <svg width="14" height="14" viewBox="0 0 24 24"><path d="M5 12h14" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>
          </button>
          <button onClick={() => resize(step)} title="Larger" aria-label="Larger">
            <svg width="14" height="14" viewBox="0 0 24 24"><path d="M12 5v14M5 12h14" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round"/></svg>
          </button>
          {!isSig && (
            <button onClick={() => onEdit(stamp.id)} title="Edit text" aria-label="Edit text">
              <svg width="14" height="14" viewBox="0 0 24 24" fill="none"><path d="M14.5 5.5 18.5 9.5M4 20l1-4L16 5a2 2 0 0 1 3 3L8 19l-4 1Z" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>
            </button>
          )}
          <span className="psig-grab" title="Drag to move">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="currentColor"><circle cx="9" cy="6" r="1.6"/><circle cx="15" cy="6" r="1.6"/><circle cx="9" cy="12" r="1.6"/><circle cx="15" cy="12" r="1.6"/><circle cx="9" cy="18" r="1.6"/><circle cx="15" cy="18" r="1.6"/></svg>
          </span>
          <button onClick={onRemove} title="Remove" aria-label="Remove">
            <svg width="14" height="14" viewBox="0 0 24 24"><path d="m6 6 12 12M18 6 6 18" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/></svg>
          </button>
        </div>
        {isSig ? (
          <span className="psig-ink" style={{ fontFamily: font.family, fontSize: stamp.size * font.size + "px" }}>{stamp.text}</span>
        ) : (
          <span
            ref={spanRef}
            className="psig-text"
            contentEditable={editing}
            suppressContentEditableWarning
            spellCheck={false}
            style={{ fontSize: stamp.size + "px" }}
            onBlur={(e) => { onChange(stamp.id, { text: e.target.textContent.trim() || " " }); onEdit(null); }}
            onKeyDown={(e) => { if (e.key === "Enter") { e.preventDefault(); e.target.blur(); } }}
          >{stamp.text}</span>
        )}
      </div>
    );
  }

  /* ---- file document view ---- */
  function FileDocView({ file, profile, stamps, setStamps }) {
    const hostRef = useRef();
    const stageRef = useRef();
    const [status, setStatus] = useState("loading");
    const [editing, setEditing] = useState(null);
    const [pageEls, setPageEls] = useState([]);

    useEffect(() => {
      let alive = true;
      const host = hostRef.current;
      if (host) host.innerHTML = "";
      setStatus("loading");
      setPageEls([]);
      (async () => {
        try {
          if (file.kind === "pdf") await renderPdf(host, file.dataUrl);
          else await renderDocx(host, file.dataUrl);
          if (!alive) return;
          const els = pageNodes(stageRef.current);
          els.forEach((el) => el.classList.add("fpage-anchor"));
          setPageEls(els);
          setStatus("ready");
        } catch (err) {
          console.error("render error", err);
          if (alive) setStatus("error");
        }
      })();
      return () => { alive = false; };
    }, [file.dataUrl, file.kind]);

    const update = (id, patch) => setStamps((arr) => arr.map((s) => (s.id === id ? { ...s, ...patch } : s)));
    const remove = (id) => setStamps((arr) => arr.filter((s) => s.id !== id));

    return (
      <div className="filedoc-scroll scroll">
        {status === "loading" && <div className="filedoc-note">Rendering {file.name}…</div>}
        {status === "error" && (
          <div className="filedoc-note err">
            Couldn’t render <b>{file.name}</b>. Try a PDF, or a .docx exported from Word/Google Docs.
          </div>
        )}
        <div className="filedoc-stage" ref={stageRef} style={{ display: status === "ready" ? "block" : "none" }}>
          <div ref={hostRef}></div>
        </div>
        {status === "ready" && pageEls.map((el, i) =>
          window.ReactDOM.createPortal(
            stamps.filter((s) => (s.page || 0) === i).map((s) => (
              <Stamp
                key={s.id}
                stamp={s}
                profile={profile}
                editing={editing === s.id}
                onChange={update}
                onRemove={() => remove(s.id)}
                onEdit={setEditing}
                pageEl={el}
              />
            )),
            el
          )
        )}
      </div>
    );
  }

  window.FileDocView = FileDocView;
  window.signetPageNodes = pageNodes;
})();
