/* app.jsx — production entry point for the Ditto Vault landing page.
   Replaces the design-canvas mockup shell with a single, scrollable, responsive
   page. Mounts a global `window.openWaitlist()` that any CTA in the section
   components can call to open the waitlist modal.
*/

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

// — Responsive switch ────────────────────────────────────────────────────
// Below 768px we render the mobile JSX variants of each section. CSS
// media-queries in styles.css handle smaller-scale typography concurrently.
function useIsMobile(breakpoint = 768) {
  const get = () => (typeof window !== "undefined" ? window.innerWidth < breakpoint : false);
  const [m, setM] = useState(get);
  useEffect(() => {
    const onResize = () => setM(get());
    window.addEventListener("resize", onResize);
    return () => window.removeEventListener("resize", onResize);
  }, []);
  return m;
}

// — Scroll-entry reveal hook ─────────────────────────────────────────────
// Toggles `.is-visible` on first viewport entry. Disconnects after firing
// (one-shot). Respects `prefers-reduced-motion`: in that mode we skip the
// observer entirely and render visible from the start.
function useReveal(threshold = 0.08, rootMargin = "0px 0px -8% 0px") {
  const ref = useRef(null);
  const [visible, setVisible] = useState(false);
  useEffect(() => {
    if (typeof window === "undefined") return;
    if (window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches) {
      setVisible(true);
      return;
    }
    const node = ref.current;
    if (!node) return;
    const io = new IntersectionObserver(
      (entries) => {
        for (const e of entries) {
          if (e.isIntersecting) {
            setVisible(true);
            io.disconnect();
            break;
          }
        }
      },
      { threshold, rootMargin }
    );
    io.observe(node);
    return () => io.disconnect();
  }, [threshold, rootMargin]);
  return [ref, visible];
}

// — Reveal wrapper ───────────────────────────────────────────────────────
// Adds `.reveal` + `.is-visible` class flow + optional stagger delay.
// `delay` lets us cascade adjacent reveals; `as` switches the rendered tag.
function Reveal({ children, delay = 0, as = "div", className = "", style, ...rest }) {
  const [ref, visible] = useReveal();
  const Tag = as;
  const cls = ["reveal", visible ? "is-visible" : "", className].filter(Boolean).join(" ");
  const css = { ...(style || {}), "--reveal-delay": delay ? `${delay}ms` : undefined };
  return <Tag ref={ref} className={cls} style={css} {...rest}>{children}</Tag>;
}

// — Active section tracker ───────────────────────────────────────────────
// Watches sections with [id] and reports which one is most prominent in
// the viewport. Used by Nav to highlight the matching link as you scroll.
function useActiveSection(ids) {
  const [active, setActive] = useState(ids[0] || null);
  useEffect(() => {
    if (typeof window === "undefined") return;
    const nodes = ids
      .map((id) => document.getElementById(id))
      .filter(Boolean);
    if (!nodes.length) return;
    const visible = new Map();
    const io = new IntersectionObserver(
      (entries) => {
        for (const e of entries) {
          if (e.isIntersecting) visible.set(e.target.id, e.intersectionRatio);
          else visible.delete(e.target.id);
        }
        if (visible.size > 0) {
          // Pick the section with the largest intersection ratio.
          let best = null;
          let bestRatio = -1;
          for (const [id, ratio] of visible.entries()) {
            if (ratio > bestRatio) { best = id; bestRatio = ratio; }
          }
          if (best) setActive(best);
        }
      },
      { rootMargin: "-30% 0px -50% 0px", threshold: [0, 0.1, 0.25, 0.5, 0.75, 1] }
    );
    nodes.forEach((n) => io.observe(n));
    return () => io.disconnect();
  }, [ids.join("|")]);
  return active;
}

// — Waitlist submit ──────────────────────────────────────────────────────
// POSTs to the Vercel serverless function at /api/waitlist (api/waitlist.js).
// Server-side validation + structured logging to Vercel function logs. To
// add real email/CRM forwarding, set RESEND_API_KEY + WAITLIST_NOTIFY_EMAIL
// env vars in the Vercel project settings.
async function submitToWaitlist({ email, accredited }) {
  try {
    const r = await fetch("/api/waitlist", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ email, accredited, source: "vaults-landing" }),
    });
    const data = await r.json().catch(() => ({}));
    return { ok: r.ok && data && data.ok !== false };
  } catch (e) {
    console.error("[waitlist] submit_failed", e);
    return { ok: false };
  }
}

