// MostlyQR — free photo-QR generator at /photo-qr-code (F214's marketing surface).
//
// Same shape as /qr-code-generator (mqr/qrgen.jsx): a no-login SEO free tool that runs
// entirely in the browser, then hands off to the builder with the destination prefilled.
//
// The page's ONE argument, and the reason it isn't just another artistic-QR page: every
// competitor in this category trades scannability for looks. The AI-art generators say so
// outright — they ship a "QR strength" dial. The closest honest competitor encodes the
// picture INTO the error-correction bits, i.e. spends the redundancy that exists to survive
// glare and creases. We spend none of it: the picture lives in the space around each module
// centre, and every centre still carries the value the encoder demanded.
//
// So the page SHOWS that rather than claiming it — it re-verifies the rendered code against
// the encoder live, in front of the reader, and prints the count. Same contract as qrgen's
// module-count delta: the benefit is measured on the page, not asserted in copy.
//
// IIFE-scoped so no top-level name leaks into the shared global scope (see enterprise.jsx).

// Localized-page URLs go through the app's ONE helper (window.mqrPath, defined in
// mqr/shared.jsx over @mostly-tiny/i18n core/locale-path.js): a page that ships once per
// locale must link its OWN locale's sibling, or the German page sends every crawler and
// reader back to English. Shared single routes (/builder, /signin, /docs/api) stay literal.
const P = (p) => ((typeof window !== "undefined" && window.mqrPath) ? window.mqrPath(p) : p);

