// public/email-gate.jsx
// Soft email gate: fades the matrix on first visit and asks for an email.
// Dismissable via "Skip for now" or Escape. Fail-silent on backend errors —
// soft gate means we never block the visitor on a network hiccup.

function EmailGate({ t, dark }) {
  const STORAGE_KEY = "r-gate-state";
  // "skipped" decays after 10 days so returning visitors get another chance.
  // "submitted" persists forever — once we have an email, don't re-ask.
  const SKIP_TTL_MS = 10 * 24 * 60 * 60 * 1000;

  const { state: initialState, decayedFromSkip } = (() => {
    try {
      // If the URL carries ?inv=<token>, the visitor-tracking resolver is
      // about to identify them and pre-fill this gate's localStorage state.
      // Suppress the gate while that's pending to avoid a flash of the modal.
      const hasInv = new URLSearchParams(window.location.search).get("inv");
      if (hasInv) return { state: { status: "pending_inv_resolve" }, decayedFromSkip: false };
      const raw = localStorage.getItem(STORAGE_KEY);
      if (!raw) return { state: null, decayedFromSkip: false };
      const parsed = JSON.parse(raw);
      if (parsed?.status === "skipped" && parsed?.ts && Date.now() - parsed.ts > SKIP_TTL_MS) {
        try { localStorage.removeItem(STORAGE_KEY); } catch (_) {}
        return { state: null, decayedFromSkip: true };
      }
      return { state: parsed, decayedFromSkip: false };
    } catch (_) {}
    return { state: null, decayedFromSkip: false };
  })();

  const state = initialState;

  // Story-first flow: on a first visit the page opens at the story, and the gate waits until the
  // visitor reaches the offerings (StoryPage dispatches reurbano:request-gate). On a return visit
  // (story seen) or when there is no story, the gate shows on load per the usual state rules.
  const storyFirst = (() => {
    try {
      if (window.StoryRules && window.StoryRules.isSeen(localStorage.getItem("r-deck-seen"), window.STORY)) return false;
    } catch (_) { return false; }
    return !!(window.STORY && window.STORY.slides && window.STORY.slides.length);
  })();
  const [revealed, setRevealed] = React.useState(!storyFirst);

  const [phase, setPhase] = React.useState("visible"); // visible | thanks | fading | done

  React.useEffect(() => {
    if (revealed) return;
    const onRequest = () => setRevealed(true);
    window.addEventListener("reurbano:request-gate", onRequest, { once: true });
    return () => window.removeEventListener("reurbano:request-gate", onRequest);
  }, [revealed]);
  const [email, setEmail] = React.useState("");
  const inputRef = React.useRef(null);
  const previouslyFocused = React.useRef(null);
  const isTouchScreen = () => (window.matchMedia && window.matchMedia("(hover: none)").matches)
    || ("ontouchstart" in window);
  const headingId = "r-gate-heading";

  React.useEffect(() => {
    if (state || phase === "done" || !revealed) return;
    previouslyFocused.current = document.activeElement;
    // Skip auto-focus on touch devices — iOS Safari scrolls the page to the
    // focused input, leaving the page scrolled past the header when the gate
    // closes.
    if (!isTouchScreen()) inputRef.current?.focus();
    // Give focus back without scrolling to it: the element that had it (often the story cover's
    // button that led here) can sit far up the page, and the visitor is at the offerings.
    return () => { try { previouslyFocused.current?.focus({ preventScroll: true }); } catch (_) {} };
  }, [state, phase, revealed]);

  // iOS scrolls the page toward the email field while its keyboard is up. On a touch screen, remember
  // where the page was when the field took focus, and put it back there once the gate is done. Nothing
  // moves the page on a desktop, and the gate can appear while the page is still scrolling to the
  // offerings, so a position taken when it appears is not where the visitor stopped.
  const scrollAtFocus = React.useRef(null);
  const rememberScroll = () => {
    if (scrollAtFocus.current === null && isTouchScreen()) scrollAtFocus.current = window.scrollY;
  };
  React.useEffect(() => {
    if (phase === "done" && scrollAtFocus.current !== null) {
      try { window.scrollTo(0, scrollAtFocus.current); } catch (_) {}
    }
  }, [phase]);

  React.useEffect(() => {
    // Tell listeners (the residency coach mark) the gate is not blocking the screen: either it never
    // showed (already resolved / inv pending) or it just finished.
    if (state || phase === "done") {
      try { window.dispatchEvent(new CustomEvent("reurbano:gate-resolved")); } catch (_) {}
    }
  }, [phase]);

  React.useEffect(() => {
    if (state || phase === "done" || !revealed) return;
    const onKey = (e) => { if (e.key === "Escape") { e.preventDefault(); skip(); } };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [state, phase, revealed]);

  if (state || phase === "done" || !revealed) return null;
  if (!t) return null;

  const persist = (status, emailValue) => {
    try {
      localStorage.setItem(STORAGE_KEY, JSON.stringify({
        status, email: emailValue || undefined, ts: Date.now(),
      }));
    } catch (_) {}
  };

  const gatePhase = decayedFromSkip ? "returning_after_skip" : "fresh";

  const skip = () => {
    persist("skipped", null);
    if (window.posthog) window.posthog.capture("email_gate_skipped", { gate_phase: gatePhase });
    setPhase("fading");
    setTimeout(() => setPhase("done"), 300);
  };

  const submit = (e) => {
    e.preventDefault();
    const value = email.trim();
    if (!value || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
      inputRef.current?.focus();
      return;
    }
    persist("submitted", value);
    // Route to visitor tracker (handles Attio capture + PostHog identify).
    try { window.visitorTracker?.onEmailSubmit(value, { gate_phase: gatePhase }); } catch (_) {}
    setPhase("thanks");
    setTimeout(() => setPhase("fading"), 900);
    setTimeout(() => setPhase("done"), 1200);
  };

  const onTabKeydown = (e) => {
    if (e.key !== "Tab") return;
    const focusables = e.currentTarget.querySelectorAll(
      "input, button, [href], [tabindex]:not([tabindex='-1'])"
    );
    if (focusables.length === 0) return;
    const first = focusables[0];
    const last = focusables[focusables.length - 1];
    if (e.shiftKey && document.activeElement === first) {
      e.preventDefault(); last.focus();
    } else if (!e.shiftKey && document.activeElement === last) {
      e.preventDefault(); first.focus();
    }
  };

  const opacity = phase === "fading" ? 0 : 1;

  return (
    <div className="r-gate-backdrop" style={{
      position: "fixed", inset: 0, zIndex: 300,
      background: "rgba(250,247,243,0.7)",
      backdropFilter: "blur(6px)",
      WebkitBackdropFilter: "blur(6px)",
      opacity, transition: "opacity 300ms ease",
      display: "flex", alignItems: "center", justifyContent: "center",
      padding: 24,
    }}>
      <div
        role="dialog"
        aria-modal="true"
        aria-labelledby={headingId}
        onKeyDown={onTabKeydown}
        style={{
          position: "relative",
          width: "100%", maxWidth: 420,
          background: "#FFFFFF", border: "1px solid #E2E0DF",
          padding: "28px 24px",
          fontFamily: "var(--font-body)", color: "#393433",
        }}
      >
        {phase !== "thanks" && (
          <button
            type="button"
            onClick={skip}
            aria-label={t.gateClose || "Close"}
            style={{
              position: "absolute", top: 8, right: 10,
              width: 28, height: 28, padding: 0,
              background: "transparent", border: "none", cursor: "pointer",
              color: "#8A827F", fontSize: 22, lineHeight: 1,
              fontFamily: "var(--font-body)",
            }}
          >
            ×
          </button>
        )}
        {phase === "thanks" ? (
          <div aria-live="polite" style={{
            fontFamily: "var(--font-display)", fontSize: 18, color: "#4866B2",
            textAlign: "center", padding: "16px 0",
          }}>
            {t.gateThanks || "Thanks."}
          </div>
        ) : (
          <form onSubmit={submit}>
            <div id={headingId} style={{
              fontFamily: "var(--font-display)", fontSize: 18, fontWeight: 400,
              letterSpacing: "-0.01em", marginBottom: 8, paddingRight: 28,
            }}>
              {t.gateHeading}
            </div>
            <p style={{ fontSize: 13, lineHeight: 1.45, color: "#6B6361", marginTop: 0, marginBottom: 16 }}>
              {t.gateBody}
            </p>
            <p style={{ fontSize: 11, lineHeight: 1.45, color: "#8A827F", marginTop: 0, marginBottom: 16 }}>
              {t.gatePrivacy}
            </p>
            <input
              ref={inputRef}
              onFocus={rememberScroll}
              type="email"
              required
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              placeholder={t.gateEmailPlaceholder}
              style={{
                width: "100%", boxSizing: "border-box",
                height: 40, padding: "0 12px",
                border: "1px solid #C7C2BD", background: "#FAF7F3",
                fontFamily: "var(--font-body)", fontSize: 14, color: "#393433",
                marginBottom: 14,
              }}
            />
            <button type="submit" style={{
              width: "100%", height: 40,
              background: "#4866B2", color: "#FAF7F3",
              border: "none", cursor: "pointer",
              fontFamily: "var(--font-mono)", fontSize: 11,
              letterSpacing: "0.16em", textTransform: "uppercase",
            }}>
              {t.gateContinue}
            </button>
          </form>
        )}
      </div>
    </div>
  );
}

window.EmailGate = EmailGate;
