/* global React, ReactDOM, useTweaks, TweaksPanel, TweakSection, TweakRadio, TweakColor, TweakSlider,
   Hero, Problem, Features, HowItWorks, FinalCTA, StickyCTA, useReveal */
const { useState, useEffect, useRef, useCallback } = React;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroLayout": "lower",
  "accent": "#7bbf4f",
  "sway": true
} /*EDITMODE-END*/;

/* locked-in defaults: scroll grade intensity=6, veil=balanced */
const MOTION_DEFAULT = 6;
const LEGIBILITY_DEFAULT = "balanced";

/* readability veil strength over the photo */
const VEIL = { subtle: 0.30, balanced: 0.46, high: 0.62 };

/* accent -> matching deeper shade for hover/shadow */
const ACCENT_DEEP = {
  "#e2613c": "#c4492a",
  "#e8a13a": "#d2861f",
  "#d9763b": "#bd5d24",
  "#7bbf4f": "#5fa238"
};

/* linear interpolate */
const lerp = (a, b, t) => a + (b - a) * t;
const clamp01 = (x) => x < 0 ? 0 : x > 1 ? 1 : x;

/* grade endpoints: [top(sparse/cool), bottom(lush/golden)] */
const GRADE = {
  saturate: [0.52, 1.30],
  brightness: [0.83, 1.07],
  contrast: [0.93, 1.07],
  hue: [-9, 9], // deg
  sepia: [0.02, 0.17],
  washTop: [0.46, 0.0], // cool slate alpha
  washBottom: [0.30, 0.52], // earth shade alpha at very bottom
  gold: [0.0, 0.92], // golden glow strength
  grow: [1.0, 1.16] // grass scales up from the bottom as it "grows"
};

const TALLY_SRC = "https://tally.so/embed/LZkAkl?alignLeft=1&hideTitle=1&dynamicHeight=1";

