/* Auth screen — sign up / log in.
 *
 * Real accounts: credentials are checked by the serverless API in /api/ against
 * a Postgres users table (hashed passwords), and the session is an httpOnly,
 * signed cookie — so logging in works across devices. localStorage only caches
 * the current user's display info (name/email/onboarded) so the rest of the app
 * can read "who am I" synchronously; it is NOT the credential.
 *
 * Graceful degradation: if the API is unreachable or not configured yet (no
 * DATABASE_URL / SESSION_SECRET), every call falls back to a local-only,
 * device-scoped store so the site keeps working — the original prototype
 * behavior — until the backend is provisioned.
 */

const { useState: useAuthState } = React;

const USERS_KEY = "w2r4_users_v1";
const SESSION_KEY = "w2r4_session_v1";

// Local fallback user store (used only when the server is unreachable).
function loadUsers() {
  try {return JSON.parse(localStorage.getItem(USERS_KEY) || "{}");}
  catch (_) {return {};}
}
function saveUsers(u) {localStorage.setItem(USERS_KEY, JSON.stringify(u));}
// Synchronous display-info cache of the current user (mirrors the server).
function saveSession(s) {localStorage.setItem(SESSION_KEY, JSON.stringify(s));}
function loadSession() {
  try {return JSON.parse(localStorage.getItem(SESSION_KEY) || "null");}
  catch (_) {return null;}
}
function clearSession() {localStorage.removeItem(SESSION_KEY);}

/* ── Server calls ────────────────────────────────────────────────────────
 * Each returns either { ok, status, data } or { unavailable: true } when the
 * backend can't be reached / isn't configured (HTTP 503 or a network error),
 * which signals callers to fall back to local mode. */
async function apiCall(path, opts) {
  opts = opts || {};
  try {
    const r = await fetch(path, {
      method: opts.method || "GET",
      headers: opts.body ? { "Content-Type": "application/json" } : undefined,
      body: opts.body ? JSON.stringify(opts.body) : undefined,
      credentials: "same-origin",
      keepalive: !!opts.keepalive,
    });
    if (r.status === 503) return { unavailable: true };
    // A non-JSON response means the API isn't actually there (e.g. a static
    // host serving index.html for /api/* because functions aren't deployed).
    // Treat it as unavailable so callers fall back to local mode.
    const ct = (r.headers.get && r.headers.get("content-type")) || "";
    if (!ct.includes("application/json")) return { unavailable: true };
    let data = {};
    try {data = (await r.json()) || {};} catch (_) {return { unavailable: true };}
    return { ok: r.ok, status: r.status, data };
  } catch (_) {
    return { unavailable: true };
  }
}

async function serverSignup(body) {return apiCall("/api/auth/signup", { method: "POST", body });}
async function serverLogin(body)  {return apiCall("/api/auth/login",  { method: "POST", body });}
async function serverLogout()     {return apiCall("/api/auth/logout", { method: "POST" });}

// Boot-time reconcile with the server. Never throws. Returns the resolved
// session (or null). Also hydrates saved prefs into localStorage so the rest
// of the app — which reads prefs synchronously — sees the server's copy.
async function hydrate() {
  const res = await apiCall("/api/auth/me");
  if (res.unavailable) return loadSession();      // keep local cache untouched
  const user = res.data && res.data.user;
  if (user) {
    saveSession({ email: user.email, name: user.name, onboarded: !!user.onboarded });
    if (res.data.prefs && window.W2R4TeamPrefs) window.W2R4TeamPrefs.applyServerPrefs(res.data.prefs);
    return loadSession();
  }
  // Server says nobody is logged in: drop a stale real session (expired, or a
  // different device), but keep guest sessions (deliberately local-only).
  const cur = loadSession();
  if (cur && !cur.isGuest) clearSession();
  return loadSession();
}

window.W2R4_Auth = {
  loadSession, saveSession, clearSession,
  loadUsers, saveUsers,
  serverSignup, serverLogin, serverLogout, hydrate,
};

function Field({ label, type = "text", value, onChange, placeholder, hint, error, autoFocus }) {
  return (
    <label className="auth-field">
      <span className="auth-field-label">{label}</span>
      <input
        type={type}
        value={value}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        autoFocus={autoFocus}
        className={"auth-input" + (error ? " err" : "")} />
      
      {error ?
      <span className="auth-hint err">{error}</span> :
      hint ? <span className="auth-hint">{hint}</span> : null}
    </label>);

}

