// app.jsx — root: routing, opt-in modal, vault transition, persistence, tweaks
const { useState: useS, useEffect: useE, useRef: useR } = React;

const STORE_KEY = "hyro70.member.v1";
const PAGE_KEY = "hyro70.page.v1";

function loadMember() {
  try { return JSON.parse(localStorage.getItem(STORE_KEY)); } catch (e) { return null; }
}
function saveMember(m) { try { localStorage.setItem(STORE_KEY, JSON.stringify(m)); } catch (e) {} }

/* ---------- Opt-in modal ---------- */
function OptinModal({ open, onClose, onSubmit, prefill }) {
  const [first, setFirst] = useS(prefill.firstName || "");
  const [email, setEmail] = useS(prefill.email || "");
  const [errs, setErrs] = useS({});

  useE(() => { if (open) { setFirst(prefill.firstName || ""); setEmail(prefill.email || ""); setErrs({}); } }, [open]);

  function submit(e) {
    e.preventDefault();
    const next = {};
    if (!first.trim()) next.first = "Pop your first name in";
    if (!/^[^@\s]+@[^@\s]+\.[^@\s]+$/.test(email.trim())) next.email = "That email does not look right";
    setErrs(next);
    if (Object.keys(next).length === 0) onSubmit({ firstName: first.trim(), email: email.trim() });
  }

  return (
    <div className={"modal-back" + (open ? " show" : "")} onClick={onClose}>
      <form className="modal" onClick={e => e.stopPropagation()} onSubmit={submit}>
        <button type="button" className="close" onClick={onClose} aria-label="Close">×</button>
        <div className="lock-ic">{Icon.unlock({})}</div>
        <h3>Start your 70 days</h3>
        <p className="sub">First name and email. That is it. Your tracker is on the other side.</p>
        <div className={"field" + (errs.first ? " err" : "")}>
          <label>First name</label>
          <input value={first} onChange={e => setFirst(e.target.value)} placeholder="Alex" autoComplete="given-name" />
          {errs.first && <div className="msg">{errs.first}</div>}
        </div>
        <div className={"field" + (errs.email ? " err" : "")}>
          <label>Email</label>
          <input value={email} onChange={e => setEmail(e.target.value)} placeholder="you@email.com" type="email" autoComplete="email" />
          {errs.email && <div className="msg">{errs.email}</div>}
        </div>
        <button className="cta block big" type="submit" style={{ marginTop: 6 }}>Open my tracker</button>
        <p className="fine">Free to join. We will only email you about your challenge.</p>
      </form>
    </div>
  );
}

/* ---------- Vault transition overlay ---------- */
function VaultOverlay({ phase }) {
  if (!phase) return null;
  return (
    <div className={"vault-overlay " + phase}>
      <div className="vault-door left"><div className="edge"></div></div>
      <div className="vault-door right"><div className="edge"></div></div>
      <div className="vault-seam">
        <div className="ring">{Icon.unlock({})}</div>
        <div className="t">Unlocking your 70</div>
      </div>
    </div>
  );
}

/* ---------- Press bar (toggled by showPress tweak) ---------- */
function PressBar() {
  return (
    <div style={{ background: "var(--hyro-white)", borderTop: "1px solid var(--hyro-line)", borderBottom: "1px solid var(--hyro-line)", padding: "22px 0" }}>
      <div className="wrap" style={{ display: "flex", flexWrap: "wrap", alignItems: "center", justifyContent: "center", gap: "16px 34px" }}>
        <span style={{ fontFamily: "var(--font-display)", textTransform: "uppercase", letterSpacing: "0.08em", fontSize: 12, color: "var(--hyro-grey-500)" }}>As seen in</span>
        {[0,1,2,3].map(i => (
          <span key={i} style={{ fontFamily: "var(--font-sans)", fontSize: 12, color: "var(--hyro-grey-300)", border: "1px dashed var(--hyro-grey-300)", borderRadius: 8, padding: "8px 18px" }}>[ Press logo ]</span>
        ))}
      </div>
    </div>
  );
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "heroCopy": "Offer-led",
  "previewDay": 39,
  "showPress": false,
  "stickyCta": true
}/*EDITMODE-END*/;

