// Sample Previewer — renders the first N pages of a PDF on demand using pdf.js.
// Reusable: accepts props for pdfUrl, downloadName, storageKey, maxPages, label, anchor.

const { useState, useEffect, useRef, useCallback } = React;

// Lazy-load pdf.js once and share the promise
let _pdfjsPromise = null;
function loadPdfJs() {
  if (_pdfjsPromise) return _pdfjsPromise;
  _pdfjsPromise = new Promise((resolve, reject) => {
    if (window.pdfjsLib) return resolve(window.pdfjsLib);
    const s = document.createElement("script");
    s.src = "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.min.js";
    s.onload = () => {
      window.pdfjsLib.GlobalWorkerOptions.workerSrc =
        "https://cdnjs.cloudflare.com/ajax/libs/pdf.js/3.11.174/pdf.worker.min.js";
      resolve(window.pdfjsLib);
    };
    s.onerror = reject;
    document.head.appendChild(s);
  });
  return _pdfjsPromise;
}

function SamplePreviewer({
  pdfUrl,
  downloadName = "sample.pdf",
  storageKey = "etw_sample_email",
  maxPages = 8,
  label = "READ A SAMPLE",
  anchor = "sample-previewer",
  endTitle = "Want the full sample?",
  endTag = "END OF FREE SAMPLE",
  buyUrl = null,
  buyLabel = "Buy now",
  buyPrice = null,
  sampleBadge = false,
  coverImage = null
}) {
  const SAMPLE_PDF = pdfUrl;
  const SAMPLE_DOWNLOAD = pdfUrl;
  const MAX_PAGES = maxPages;

  const [pdf, setPdf] = useState(null);
  const [page, setPage] = useState(1);
  const [dir, setDir] = useState(1);
  const [loading, setLoading] = useState(true);
  const [renderedPage, setRenderedPage] = useState(null); // {n, src}
  const canvasRef = useRef(null);
  const renderTaskRef = useRef(null);

  // Email-gate state. "idle" → "gating" → "submitted"
  const STORAGE_KEY = storageKey;
  const [gateState, setGateState] = useState(() => {
    try {
      return localStorage.getItem(STORAGE_KEY) ? "submitted" : "idle";
    } catch { return "idle"; }
  });
  const [email, setEmail] = useState(() => {
    try { return localStorage.getItem(STORAGE_KEY) || ""; } catch { return ""; }
  });
  const [emailTouched, setEmailTouched] = useState(false);
  const emailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);

  const gateInputRef = useRef(null);

  const triggerDownload = useCallback(() => {
    const a = document.createElement("a");
    a.href = SAMPLE_DOWNLOAD;
    a.download = downloadName;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
  }, [SAMPLE_DOWNLOAD, downloadName]);

  const submitGate = useCallback((e) => {
    e && e.preventDefault();
    setEmailTouched(true);
    if (!emailValid) return;
    try { localStorage.setItem(STORAGE_KEY, email); } catch {}
    setGateState("submitted");
    // small delay so the user sees the confirmation, then auto-download
    setTimeout(() => triggerDownload(), 350);
  }, [email, emailValid, triggerDownload]);

  const onDownloadClick = useCallback((e) => {
    if (gateState === "submitted") {
      // already gave email — just download, default <a download> behaviour
      return;
    }
    e.preventDefault();
    setGateState("gating");
    // focus the input after the panel opens
    setTimeout(() => {
      if (gateInputRef.current) gateInputRef.current.focus();
    }, 80);
  }, [gateState]);

  // load pdf
  useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        const lib = await loadPdfJs();
        const doc = await lib.getDocument(SAMPLE_PDF).promise;
        if (!cancelled) setPdf(doc);
      } catch (e) {
        console.error("Sample PDF failed to load", e);
        if (!cancelled) setLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, []);

  // render current page
  useEffect(() => {
    if (!pdf) return;
    let cancelled = false;
    (async () => {
      setLoading(true);
      try {
        // cancel any in-flight render
        if (renderTaskRef.current) {
          try { renderTaskRef.current.cancel(); } catch {}
          renderTaskRef.current = null;
        }
        const p = await pdf.getPage(page);
        const target = 1200; // device px width
        const v0 = p.getViewport({ scale: 1 });
        const scale = (target / v0.width) * (window.devicePixelRatio || 1);
        const v = p.getViewport({ scale });
        const canvas = document.createElement("canvas");
        canvas.width = Math.floor(v.width);
        canvas.height = Math.floor(v.height);
        const ctx = canvas.getContext("2d");
        ctx.fillStyle = "#faf6ec";
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        const task = p.render({ canvasContext: ctx, viewport: v });
        renderTaskRef.current = task;
        await task.promise;
        if (cancelled) return;
        const src = canvas.toDataURL("image/jpeg", 0.86);
        setRenderedPage({ n: page, src });
      } catch (e) {
        if (e && e.name !== "RenderingCancelledException") {
          console.error("render failed", e);
        }
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => { cancelled = true; };
  }, [pdf, page]);

  // prefetch neighbours (silent)
  useEffect(() => {
    if (!pdf) return;
    const next = Math.min(page + 1, MAX_PAGES);
    if (next !== page) {
      pdf.getPage(next).catch(() => {});
    }
  }, [pdf, page]);

  const go = useCallback((delta) => {
    setPage((p) => {
      const n = p + delta;
      if (n < 1 || n > MAX_PAGES) return p;
      setDir(delta);
      return n;
    });
  }, []);

  // Zoom state — click on page opens lightbox
  const [zoomed, setZoomed] = useState(false);

  // Escape to close zoom
  useEffect(() => {
    if (!zoomed) return;
    const onKey = (e) => {
      if (e.key === "Escape") setZoomed(false);
      else if (e.key === "ArrowLeft") go(-1);
      else if (e.key === "ArrowRight") go(1);
    };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [zoomed, go]);

  // keyboard nav when previewer is focused / hovered
  const wrapRef = useRef(null);
  useEffect(() => {
    const onKey = (e) => {
      if (!wrapRef.current) return;
      const r = wrapRef.current.getBoundingClientRect();
      const visible = r.bottom > 0 && r.top < window.innerHeight;
      if (!visible) return;
      if (e.key === "ArrowLeft") go(-1);
      if (e.key === "ArrowRight") go(1);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [go]);

  const atEnd = page === MAX_PAGES;
  const atStart = page === 1;

  return (
    <div className="sample-previewer" ref={wrapRef} data-comment-anchor={anchor}>
      <div className="sample-toprail">
        <span className="page-mono">{label}</span>
        <span className="page-mono">
          {String(page).padStart(2, "0")} / {String(MAX_PAGES).padStart(2, "0")}
        </span>
      </div>

      <div className="sample-stage">
        <div className="sample-shadow"></div>
        <div className={`sample-page-wrap ${dir > 0 ? "flip-fwd" : "flip-bwd"}`} key={renderedPage ? renderedPage.n : "loading"}>
          {coverImage && page === 1 ? (
            <img
              src={coverImage}
              alt="Cover — click to zoom"
              className="sample-page-img sample-page-cover zoomable"
              draggable="false"
              onClick={() => setZoomed(true)}
            />
          ) : renderedPage ? (
            <img
              src={renderedPage.src}
              alt={`Sample page ${renderedPage.n} — click to zoom`}
              className="sample-page-img zoomable"
              draggable="false"
              onClick={() => setZoomed(true)}
            />
          ) : (
            <div className="sample-skeleton">
              <div className="sk-line w70"></div>
              <div className="sk-line w50"></div>
              <div className="sk-line w90"></div>
              <div className="sk-line w80"></div>
              <div className="sk-line w60"></div>
              <div className="sk-line w85"></div>
              <div className="sk-line w70"></div>
              <div className="sk-line w55"></div>
            </div>
          )}
          {loading && renderedPage && !(coverImage && page === 1) && (
            <div className="sample-loading-overlay" aria-hidden="true"></div>
          )}
          {sampleBadge && page === 1 && (
            <span className="sample-page-badge" aria-hidden="true">FREE SAMPLE</span>
          )}
        </div>

        {/* edge tap zones for big touch areas */}
        <button
          className="sample-edge sample-edge-l"
          onClick={() => go(-1)}
          disabled={atStart}
          aria-label="Previous page"
        >
          <span className="edge-arrow" aria-hidden="true">‹</span>
        </button>
        <button
          className="sample-edge sample-edge-r"
          onClick={() => go(1)}
          disabled={atEnd}
          aria-label="Next page"
        >
          <span className="edge-arrow" aria-hidden="true">›</span>
        </button>
      </div>

      <div className="sample-controls">
        <button
          className="sample-btn ghost"
          onClick={() => go(-1)}
          disabled={atStart}
          aria-label="Previous page"
        >
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M15 18l-6-6 6-6"/></svg>
          <span>Prev</span>
        </button>

        <div className="sample-progress" aria-hidden="true">
          {Array.from({ length: MAX_PAGES }).map((_, idx) => (
            <button
              key={idx}
              className={`sample-tick ${idx + 1 === page ? "active" : ""} ${idx + 1 < page ? "done" : ""}`}
              onClick={() => { setDir(idx + 1 > page ? 1 : -1); setPage(idx + 1); }}
              aria-label={`Go to page ${idx + 1}`}
            />
          ))}
        </div>

        <button
          className="sample-btn ghost"
          onClick={() => go(1)}
          disabled={atEnd}
          aria-label="Next page"
        >
          <span>Next</span>
          <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><path d="M9 18l6-6-6-6"/></svg>
        </button>
      </div>

      <div className={`sample-end-cta ${atEnd ? "show" : ""} state-${buyUrl ? "buy" : gateState}`}>
        {buyUrl ? (
          <>
            <div className="sample-end-text">
              <span className="page-mono rust">{endTag}</span>
              <span className="sample-end-h">{endTitle}</span>
            </div>
            <a
              className="sample-dl-btn"
              href={buyUrl}
            >
              <span>{buyLabel}{buyPrice ? ` · ${buyPrice}` : ""} →</span>
            </a>
          </>
        ) : gateState === "idle" ? (
          <>
            <div className="sample-end-text">
              <span className="page-mono rust">{endTag}</span>
              <span className="sample-end-h">{endTitle}</span>
            </div>
            <button
              className="sample-dl-btn"
              onClick={onDownloadClick}
              type="button"
            >
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
                <polyline points="7 10 12 15 17 10"/>
                <line x1="12" y1="15" x2="12" y2="3"/>
              </svg>
              <span>Download PDF</span>
            </button>
          </>
        ) : gateState === "gating" ? (
          <form className="sample-gate" onSubmit={submitGate} noValidate>
            <div className="sample-gate-head">
              <span className="page-mono rust">ONE QUICK STEP</span>
              <span className="sample-end-h">Where should we send it?</span>
            </div>
            <div className="sample-gate-row">
              <input
                ref={gateInputRef}
                type="email"
                className="sample-gate-input"
                placeholder="you@example.com"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
                onBlur={() => setEmailTouched(true)}
                aria-label="Email address"
                autoComplete="email"
              />
              <button type="submit" className="sample-gate-submit">
                Send me the PDF →
              </button>
            </div>
            <div className="sample-gate-fine">
              {emailTouched && !emailValid && email.length > 0 ? (
                <span className="sample-gate-err">That doesn't look like a valid email yet.</span>
              ) : (
                <span className="page-mono">
                  ※ ALSO ADDS YOU TO THE THAT WORKS STUDIO LIST. UNSUBSCRIBE IN ONE CLICK.
                </span>
              )}
              <button
                type="button"
                className="sample-gate-back"
                onClick={() => setGateState("idle")}
              >
                ← Cancel
              </button>
            </div>
          </form>
        ) : gateState === "submitted" ? (
          <>
            <div className="sample-end-text">
              <span className="page-mono rust">✓ DOWNLOAD STARTED</span>
              <span className="sample-end-h">Sent to <span className="sample-gate-email">{email}</span></span>
            </div>
            <a
              className="sample-dl-btn ghost"
              href={SAMPLE_DOWNLOAD}
              download={downloadName}
            >
              <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
                <path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/>
                <polyline points="7 10 12 15 17 10"/>
                <line x1="12" y1="15" x2="12" y2="3"/>
              </svg>
              <span>Download again</span>
            </a>
          </>
        ) : null}
      </div>

      {/* ZOOM LIGHTBOX */}
      {zoomed && (
        <div className="sample-zoom" onClick={() => setZoomed(false)} role="dialog" aria-modal="true">
          <button
            type="button"
            className="sample-zoom-close"
            onClick={(e) => { e.stopPropagation(); setZoomed(false); }}
            aria-label="Close"
          >×</button>
          <button
            type="button"
            className="sample-zoom-nav prev"
            onClick={(e) => { e.stopPropagation(); go(-1); }}
            disabled={atStart}
            aria-label="Previous page"
          >‹</button>
          <button
            type="button"
            className="sample-zoom-nav next"
            onClick={(e) => { e.stopPropagation(); go(1); }}
            disabled={atEnd}
            aria-label="Next page"
          >›</button>
          <div className="sample-zoom-stage" onClick={(e) => e.stopPropagation()}>
            {coverImage && page === 1 ? (
              <img src={coverImage} alt="Cover" className="sample-zoom-img" />
            ) : renderedPage ? (
              <img src={renderedPage.src} alt={`Page ${renderedPage.n}`} className="sample-zoom-img" />
            ) : null}
            {sampleBadge && page === 1 && (
              <span className="sample-page-badge zoom" aria-hidden="true">FREE SAMPLE</span>
            )}
          </div>
          <div className="sample-zoom-foot">
            <span className="page-mono">PAGE {String(page).padStart(2, "0")} / {String(MAX_PAGES).padStart(2, "0")} · PRESS ESC TO CLOSE</span>
          </div>
        </div>
      )}
    </div>
  );
}

window.SamplePreviewer = SamplePreviewer;