function isValidEmail(s) {
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(s);
}

// — Interactive waitlist dialog (controlled form) ────────────────────────
function InteractiveWaitlistDialog({ onClose }) {
  const [email, setEmail] = useState("");
  const [accredited, setAccredited] = useState(false);
  const [state, setState] = useState("default"); // default | focus | error | submitting | success
  const [errorMsg, setErrorMsg] = useState(null);
  const inputRef = useRef(null);

  useEffect(() => {
    // Focus the email field on open for keyboard users.
    setTimeout(() => inputRef.current && inputRef.current.focus(), 0);
  }, []);

  const submit = async (e) => {
    if (e && e.preventDefault) e.preventDefault();
    if (state === "submitting" || state === "success") return;
    if (!isValidEmail(email)) {
      setErrorMsg("Please enter a valid email address.");
      setState("error");
      return;
    }
    setErrorMsg(null);
    setState("submitting");
    try {
      const r = await submitToWaitlist({ email, accredited });
      if (r && r.ok) setState("success");
      else throw new Error("submit-failed");
    } catch (_) {
      setErrorMsg("Something went wrong. Please try again.");
      setState("error");
    }
  };

  const isSuccess = state === "success";
  const isError = state === "error";
  const isSubmitting = state === "submitting";
  const fieldState = isError ? "error" : (state === "focus" ? "focus" : "default");
  const ringColor = isError ? "var(--danger)" : (state === "focus" ? "var(--accent)" : "var(--line-strong)");

  return (
    <div role="dialog" aria-modal="true" aria-labelledby="wl-heading" style={{
      width:"min(480px, calc(100vw - 32px))",
      background:"var(--bg-elev-1)",
      border:"1px solid var(--line-strong)",
      borderRadius:"var(--r-4)",
      boxShadow:"0 32px 80px rgba(0,0,0,0.5), 0 0 0 1px var(--line) inset",
      overflow:"hidden",
      display:"flex", flexDirection:"column",
    }}>
      <div style={{ padding:"22px 26px 18px", borderBottom:"1px solid var(--line)", display:"flex", justifyContent:"space-between", alignItems:"flex-start" }}>
        <div style={{ display:"flex", flexDirection:"column", gap:6 }}>
          <div className="eyebrow"><span className="slash">/</span><span>Waitlist · vault access</span></div>
          <h3 id="wl-heading" style={{ margin:0, fontFamily:"var(--font-display)", fontSize:22, fontWeight:500, letterSpacing:"-0.015em", lineHeight:1.15, color:"var(--text)" }}>
            {isSuccess ? "You're on the list." : "Join the dvUSDCx waitlist"}
          </h3>
        </div>
        <button aria-label="Close" onClick={onClose} style={{
          width:28, height:28, border:"1px solid var(--line-strong)", background:"transparent",
          borderRadius:"var(--r-2)", color:"var(--text-3)", display:"inline-flex",
          alignItems:"center", justifyContent:"center", cursor:"pointer", flexShrink:0,
        }}>
          <svg width="11" height="11" viewBox="0 0 11 11"><path d="M1 1l9 9M10 1L1 10" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" /></svg>
        </button>
      </div>

      <form onSubmit={submit} style={{ padding:"22px 26px 24px", display:"flex", flexDirection:"column", gap:18 }}>
        {!isSuccess && (
          <p style={{ margin:0, fontSize:13, color:"var(--text-2)", lineHeight:1.55 }}>
            We'll email you when the vault opens to deposits and when the marketplace tier accepts accreditation. No drip campaigns.
          </p>
        )}

        {isSuccess ? (
          <div style={{ display:"flex", flexDirection:"column", gap:14, padding:"20px 18px", background:"var(--accent-soft)", border:"1px solid var(--accent-line)", borderRadius:"var(--r-3)" }}>
            <div style={{ display:"flex", alignItems:"center", gap:10 }}>
              <span style={{ width:20, height:20, borderRadius:"50%", background:"var(--accent)", color:"var(--text-on-acc)", display:"inline-flex", alignItems:"center", justifyContent:"center" }}>
                <Icon.check />
              </span>
              <span style={{ fontSize:14, color:"var(--text)", fontWeight:600 }}>Email confirmed: {email}</span>
            </div>
            <div style={{ fontSize:12, color:"var(--text-2)", lineHeight:1.55 }}>
              {accredited
                ? "You're flagged for accreditation. We'll send a Persona link when the marketplace shelf opens to verify investors."
                : "You'll get the launch email for the core vault. If you want marketplace access, check the accredited-investor box and re-submit any time."}
            </div>
          </div>
        ) : (
          <>
            <label style={{ display:"flex", flexDirection:"column", gap:8 }}>
              <div style={{ display:"flex", justifyContent:"space-between", alignItems:"baseline" }}>
                <span className="mono" style={{ fontSize:10, color:"var(--text-3)", letterSpacing:"0.06em", textTransform:"uppercase" }}>
                  Email
                </span>
                {!isError && <span className="mono" style={{ fontSize:10, color:"var(--text-4)" }}>Required</span>}
              </div>
              <div style={{
                display:"flex", alignItems:"center",
                border:"1px solid " + ringColor,
                background: state === "focus" ? "var(--bg-elev-3)" : "var(--bg-elev-2)",
                borderRadius:"var(--r-3)",
                padding:"0 14px", height:44,
                boxShadow: state === "focus" ? "0 0 0 3px var(--accent-soft)" : "none",
                transition:"border-color .12s, box-shadow .12s",
              }}>
                <input
                  ref={inputRef}
                  type="email"
                  inputMode="email"
                  autoComplete="email"
                  placeholder="you@firm.com"
                  value={email}
                  onChange={(e) => { setEmail(e.target.value); if (state === "error") setState("focus"); }}
                  onFocus={() => { if (state !== "error") setState("focus"); }}
                  onBlur={() => { if (state === "focus") setState("default"); }}
                  disabled={isSubmitting}
                  style={{
                    flex:1, background:"transparent", border:"none", outline:"none",
                    color:"var(--text)", fontFamily:"var(--font-sans)", fontSize:14,
                    letterSpacing:"-0.005em",
                  }}
                />
              </div>
              {isError && errorMsg && (
                <span style={{ fontSize:11, color:"var(--danger)", fontFamily:"var(--font-mono)", letterSpacing:"0.02em" }}>
                  → {errorMsg}
                </span>
              )}
            </label>

            <label style={{ display:"flex", gap:10, cursor:"pointer", paddingTop:4, alignItems:"flex-start", userSelect:"none" }}>
              <input
                type="checkbox"
                checked={accredited}
                onChange={(e) => setAccredited(e.target.checked)}
                style={{ position:"absolute", opacity:0, pointerEvents:"none" }}
              />
              <span aria-hidden="true" style={{
                width:18, height:18, flexShrink:0, marginTop:1,
                border:"1px solid " + (accredited ? "var(--accent)" : "var(--line-strong)"),
                background: accredited ? "var(--accent)" : "var(--bg-elev-2)",
                borderRadius:"var(--r-2)",
                display:"inline-flex", alignItems:"center", justifyContent:"center",
                color: "var(--text-on-acc)",
                transition:"background .12s, border-color .12s",
              }}>
                {accredited && <Icon.check />}
              </span>
              <div style={{ display:"flex", flexDirection:"column", gap:3 }}>
                <span style={{ fontSize:13, color:"var(--text)", letterSpacing:"-0.005em" }}>
                  I am an accredited investor
                </span>
                <span style={{ fontSize:11, color:"var(--text-3)", lineHeight:1.5 }}>
                  Required for the marketplace tier (dvFOBXX, dvHQLAX, dvDLR, dvCredit-A). Optional for the core vault.
                </span>
              </div>
            </label>
          </>
        )}

        {!isSuccess && (
          <div style={{ paddingTop:8, borderTop:"1px solid var(--line)", display:"flex", justifyContent:"space-between", alignItems:"center", gap:12, marginTop:6 }}>
            <span className="mono" style={{ fontSize:10, color:"var(--text-4)", letterSpacing:"0.04em" }}>
              We don't share your email. Ever.
            </span>
            <div style={{ display:"flex", gap:10 }}>
              <button type="button" className="btn btn-secondary" style={{ height:36, fontSize:13 }} onClick={onClose}>Cancel</button>
              <button type="submit" className="btn btn-primary" style={{ height:36, fontSize:13 }} disabled={isSubmitting}>
                {isSubmitting ? "Submitting…" : <>Join waitlist <Icon.arrow /></>}
              </button>
            </div>
          </div>
        )}

        {isSuccess && (
          <div style={{ paddingTop:8, borderTop:"1px solid var(--line)", display:"flex", justifyContent:"flex-end", marginTop:6 }}>
            <button type="button" className="btn btn-primary" style={{ height:36, fontSize:13 }} onClick={onClose}>Done</button>
          </div>
        )}
      </form>
    </div>
  );
}