(function () {
const { Icon: IconPG, MQMark: MQMarkPG, Wordmark: WordmarkPG, PhotoQR: PhotoQRPG, photoMatrix: photoMatrixPG } = window.MQR;
const { Button: BtnPG } = window.ForgeDesignSystem_e40d74;
const I18N_PG = (typeof window !== "undefined" && window.ForgeI18n) || { t: (k) => k, locale: "en" };
const trPG = I18N_PG.t;
const HOME_PG = "/";

const SAMPLE_PG = "/mqr/sample-monstera.webp";
const SAMPLE_URL_PG = "https://northbrew.co/spring-menu";

// Visible FAQ — kept IDENTICAL to the `faq` array on the photogen entry in seo.config.js
// (visible ↔ FAQPage JSON-LD parity, the same contract the compare pages use).
const PG_FAQ = [
  { q: "Can a QR code really be a photograph and still scan?", a: "Yes. A scanner does not read the whole of each module — it samples a small area at the module's centre and thresholds that. Everything outside those centres is free space, so a photograph can live there while the code stays exactly as readable. MostlyQR forces each centre to the value the encoder demands and spends the rest of the module on your picture." },
  { q: "Does a photo QR code use up the error correction?", a: "Not in MostlyQR. This is the difference that matters. Most artistic QR tools overwrite modules and rely on error correction to repair the damage, which spends the redundancy that exists to survive glare, creases and bad light. A MostlyQR photo code changes no module at all — every centre still carries its exact value, so the full 30% redundancy of error-correction level H is still there when someone scans it off a rained-on menu." },
  { q: "What kind of photo works best?", a: "A bold subject on a plain, light background, filling the frame. A QR carries roughly fifty by fifty tones, which is far less detail than it sounds — so strong shapes survive and fine detail does not. Square-ish subjects use the space best, because the code is square. Avoid a shadow falling on the background: on a white ground it is the only other dark thing in frame, so it reads as part of the subject." },
  { q: "Is this free? Do I need an account?", a: "The generator here is free and needs no account — the photo never leaves your browser, and the code is rendered on your own device. What an account adds is a dynamic code: one you can repoint after it is printed, and whose scans you can count." },
  { q: "Can I change where a photo QR code points after printing it?", a: "Only if it is dynamic. The code on this page is static — it encodes your link directly, so it works forever but can never be changed. A MostlyQR dynamic photo code encodes a short link instead, so you can swap the destination after the posters are up, and MostlyQR codes never expire even if you cancel." },
  { q: "Why can I not download a photo QR as SVG?", a: "Because it would be a lie. A dithered photo code is made of pixels, not shapes — a mid-size code is around a hundred and fifty thousand of them. Wrapping that in an SVG would give you a vector file that contains a raster image, which is worse than an honest PNG. So photo codes export as PNG, JPG and PDF." },
  { q: "Will it scan from a printed poster?", a: "It scans as reliably as a plain code of the same size, because none of the error correction has been spent. The ordinary print rules still apply: keep the quiet zone, print it large enough, and test the actual print rather than the screen — advice that is true of every QR code, not just photographic ones." },
  { q: "What is the difference between mosaic and halftone?", a: "Mosaic draws only the code's own modules, sizing each one by how dark the picture is at that point, and leaves the space between them clean — it still reads as a QR code. Halftone turns the whole square into continuous photographic texture, so it reads more like a photograph and less like a code. Both are the same scannable matrix underneath." },
];

/** Re-verify the rendered code against the encoder — the page's central claim, measured. */
function verifyPG(canvas, data, minVersion, quiet) {
  const D = window.MostlyQRDither;
  if (!canvas || !canvas.width || !D || !photoMatrixPG) return null;
  const matrix = photoMatrixPG(data, "H", minVersion);
  if (!matrix) return null;
  const scale = canvas.width / (matrix.size + quiet * 2);
  const ctx = canvas.getContext("2d");
  const { data: px } = ctx.getImageData(0, 0, canvas.width, canvas.height);
  let wrong = 0;
  for (let row = 0; row < matrix.size; row++) {
    for (let col = 0; col < matrix.size; col++) {
      const x = Math.floor((col + quiet) * scale + scale / 2);
      const y = Math.floor((row + quiet) * scale + scale / 2);
      const dark = px[(y * canvas.width + x) * 4] < 128;
      if (dark !== matrix.get(row, col)) wrong++;
    }
  }
  return { total: matrix.size * matrix.size, wrong, size: matrix.size };
}

function PhotoGen() {
  const [photo, setPhoto] = React.useState(SAMPLE_PG);
  const [url, setUrl] = React.useState(SAMPLE_URL_PG);
  const [look, setLook] = React.useState("mosaic");
  const [check, setCheck] = React.useState(null);
  const fileRef = React.useRef(null);
  const canvasRef = React.useRef(null);
  // Read AFTER mount, never during render. The prerenderer has no ?demo=1, so deriving
  // this at render time makes the server and the first client render disagree and React
  // reports a hydration mismatch on the CTA's href. qrgen gets away with the same line
  // only because its input starts empty, so its CTA has no href to differ on; this page
  // prefills a sample destination, so it renders one immediately. Starting false matches
  // the server, then the effect flips it.
  const [inDemo, setInDemo] = React.useState(false);
  React.useEffect(() => {
    try { setInDemo(new URLSearchParams(window.location.search).get("demo") === "1"); } catch (e) { /* no window */ }
  }, []);

  const trimmed = (url || "").trim();
  const isHttp = /^https?:\/\//i.test(trimmed);
  const payload = trimmed || SAMPLE_URL_PG;
  const MIN_VERSION = 12;
  const QUIET = 4;

  const onFile = (e) => {
    const file = e.target.files && e.target.files[0];
    if (!file) return;
    const reader = new FileReader();
    reader.onload = () => {
      // Downscale in the browser exactly as the builder does — the renderer samples
      // this to ~65×65 anyway, so the rest is carried and thrown away.
      const img = new Image();
      img.onload = () => {
        const MAX = 1024;
        const k = Math.min(1, MAX / Math.max(img.width, img.height));
        const c = document.createElement("canvas");
        c.width = Math.max(1, Math.round(img.width * k));
        c.height = Math.max(1, Math.round(img.height * k));
        const ctx = c.getContext("2d");
        ctx.fillStyle = "#ffffff";
        ctx.fillRect(0, 0, c.width, c.height);
        ctx.drawImage(img, 0, 0, c.width, c.height);
        setPhoto(c.toDataURL("image/webp", 0.85));
      };
      img.onerror = () => setPhoto(reader.result);
      img.src = reader.result;
    };
    reader.readAsDataURL(file);
  };

  // Verify after each render settles. Reading the canvas is cheap next to the dither
  // that produced it, and this is the page's whole argument — it has to be live.
  React.useEffect(() => {
    const t = setTimeout(() => setCheck(verifyPG(canvasRef.current, payload, MIN_VERSION, QUIET)), 400);
    return () => clearTimeout(t);
  }, [photo, payload, look]);

  const download = (type, ext) => () => {
    const c = canvasRef.current;
    if (!c) return;
    c.toBlob((blob) => {
      if (!blob) return;
      const a = document.createElement("a");
      a.href = URL.createObjectURL(blob);
      a.download = "photo-qr." + ext;
      document.body.appendChild(a); a.click(); a.remove();
      setTimeout(() => URL.revokeObjectURL(a.href), 1000);
    }, type, 0.95);
  };

  const builderHref = "/builder?type=url" + (inDemo ? "&demo=1" : "") +
    (isHttp ? "&dest=" + encodeURIComponent(trimmed.slice(0, 2048)) : "");

  return (
    <div className="mk-root ent-root qg-page">
      <header className="mk-nav ent-nav">
        <div className="mk-wrap mk-nav__inner">
          <a className="mk-brand" href={HOME_PG}><MQMarkPG animate /><WordmarkPG /></a>
          <nav className="mk-nav__links">
            <a href={P("/#pricing")}>{trPG("mqr.landing.nav.pricing")}</a>
            <a href={P("/qr-code-generator")}>{trPG("seo.photogen.nav.generator")}</a>
            <a href={P("/enterprise")}>{trPG("mqr.landing.platform.tier.ent")}</a>
          </nav>
          <div className="mk-nav__cta" />
        </div>
      </header>

      <section className="bc-hero qg-hero">
        <div className="mk-wrap qg-hero__inner">
          <span className="mk-eyebrow" style={{ color: "var(--accent)" }}>{trPG("seo.photogen.eyebrow")}</span>
          <h1 className="ent-h1" style={{ color: "var(--fg)", fontSize: 40 }}>{trPG("seo.photogen.h1")}</h1>
          <p className="mk-lead" style={{ marginInline: "auto" }} dangerouslySetInnerHTML={{ __html: trPG("seo.photogen.lead") }} />

          <div className="pg-tool">
            <div className="pg-tool__controls">
              <label className="pg-label">{trPG("seo.photogen.yourphoto")}</label>
              <div className="pg-pick">
                <div className="pg-pick__thumb">
                  <img src={photo} alt={trPG("seo.photogen.yourphoto")} data-testid="pg-thumb" />
                </div>
                <button type="button" className="pg-pick__drop" onClick={() => fileRef.current && fileRef.current.click()}>
                  <IconPG name="download" size={15} /> {trPG("seo.photogen.upload")}
                </button>
                <input ref={fileRef} type="file" accept="image/*" onChange={onFile} style={{ display: "none" }} data-testid="pg-upload" />
              </div>

              <label className="pg-label">{trPG("seo.photogen.look")}</label>
              <div className="pg-segs">
                {[["mosaic", trPG("mqr.builder.photo.style.mosaic")], ["halftone", trPG("mqr.builder.photo.style.halftone")]].map(([v, l]) => (
                  <button key={v} type="button" className="pg-seg" data-on={look === v} data-pg-look={v}
                    onClick={() => setLook(v)}>{l}</button>
                ))}
              </div>

              <label className="pg-label">{trPG("seo.photogen.destination")}</label>
              <input className="pg-input" value={url} placeholder="https://" data-testid="pg-url"
                onChange={(e) => setUrl(e.target.value)} aria-label={trPG("seo.photogen.destination")} />
            </div>

            <div className="pg-tool__out">
              <div className="pg-canvaswrap">
                <PhotoQRPG innerRef={canvasRef} data={payload} image={photo} ecc="H"
                  photoStyle={look} minVersion={MIN_VERSION} quiet={QUIET} scale={12}
                  dotMin={0.36} dotMax={0.72} ghost={0.9} contrast={2.2} fit="contain"
                  shape="dots" fg="#111111" bg="#ffffff" />
              </div>

              {/* The claim, measured on the page rather than asserted in the copy. */}
              {check && (
                <p className="pg-verify" data-testid="pg-verify" data-wrong={check.wrong}>
                  <IconPG name="check" size={14} sw={2.6} />
                  <span dangerouslySetInnerHTML={{ __html: trPG("seo.photogen.verified", { total: check.total, size: check.size }) }} />
                </p>
              )}

              <div className="pg-downloads">
                <BtnPG variant="secondary" onClick={download("image/png", "png")}>PNG</BtnPG>
                <BtnPG variant="secondary" onClick={download("image/jpeg", "jpg")}>JPG</BtnPG>
              </div>
              <p className="pg-note">{trPG("seo.photogen.staticnote")}</p>
              <a href={builderHref} style={{ textDecoration: "none", display: "block" }}>
                <BtnPG variant="primary" iconRight={<IconPG name="arrow" size={15} />} style={{ width: "100%", justifyContent: "center" }}>
                  {trPG("seo.photogen.cta")}
                </BtnPG>
              </a>
            </div>
          </div>
        </div>
      </section>

      <section className="mk-why pg-why">
        <div className="mk-wrap">
          <div className="mk-section-head">
            <h2 className="mk-h2">{trPG("seo.photogen.diff.title")}</h2>
            <p className="mk-sub">{trPG("seo.photogen.diff.sub")}</p>
          </div>
          <div className="mk-args">
            {[0, 1, 2].map((i) => (
              <div className="mk-arg" key={i}>
                <span className="mk-arg__n">0{i + 1}</span>
                <h3>{trPG("seo.photogen.diff." + i + ".t")}</h3>
                <p>{trPG("seo.photogen.diff." + i + ".d")}</p>
              </div>
            ))}
          </div>
        </div>
      </section>

      <section className="mk-faq">
        <div className="mk-wrap mk-faq__inner">
          <div className="mk-section-head"><h2 className="mk-h2">{trPG("seo.photogen.faq.title")}</h2></div>
          <div className="mk-faq__list">
            {PG_FAQ.map((f, i) => (
              <details className="mk-faq__item" key={i}>
                <summary>
                  <span>{trPG("seo.photogen.faq." + i + ".q")}</span>
                  <IconPG name="chevDown" size={17} className="mk-faq__chev" />
                </summary>
                <p>{trPG("seo.photogen.faq." + i + ".a")}</p>
              </details>
            ))}
          </div>
        </div>
      </section>

      <section className="mk-close">
        <div className="mk-wrap mk-close__inner">
          <h2 className="mk-h2">{trPG("seo.photogen.foot.title")}</h2>
          <p>{trPG("seo.photogen.foot.sub")}</p>
          <a href={builderHref} className="mk-close__cta" style={{ textDecoration: "none" }}>
            <BtnPG variant="primary" iconRight={<IconPG name="arrow" size={15} />}>{trPG("seo.photogen.cta")}</BtnPG>
          </a>
        </div>
      </section>

      <window.MQRFooter />
    </div>
  );
}

window.MQRPhotoGen = PhotoGen;
})();