function Auth({ onAuthed }) {
  const [mode, setMode] = useAuthState("signup"); // "signup" | "login"
  const [name, setName] = useAuthState("");
  const [email, setEmail] = useAuthState("");
  const [pw, setPw] = useAuthState("");
  const [errors, setErrors] = useAuthState({});
  const [busy, setBusy] = useAuthState(false);

  const switchMode = (m) => {setMode(m);setErrors({});};

  // Local-only fallback (server unreachable / not configured yet): preserves
  // the original device-scoped behavior so the app still works before the DB
  // is provisioned.
  const localFallback = (key) => {
    const users = loadUsers();
    if (mode === "signup") {
      if (users[key]) {
        setErrors({ email: "An account already exists for this email. Try logging in." });
        setBusy(false);
        return;
      }
      users[key] = { email: key, name: name.trim(), pw, createdAt: Date.now(), onboarded: false };
      saveUsers(users);
      const u = { email: key, name: name.trim(), onboarded: false };
      saveSession(u);
      setBusy(false);
      onAuthed(u);
    } else {
      const u = users[key];
      if (!u || u.pw !== pw) {
        setErrors({ pw: "Email or password doesn't match." });
        setBusy(false);
        return;
      }
      const sess = { email: u.email, name: u.name, onboarded: !!u.onboarded };
      saveSession(sess);
      setBusy(false);
      onAuthed(sess);
    }
  };

  const submit = async (e) => {
    e && e.preventDefault();
    const err = {};
    if (mode === "signup" && !name.trim()) err.name = "Tell us what to call you";
    if (!/^\S+@\S+\.\S+$/.test(email)) err.email = "That doesn't look like an email";
    if (pw.length < 6) err.pw = "At least 6 characters";

    if (Object.keys(err).length) {setErrors(err);return;}
    setBusy(true);

    const key = email.trim().toLowerCase();
    const res = mode === "signup" ?
      await window.W2R4_Auth.serverSignup({ name: name.trim(), email: key, password: pw }) :
      await window.W2R4_Auth.serverLogin({ email: key, password: pw });

    if (res.unavailable) {
      localFallback(key);
      return;
    }
    if (res.ok && res.data.user) {
      const u = {
        email: res.data.user.email,
        name: res.data.user.name,
        onboarded: !!res.data.user.onboarded,
      };
      saveSession(u);
      if (res.data.prefs && window.W2R4TeamPrefs) window.W2R4TeamPrefs.applyServerPrefs(res.data.prefs);
      setBusy(false);
      onAuthed(u);
      return;
    }
    // Map the server's error code to the relevant field.
    const code = res.data && res.data.error;
    if (mode === "signup" && (code === "exists" || res.status === 409)) {
      setErrors({ email: "An account already exists for this email. Try logging in." });
    } else if (mode === "login" && (code === "invalid" || res.status === 401)) {
      setErrors({ pw: "Email or password doesn't match." });
    } else if (code === "email") {
      setErrors({ email: "That doesn't look like an email" });
    } else if (code === "password") {
      setErrors({ pw: "At least 6 characters" });
    } else if (code === "name") {
      setErrors({ name: "Tell us what to call you" });
    } else {
      setErrors({ pw: "Something went wrong. Please try again." });
    }
    setBusy(false);
  };

  const useGuest = () => {
    const session = { email: null, name: "Guest", onboarded: false, isGuest: true };
    saveSession(session);
    onAuthed(session);
  };

  const isSignup = mode === "signup";

  return (
    <div className="auth-shell">
      <div className="auth-side">
        <div className="auth-brand">
          <span className="brand-word">Who2Root4<sup className="w2r4-tm">TM</sup></span>
        </div>
        <div className="auth-pitch">
          <div className="onb-eyebrow">FOR FANS OF ANY TEAM</div>
          <h1 className="auth-pitch-title">
            Every week,<br />a reason to care<br />about every game.
          </h1>
          <p className="auth-pitch-sub">Pick your favorite team and see which games to watch — ranked by playoff implications.


          </p>
          <ul className="auth-bullets">
            <li><span className="dot"></span> Ranked rooting recommendations, every week</li>
            <li><span className="dot"></span> Division &amp; conference impact, scored</li>
            <li><span className="dot"></span> A schedule that knows what you care about</li>
          </ul>
        </div>
        <div className="auth-foot mono">POWERED BY AI & ANALYTICS</div>
      </div>

      <div className="auth-form-wrap">
        <form className="auth-form" onSubmit={submit}>
          <div className="auth-tabs" role="tablist">
            <button type="button" role="tab" aria-selected={isSignup}
            className={"auth-tab" + (isSignup ? " active" : "")}
            onClick={() => switchMode("signup")}>
              Sign up
            </button>
            <button type="button" role="tab" aria-selected={!isSignup}
            className={"auth-tab" + (!isSignup ? " active" : "")}
            onClick={() => switchMode("login")}>
              Log in
            </button>
            <div className="auth-tab-thumb" style={{ left: isSignup ? "4px" : "calc(50% + 0px)" }}></div>
          </div>

          <h2 className="auth-form-title">
            {isSignup ? "Create your account" : "Welcome back"}
          </h2>
          <p className="auth-form-sub">
            {isSignup ?
            "Save your team and see it on any device." :
            "Pick up where you left off — on any device."}
          </p>

          {isSignup &&
          <Field label="Name" value={name} onChange={setName}
          placeholder="Your name" error={errors.name} autoFocus />
          }
          <Field label="Email" type="email" value={email} onChange={setEmail}
          placeholder="you@example.com" error={errors.email}
          autoFocus={!isSignup} />
          <Field label="Password" type="password" value={pw} onChange={setPw}
          placeholder={isSignup ? "At least 6 characters" : "Your password"}
          error={errors.pw}
          hint={isSignup ? "At least 6 characters." : null} />

          <button type="submit" className="btn primary auth-submit" disabled={busy}>
            {busy ?
            isSignup ? "Creating account…" : "Logging in…" :
            isSignup ? "Create account" : "Log in"}
            <span style={{ fontSize: 11, opacity: 0.9 }}>→</span>
          </button>

          <div className="auth-divider"><span>or</span></div>

          <button type="button" className="btn ghost auth-demo" onClick={useGuest}>
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor"
            strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"
            style={{ marginRight: 2 }}>
              <path d="M5 12h14M13 5l7 7-7 7" />
            </svg>
            Continue as guest
          </button>

          <p className="auth-fineprint">
            Guests pick a team and use everything — sign up later to save it across devices.
          </p>
        </form>
      </div>
    </div>);

}

window.Auth = Auth;