// — Modal shell (backdrop + ESC + body scroll lock) ──────────────────────
function WaitlistModal({ open, onClose }) {
  // ESC key closes
  useEffect(() => {
    if (!open) return;
    const onKey = (e) => { if (e.key === "Escape") onClose(); };
    window.addEventListener("keydown", onKey);
    document.body.style.overflow = "hidden";
    return () => {
      window.removeEventListener("keydown", onKey);
      document.body.style.overflow = "";
    };
  }, [open, onClose]);

  if (!open) return null;
  return (
    <div
      onClick={onClose}
      className="ditto-root"
      style={{
        position:"fixed", inset:0, zIndex:100,
        background:"rgba(5, 7, 11, 0.72)",
        backdropFilter:"blur(6px)",
        WebkitBackdropFilter:"blur(6px)",
        display:"flex", alignItems:"center", justifyContent:"center",
        padding:16,
        animation:"wl-fade-in 220ms cubic-bezier(0.23, 1, 0.32, 1)",
      }}
    >
      <div onClick={(e) => e.stopPropagation()}>
        <InteractiveWaitlistDialog onClose={onClose} />
      </div>
    </div>
  );
}

// — Root app ─────────────────────────────────────────────────────────────
const NAV_IDS = ["hero", "vault", "onramp", "marketplace", "dvn", "roadmap"];