function EarlyAccessModal({ open, onClose }) {
  const dialogRef = useRef(null);
  const iframeRef = useRef(null);

  // scroll-lock + Escape; assign the iframe src directly on open
  useEffect(() => {
    if (!open) return;
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = "hidden";
    const onKey = (e) => {if (e.key === "Escape") onClose();};
    document.addEventListener("keydown", onKey);
    // React-mounted iframes aren't picked up by Tally.loadEmbeds reliably,
    // so set src ourselves. embed.js still handles dynamicHeight resizing.
    const tf = setTimeout(() => {
      const fr = iframeRef.current;
      if (fr && !fr.src) fr.src = TALLY_SRC;
      if (window.Tally && Tally.loadEmbeds) Tally.loadEmbeds();
    }, 40);
    return () => {
      clearTimeout(tf);
      document.removeEventListener("keydown", onKey);
      document.body.style.overflow = prevOverflow;
    };
  }, [open, onClose]);

  if (!open) return null;

  return (
    <div className="ea-overlay" onMouseDown={(e) => {if (e.target === e.currentTarget) onClose();}}>
      <div className="ea-modal" role="dialog" aria-modal="true" aria-labelledby="ea-title" ref={dialogRef}>
        <button className="ea-close" aria-label="Close" onClick={onClose}>×</button>
        <p className="eyebrow">Early access</p>
        <h3 className="ea-title" id="ea-title">Be first on the lawn.</h3>
        <p className="ea-sub">
          Drop your email and we'll let you know the day Grassara lands on Android.
        </p>
        <div className="ea-embed">
          <iframe
            ref={iframeRef}
            data-tally-src={TALLY_SRC}
            loading="lazy"
            width="100%"
            frameBorder="0"
            marginHeight="0"
            marginWidth="0"
            title="Grassara early access">
          </iframe>
        </div>
      </div>
    </div>);

}

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [showSticky, setShowSticky] = useState(false);
  const [eaOpen, setEaOpen] = useState(false);
  const rootRef = useRef(document.documentElement);

  useReveal();

  /* ---------- analytics: page view + section views ---------- */
  useEffect(() => {
    if (typeof window.track === "function") window.track("page_view", { page: "home" });
    const secs = document.querySelectorAll("[data-screen-label]");
    const seen = new Set();
    const io = new IntersectionObserver(
      (ents) => ents.forEach((en) => {
        const name = en.target.getAttribute("data-screen-label");
        if (en.isIntersecting && !seen.has(name)) {
          seen.add(name);
          if (typeof window.track === "function") window.track("section_view", { section: name });
        }
      }),
      { threshold: 0.4 }
    );
    secs.forEach((s) => io.observe(s));
    return () => io.disconnect();
  }, []);

  /* apply accent tokens */
  useEffect(() => {
    const r = rootRef.current;
    r.style.setProperty("--accent", t.accent);
    r.style.setProperty("--accent-deep", ACCENT_DEEP[t.accent] || t.accent);
  }, [t.accent]);

  /* apply legibility veil — locked to balanced */
  useEffect(() => {
    rootRef.current.style.setProperty("--veil", VEIL[LEGIBILITY_DEFAULT] ?? VEIL.balanced);
  }, []);

  /* ambient sway on/off */
  useEffect(() => {
    rootRef.current.style.setProperty("--sway-play", t.sway ? "running" : "paused");
  }, [t.sway]);

  /* ---------- scroll-driven color grade ---------- */
  useEffect(() => {
    const r = rootRef.current;
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

    const setGrade = (p) => {
      r.style.setProperty("--grade-saturate", lerp(...GRADE.saturate, p).toFixed(3));
      r.style.setProperty("--grade-brightness", lerp(...GRADE.brightness, p).toFixed(3));
      r.style.setProperty("--grade-contrast", lerp(...GRADE.contrast, p).toFixed(3));
      r.style.setProperty("--grade-hue", lerp(...GRADE.hue, p).toFixed(2) + "deg");
      r.style.setProperty("--grade-sepia", lerp(...GRADE.sepia, p).toFixed(3));
      r.style.setProperty("--wash-top", `rgba(122,136,142,${lerp(...GRADE.washTop, p).toFixed(3)})`);
      r.style.setProperty("--wash-bottom", `rgba(40,28,12,${lerp(...GRADE.washBottom, p).toFixed(3)})`);
      r.style.setProperty("--wash-gold", lerp(...GRADE.gold, p).toFixed(3));
      r.style.setProperty("--grow-scale", lerp(...GRADE.grow, p).toFixed(4));
    };

    if (reduce) {setGrade(0.5);return;} // static fallback, mid-grade

    /* motion intensity scales how dramatic the grade swing is.
       on small screens keep it subtle so it never overwhelms content. */
    const mobile = window.matchMedia("(max-width: 760px)").matches;
    const m = clamp01(MOTION_DEFAULT / 10) * (mobile ? 0.55 : 1);

    /* Continuous rAF poll of scroll position. More reliable than the
       'scroll' event (which can coalesce/skip under programmatic scrolling),
       and cheap — it only writes when the position actually changes.
       Paused while the tab is hidden so we burn no cycles in the background. */
    let raf,lastY = -1,lastMax = -1;
    const tick = () => {
      const y = window.scrollY || document.documentElement.scrollTop || 0;
      const max = document.documentElement.scrollHeight - window.innerHeight;
      if (y !== lastY || max !== lastMax) {
        lastY = y;lastMax = max;
        const raw = max > 0 ? clamp01(y / max) : 0;
        const p = clamp01(0.5 + (raw - 0.5) * m); // scale swing by motion
        setGrade(p);
        // show past the hero, but hide once the final CTA (with its own
        // Download button + the footer links) scrolls into view.
        const finalEl = document.querySelector(".final");
        const finalUp = finalEl && finalEl.getBoundingClientRect().top < window.innerHeight * 0.85;
        setShowSticky(y > window.innerHeight * 0.9 && !finalUp);
      }
      raf = requestAnimationFrame(tick);
    };
    const start = () => {if (!raf) {lastY = -1;raf = requestAnimationFrame(tick);}};
    const stop = () => {if (raf) {cancelAnimationFrame(raf);raf = 0;}};
    const onVis = () => document.hidden ? stop() : start();
    document.addEventListener("visibilitychange", onVis);
    start();
    return () => {stop();document.removeEventListener("visibilitychange", onVis);};
  }, []);

  const handleDownload = useCallback((e) => {
    e.preventDefault();
    if (typeof window.track === "function") window.track("cta_click", { cta: "early_access" });
    setEaOpen(true);
  }, []);

  return (
    <React.Fragment>
      {/* fixed lawn backdrop */}
      <div className="lawn" aria-hidden="true">
        <div className="lawn__grow">
          <div className="lawn__img"></div>
          <div className="lawn__img lawn__img--photo"></div>
        </div>
        <div className="lawn__grain"></div>
        <div className="lawn__wash"></div>
        <div className="lawn__gold"></div>
        <div className="lawn__veil"></div>
      </div>

      <main className="page" id="top">
        <Hero layout={t.heroLayout} onDownload={handleDownload} />
        <Problem />
        <Features />
        <HowItWorks />
        <FinalCTA onDownload={handleDownload} />
      </main>

      <StickyCTA show={showSticky} onDownload={handleDownload} />

      <EarlyAccessModal open={eaOpen} onClose={() => setEaOpen(false)} />

      <TweaksPanel>
        <TweakSection label="Hero layout" />
        <TweakRadio
          label="Alignment"
          value={t.heroLayout}
          options={[
          { label: "Centered", value: "centered" },
          { label: "Left", value: "left" },
          { label: "Lower-left", value: "lower" }]
          }
          onChange={(v) => setTweak("heroLayout", v)} />
        
        <TweakSection label="Accent" />
        <TweakColor
          label="CTA color"
          value={t.accent}
          options={["#e2613c", "#e8a13a", "#7bbf4f"]}
          onChange={(v) => setTweak("accent", v)} />
        
        <TweakSection label="Motion" />
        <TweakToggle
          label="Ambient sway"
          value={t.sway}
          onChange={(v) => setTweak("sway", v)} />
        
      </TweaksPanel>
    </React.Fragment>);

}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);