function App() {
  const [t, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [member, setMember] = useS(() => loadMember());
  const [page, setPage] = useS(() => (localStorage.getItem(PAGE_KEY) === "tracker" && loadMember()) ? "tracker" : "vault");
  const [optin, setOptin] = useS(false);
  const [phase, setPhase] = useS(null); // vault transition
  const [checked, setChecked] = useS(() => (loadMember()?.checkedDays) || []);
  const [claimed, setClaimed] = useS(() => loadMember()?.claimStatus === "submitted");
  const [justChecked, setJustChecked] = useS(null);
  const [stickyShow, setStickyShow] = useS(false);
  const heroRef = useR(null);

  const currentDay = Math.round(t.previewDay || 1);
  const dayRef = useR(currentDay);
  useE(() => { dayRef.current = currentDay; });

  // Auto-advance at 00:01 local time each new calendar day. In production the
  // current day is derived from the member's start date; here it rolls the
  // preview day forward so a fresh box opens at local midnight. One box per day.
  useE(() => {
    if (page !== "tracker" || !member) return;
    let timer;
    const schedule = () => {
      const now = new Date();
      const next = new Date(now.getFullYear(), now.getMonth(), now.getDate() + 1, 0, 1, 0, 0);
      timer = setTimeout(() => {
        setTweak("previewDay", Math.min(70, dayRef.current + 1));
        schedule();
      }, next - now);
    };
    schedule();
    return () => clearTimeout(timer);
  }, [page, member]);

  useE(() => { localStorage.setItem(PAGE_KEY, page); }, [page]);

  // sticky CTA visibility (mobile) — show once hero is scrolled past
  useE(() => {
    if (page !== "vault") { setStickyShow(false); return; }
    const el = heroRef.current;
    if (!el || !("IntersectionObserver" in window)) return;
    const io = new IntersectionObserver(([e]) => setStickyShow(!e.isIntersecting), { threshold: 0 });
    io.observe(el);
    return () => io.disconnect();
  }, [page]);

  function openCta() { setOptin(true); }

  function handleSubmit({ firstName, email }) {
    const existing = loadMember();
    const m = existing
      ? { ...existing, firstName, email }
      : { firstName, email, startDate: new Date().toISOString(), checkedDays: [], subscriptionStatus: "active", claimStatus: "none", memberId: "mbr_" + Math.random().toString(36).slice(2, 9) };
    saveMember(m);
    setMember(m);
    setChecked(m.checkedDays || []);
    setClaimed(m.claimStatus === "submitted");
    setOptin(false);
    runTransition();
  }

  function runTransition() {
    setPhase("closing");
    setTimeout(() => setPhase("closed"), 820);
    setTimeout(() => { setPage("tracker"); window.scrollTo(0, 0); }, 1320);
    setTimeout(() => setPhase("opening"), 1380);
    setTimeout(() => setPhase(null), 2200);
  }

  function toggleDay(day) {
    if (day > currentDay) return;
    setChecked(prev => {
      const has = prev.includes(day);
      const next = has ? prev.filter(d => d !== day) : [...prev, day].sort((a, b) => a - b);
      const m = loadMember(); if (m) { m.checkedDays = next; saveMember(m); }
      if (!has) { setJustChecked(day); setTimeout(() => setJustChecked(null), 360); }
      return next;
    });
  }

  function claim() {
    const m = loadMember(); if (m) { m.claimStatus = "submitted"; saveMember(m); }
    setClaimed(true);
  }

  function retake() {
    const m = loadMember();
    if (m) { m.checkedDays = []; m.claimStatus = "none"; m.startDate = new Date().toISOString(); saveMember(m); }
    setChecked([]); setClaimed(false); setTweak("previewDay", 1);
    window.scrollTo(0, 0);
  }

  function resetProgress() {
    localStorage.removeItem(STORE_KEY);
    localStorage.removeItem(PAGE_KEY);
    setMember(null); setChecked([]); setClaimed(false); setPage("vault");
    window.scrollTo(0, 0);
  }

  return (
    <>
      {page === "vault" && (
        <>
          <VaultDoor onCta={openCta} t={t} heroRef={heroRef} />
          {t.showPress && (
            <div style={{ position: "relative", marginTop: -1 }}><PressBar /></div>
          )}
          {/* sticky bottom CTA bar (mobile) */}
          {t.stickyCta && (
            <div className={"sticky-cta" + (stickyShow && !optin ? " show" : "")}>
              <div className="meta">70 days. <b>$50 back.</b></div>
              <button className="cta" onClick={openCta}>Start my 70 days</button>
            </div>
          )}
        </>
      )}

      {page === "tracker" && member && (
        <Tracker
          member={member} currentDay={currentDay} checked={checked}
          onToggle={toggleDay} claimed={claimed} onClaim={claim} onRetake={retake} justChecked={justChecked}
        />
      )}
      {page === "tracker" && !member && (
        /* safety: no member but on tracker — send back */
        <div style={{ padding: 60, textAlign: "center" }}>
          <button className="cta" onClick={() => setPage("vault")}>Back to the challenge</button>
        </div>
      )}

      <OptinModal open={optin} onClose={() => setOptin(false)} onSubmit={handleSubmit} prefill={member || {}} />
      <VaultOverlay phase={phase} />

      {/* TWEAKS */}
      <TweaksPanel>
        <TweakSection label="Page 1 — Hero" />
        <TweakSelect label="Hero headline" value={t.heroCopy}
          options={["Default", "Problem-led", "Offer-led", "Returning subscriber"]}
          onChange={v => setTweak("heroCopy", v)} />
        <TweakToggle label="Show ‘as seen in’ bar" value={t.showPress} onChange={v => setTweak("showPress", v)} />
        <TweakToggle label="Sticky mobile CTA" value={t.stickyCta} onChange={v => setTweak("stickyCta", v)} />

        <TweakSection label="Page 2 — Tracker preview" />
        <TweakSlider label="Preview day" value={t.previewDay} min={1} max={70} step={1} unit=" / 70"
          onChange={v => setTweak("previewDay", v)} />
        <TweakButton label="View the tracker" onClick={() => { if (!member) { handleSubmit({ firstName: "Alex", email: "alex@email.com" }); } else { setPage("tracker"); window.scrollTo(0,0); } }} />
        <TweakButton label="Reset progress · back to start" onClick={resetProgress} />
      </TweaksPanel>
    </>
  );
}

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