function App() {
  const isMobile = useIsMobile();
  const [waitlistOpen, setWaitlistOpen] = useState(false);
  const activeSection = useActiveSection(NAV_IDS);

  // Expose a global so the section CTA buttons can open the modal without
  // prop-drilling through every component.
  useEffect(() => {
    window.openWaitlist = () => setWaitlistOpen(true);
    return () => { delete window.openWaitlist; };
  }, []);

  const cls = "ditto-root" + (isMobile ? " is-mobile" : "");

  return (
    <div className={cls} style={{ minHeight:"100vh", background:"var(--bg)", position:"relative" }}>
      <Nav active={activeSection} mobile={isMobile} />

      <header id="hero">
        {isMobile ? <HeroMobile headline="a" heroVariant="layers" /> : <Hero headline="a" heroVariant="layers" />}
      </header>

      <Reveal as="section" id="vault">
        <SectionVault mobile={isMobile} />
      </Reveal>

      <Reveal as="section" id="onramp" delay={80}>
        <SectionOnramp mobile={isMobile} />
      </Reveal>

      <Reveal as="section" id="marketplace">
        <SectionMarketplace mobile={isMobile} />
      </Reveal>

      <Reveal as="section" id="dvn" delay={80}>
        <SectionDVN mobile={isMobile} />
      </Reveal>

      <Reveal>
        <SectionRoadmap mobile={isMobile} />
      </Reveal>

      {/* Page grain — fixed overlay, pointer-events:none. Adds physicality
          without changing contrast or perf cost beyond first paint. */}
      <div className="ditto-grain" aria-hidden="true" />

      <WaitlistModal open={waitlistOpen} onClose={() => setWaitlistOpen(false)} />
    </div>
  );
}

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