// Real member access. Identity comes only from the server's HttpOnly session.
const MEMBER_LABELS = { google: "Google", linkedin: "LinkedIn", github: "GitHub", microsoft: "Microsoft", email: "Email link", account: "FBO account" };
const MEMBER_ERRORS = {
  denied: "You cancelled sign-in. Choose a method below to try again.",
  expired: "This sign-in has expired or was already used. Please start again.",
  noemail: "That provider did not confirm your email address. Use an email link instead.",
  unsupported_verified_email: "This provider cannot confirm ownership of your email. Use an email link instead.",
  account_exists: "An account already uses this email. Sign in with an email link, then connect this provider in Account settings.",
  identity_email_changed: "The email on this sign-in has changed. Use an email link or contact hi@forbestoffer.uk.",
  failed: "Sign-in could not be completed. Please try again or use an email link.",
  link_requires_login: "Sign in to your FBO account before connecting another method.",
  unavailable: "Account access is temporarily unavailable. Your original purchase links still work.",
};
async function memberRequest(body) {
  const response = await fetch("/api/account", { method: body ? "POST" : "GET", credentials: "same-origin", cache: "no-store", headers: body ? { "Content-Type": "application/json" } : {}, ...(body ? { body: JSON.stringify(body) } : {}) });
  const data = await response.json().catch(() => ({}));
  if (!response.ok) throw new Error(MEMBER_ERRORS[data.code] || data.error || "Account access is unavailable. Please try again.");
  return data;
}
function useMember(enabled) {
  const [state, setState] = useState({ user: null, loaded: false, enabled: false, error: "" });
  const generation = useRef(0);
  const identity = useRef(undefined);
  const clearMemberStorage = () => {
    try { for (const key of ["fbo-library-token", "fbo-signed-in-email", "fbo-member-library-owner", "fbo-user"]) localStorage.removeItem(key); } catch {}
  };
  const remember = data => {
    const nextIdentity = data.user ? data.user.id : null;
    const changed = identity.current !== nextIdentity;
    identity.current = nextIdentity;
    if (data.libraryToken) {
      try { localStorage.setItem("fbo-library-token", data.libraryToken); localStorage.setItem("fbo-member-library-owner", data.user.id); } catch {}
    }
    if (!data.user) { try { if (localStorage.getItem("fbo-member-library-owner")) {
      const saved = localStorage.getItem("fbo-library-token") || "";
      // Guest purchase c/m links may replace an account credential. Preserve them.
      if (saved.startsWith("e.")) clearMemberStorage();
      else { localStorage.removeItem("fbo-member-library-owner"); localStorage.removeItem("fbo-signed-in-email"); }
    } } catch {} }
    setState({ user: data.user || null, membership: data.membership || null, loaded: true, enabled: true, error: "" });
    // A full-page OAuth callback changes the cookie too: notify already-open tabs.
    // Identity comparison prevents storage-event ping-pong between tabs.
    if (changed) announce();
  };
  const refresh = async () => {
    const turn = ++generation.current;
    try { const data = await memberRequest(); if (turn === generation.current) remember(data); }
    catch (e) { if (turn === generation.current) setState({ user: null, loaded: true, enabled: true, error: e.message }); }
  };
  useEffect(() => {
    if (!enabled) { ++generation.current; setState({ user: null, loaded: true, enabled: false, error: "" }); return; }
    refresh();
    const sync = e => {
      if (e.key === "fbo-library-token" && !e.newValue) ++generation.current;
      if (e.key !== "fbo-member-event") return;
      let event = {}; try { event = JSON.parse(e.newValue || "{}"); } catch {}
      if (event.action === "logout") {
        ++generation.current; identity.current = null; clearMemberStorage();
        setState({ user: null, loaded: true, enabled: true, error: "" });
        window.dispatchEvent(new Event("fbo-member-signed-out"));
      } else refresh();
    };
    window.addEventListener("storage", sync);
    return () => { ++generation.current; window.removeEventListener("storage", sync); };
  }, [enabled]);
  const announce = (action = "updated") => { try { localStorage.setItem("fbo-member-event", JSON.stringify({ action, at: Date.now(), nonce: Math.random() })); } catch {} };
  const accept = data => { ++generation.current; remember(data); announce(); };
  const signOut = async () => {
    ++generation.current;
    await memberRequest({ action: "logout" });
    ++generation.current;
    identity.current = null;
    clearMemberStorage();
    setState({ user: null, loaded: true, enabled: true, error: "" });
    window.dispatchEvent(new Event("fbo-member-signed-out"));
    announce("logout");
  };
  return { ...state, loaded: !enabled || (state.enabled && state.loaded), refresh, accept, signOut };
}
function ProviderMark({ provider }) {
  if (provider === "google") return <svg viewBox="0 0 24 24" aria-hidden="true"><path fill="#4285F4" d="M21.6 12.23c0-.71-.06-1.39-.18-2.05H12v3.88h5.38a4.6 4.6 0 0 1-2 3.02v2.51h3.24c1.9-1.75 2.98-4.33 2.98-7.36Z"/><path fill="#34A853" d="M12 22c2.7 0 4.96-.9 6.62-2.41l-3.24-2.51c-.9.6-2.05.97-3.38.97-2.6 0-4.82-1.76-5.61-4.12H3.05v2.59A10 10 0 0 0 12 22Z"/><path fill="#FBBC05" d="M6.39 13.93A6 6 0 0 1 6.07 12c0-.67.12-1.32.32-1.93V7.48H3.05A10 10 0 0 0 2 12c0 1.61.38 3.14 1.05 4.52l3.34-2.59Z"/><path fill="#EA4335" d="M12 5.95c1.47 0 2.79.51 3.82 1.51l2.87-2.87A9.6 9.6 0 0 0 12 2a10 10 0 0 0-8.95 5.48l3.34 2.59C7.18 7.71 9.4 5.95 12 5.95Z"/></svg>;
  if (provider === "linkedin") return <span aria-hidden="true" className="provider-linkedin">in</span>;
  if (provider === "github") return <svg viewBox="0 0 24 24" aria-hidden="true" fill="currentColor"><path d="M12 2a10 10 0 0 0-3.16 19.49c.5.09.68-.22.68-.48v-1.87c-2.78.6-3.37-1.18-3.37-1.18-.45-1.16-1.11-1.47-1.11-1.47-.91-.62.07-.61.07-.61 1 .07 1.53 1.03 1.53 1.03.9 1.53 2.34 1.09 2.91.83.09-.65.35-1.09.64-1.34-2.22-.25-4.56-1.11-4.56-4.95 0-1.09.39-1.98 1.03-2.68-.1-.25-.45-1.27.1-2.65 0 0 .84-.27 2.75 1.02a9.5 9.5 0 0 1 5 0c1.9-1.29 2.74-1.02 2.74-1.02.55 1.38.2 2.4.1 2.65.64.7 1.03 1.59 1.03 2.68 0 3.85-2.34 4.69-4.57 4.94.36.31.68.92.68 1.85v2.77c0 .27.18.58.69.48A10 10 0 0 0 12 2Z"/></svg>;
  return <span aria-hidden="true">↗</span>;
}
function MemberProviders({ providers = [], link = false }) {
  return <div className="member-providers">{providers.filter(p => MEMBER_LABELS[p]).map(p => <a className="member-provider" key={p} href={`/api/login?provider=${encodeURIComponent(p)}${link ? "&intent=link" : ""}`}><ProviderMark provider={p}/><span>{link ? "Connect" : "Continue with"} {MEMBER_LABELS[p]}</span><span className="member-provider-arrow" aria-hidden="true">↗</span></a>)}</div>;
}
function MemberAuthPage({ mode, setPage, member, pay }) {
  const continueAfterSignIn = () => {
    let target = "library";
    try {
      const saved = JSON.parse(localStorage.getItem("fbo-account-return") || "null");
      if (saved && ["membership", "checkout", "calendar"].includes(saved.page) && Date.now() - saved.at >= 0 && Date.now() - saved.at < 30 * 60 * 1000) target = saved.page;
      localStorage.removeItem("fbo-account-return");
    } catch {}
    setPage(target);
  };
  const signup = mode === "signup";
  const [email, setEmail] = useState("");
  const [name, setName] = useState("");
  const [busy, setBusy] = useState(false);
  const [sent, setSent] = useState(false);
  const [token, setToken] = useState(() => new URLSearchParams(location.hash.split("?")[1] || "").get("email_token") || "");
  const [error, setError] = useState(() => {
    const code = new URLSearchParams(location.hash.split("?")[1] || "").get("login_error");
    return code ? MEMBER_ERRORS[code] || MEMBER_ERRORS.failed : "";
  });
  useEffect(() => {
    const onLink = () => {
      const incoming = new URLSearchParams(location.hash.split("?")[1] || "").get("email_token");
      if (incoming) { setToken(incoming); setError(""); }
    };
    window.addEventListener("hashchange", onLink);
    return () => window.removeEventListener("hashchange", onLink);
  }, []);
  // Keep the single-use token in memory, not browser history or analytics URLs.
  useEffect(() => { if (token) history.replaceState(null, "", "#/login"); }, [token]);
  const submit = async e => {
    e.preventDefault(); if (busy) return; setBusy(true); setError("");
    try { await memberRequest({ action: "request-link", email: email.trim(), name: signup ? name.trim() : undefined, mode: signup ? "signup" : "login" }); setSent(true); }
    catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };
  const confirm = async () => {
    if (busy) return; setBusy(true); setError("");
    try { const data = await memberRequest({ action: "exchange", token }); member.accept(data); continueAfterSignIn(); }
    catch (e) { setError(e.message); }
    finally { setBusy(false); }
  };
  if (!pay.loaded || pay.error) return <section className="container member-page"><PaymentStatus pay={pay} library /></section>;
  if (!pay.accounts) return <LibraryPage setPage={setPage}/>;
  return <section className="container member-page page-enter page-in">
    <div className="member-layout">
      <div className="member-story">
        <div className="eyebrow-rule">{signup ? "YOUR NEXT CHAPTER" : "WELCOME BACK"}</div>
        <h1 className="h-section">{signup ? <>Good preparation.<br/>One <em>place.</em></> : <>Your next offer<br/>starts <em>here.</em></>}</h1>
        <p>Keep your interview preparation together. Sign in to find the question banks you’ve bought and pick up where you left off.</p>
        <div className="member-benefits">
          <div><span>01</span><p><strong>Your library, on any device</strong><br/>Use the same email you used at checkout.</p></div>
          <div><span>02</span><p><strong>One less password</strong><br/>Use a connected account or a secure email link.</p></div>
          <div><span>03</span><p><strong>Start at your own pace</strong><br/>Explore free samplers before choosing a pack.</p></div>
        </div>
        <button className="member-text-link" onClick={() => setPage("shop")}>Explore question banks <span aria-hidden="true">↗</span></button>
      </div>
      <div className="member-panel card">
        <div className="member-panel-top"><span className="eyebrow">FOR BEST OFFER</span><span className="member-secure">↗ YOUR ACCOUNT</span></div>
        <h2>{token ? "Confirm your sign-in." : member.user ? "You’re signed in." : sent ? "Check your inbox." : signup ? "Create your account." : "Sign in."}</h2>
        {error && <div className="member-alert" role="alert">{error}</div>}
        {member.error && <div className="member-alert" role="alert">{member.error} <button className="member-text-link" onClick={member.refresh}>Retry</button></div>}
        {token ? <div><p className="member-sub">Continue to verify your email and open your FBO account. This link can only be used once.</p><button className="btn btn-primary member-submit" disabled={busy} onClick={confirm}>{busy ? "Verifying…" : "Confirm and sign in →"}</button>{error && <button className="btn btn-ghost member-submit" onClick={() => { setToken(""); setError(""); setPage("signup"); }}>Create a free FBO account →</button>}<button className="member-text-link" onClick={() => { setToken(""); setError(""); setPage("login"); }}>Request a new sign-in link</button></div>
        : member.user ? <div><p className="member-sub">{member.user.email}</p><button className="btn btn-primary member-submit" onClick={continueAfterSignIn}>Continue →</button><button className="member-text-link" onClick={() => setPage("settings")}>Account settings</button></div>
        : sent ? <div role="status"><div className="member-mail-mark" aria-hidden="true">✉</div><p className="member-sub">If your request can be completed, a sign-in link will arrive at <strong>{email}</strong>. Check your spam folder too.</p><p className="member-small">The link expires after 15 minutes. Open it, then confirm to sign in.</p><button className="btn btn-ghost member-submit" onClick={() => setSent(false)}>Use another email or resend</button></div>
        : <>
          <p className="member-sub">{signup ? "A free account. No subscription or card required." : "Choose the way that works for you."}</p>
          <MemberProviders providers={pay.login}/>
          {!!pay.login.length && <div className="member-divider"><span>or use your email</span></div>}
          <form onSubmit={submit} className="member-form">
            {signup && <label htmlFor="member-name">Your name <span>(optional)</span><input id="member-name" className="input" autoComplete="name" maxLength={80} placeholder="Your name" value={name} onChange={e => setName(e.target.value)}/></label>}
            <label htmlFor="member-email">Email address<input id="member-email" className="input" type="email" required autoComplete="email" maxLength={254} placeholder="you@university.ac.uk" value={email} onChange={e => setEmail(e.target.value)} disabled={busy}/></label>
            <button className="btn btn-primary member-submit" type="submit" disabled={busy || !pay.accountEmail}>{busy ? "Requesting your link…" : signup ? "Create account with email →" : "Email me a sign-in link →"}</button>
            <p className="member-small">{pay.accountEmail ? "No password to remember. We’ll verify your email before signing you in." : "Email sign-in is temporarily unavailable. Choose a connected provider or use your original purchase link."}</p>
          </form>
          <p className="member-terms">By continuing, you agree to our <button onClick={() => setPage("terms")}>Terms</button> and acknowledge our <button onClick={() => setPage("privacy")}>Privacy Policy</button>.</p>
          <div className="member-switch">{signup ? "Already have an account? " : "New to FBO? "}<button onClick={() => setPage(signup ? "login" : "signup")}>{signup ? "Sign in" : "Create an account"}</button></div>
        </>}
      </div>
    </div>
    <div className="member-help">Already bought a pack? Your original library link still works. <button onClick={() => setPage("library")}>Find my library →</button></div>
  </section>;
}
function MemberSettingsPage({ member, pay, setPage }) {
  const [name, setName] = useState(member.user ? member.user.name || "" : "");
  const [busy, setBusy] = useState(false), [message, setMessage] = useState(""), [error, setError] = useState("");
  useEffect(() => { setName(member.user ? member.user.name || "" : ""); }, [member.user && member.user.name]);
  const action = async fn => { setBusy(true); setError(""); setMessage(""); try { await fn(); } catch (e) { setError(e.message); } finally { setBusy(false); } };
  if (!member.loaded) return <section className="container member-page" role="status">Loading your account…</section>;
  if (!member.user) return <MemberAuthPage mode="login" member={member} pay={pay} setPage={setPage}/>;
  const user = member.user, linked = user.providers || [];
  return <section className="container member-page page-enter page-in">
    <div className="eyebrow-rule">YOUR ACCOUNT</div><h1 className="h-section" style={{ margin: "24px 0 16px" }}>Make yourself <em>at home.</em></h1>
    <p className="member-sub">Manage your profile and the ways you sign in.</p>
    <div className="member-settings-grid">
      <div className="card member-settings-card"><h2>Your profile</h2><p className="member-small">Verified email</p><p className="member-email-value">{user.email} <span className="chip">VERIFIED</span></p>
        <form className="member-form" onSubmit={e => { e.preventDefault(); action(async () => { const data = await memberRequest({ action: "update-profile", name: name.trim() }); member.accept(data); setMessage("Your profile has been saved."); }); }}>
          <label htmlFor="profile-name">Your name<input className="input" id="profile-name" value={name} autoComplete="name" maxLength={80} onChange={e => setName(e.target.value)}/></label>
          <button className="btn btn-primary" disabled={busy}>{busy ? "Saving…" : "Save profile"}</button>
        </form>
        {error && <p role="alert" className="member-alert">{error}</p>}{message && <p role="status">{message}</p>}
        <p className="member-small">For a change of email or a data request, contact <a href="mailto:privacy@forbestoffer.uk">privacy@forbestoffer.uk</a>.</p>
      </div>
      <div className="card member-settings-card"><h2>Sign-in & access</h2><p className="member-sub">Email links can always recover your account when email sign-in is available. Connect other methods using this same verified email.</p>
        <div className="member-linked">{linked.map(p => <span className="chip" key={p}>{MEMBER_LABELS[p] || p} · connected</span>)}</div>
        <MemberProviders providers={pay.login.filter(p => !linked.includes(p))} link/>
        <div className="member-account-actions"><button className="btn btn-ghost" onClick={() => setPage("library")}>Open my library →</button><button className="member-text-link" disabled={busy} onClick={() => action(async () => { await member.signOut(); setPage("login"); })}>Sign out on this device</button></div>
        <p className="member-small">Signing out ends this browser’s account session and removes its saved library link. Original purchase emails remain valid.</p>
      </div>
    </div>
  </section>;
}
Object.assign(window, { useMember, MemberAuthPage, MemberSettingsPage, MemberProviders });
