// ============================================================
// auth.jsx — Supabase client, session + membership hooks, and the
// gate screens (sign in, checking, no access, can't check).
//
// Login is the Focus Supabase project, so it copies Focus's
// SignIn (~/Sites/goals/app.jsx): magic link + Google.
// Who may see the site is decided in the database, not here:
// arete.is_member() is true only when the caller's CONFIRMED
// email is in arete.members, and RLS on every arete.* table uses
// it. The checks below only pick which screen to show.
// ============================================================
// read a failed sign-in's error before supabase-js starts on the URL
const AUTH_ERROR = window.AreteRoutes.takeAuthError(window.location, window.history);

const { createClient } = window.supabase;
const supaClient = createClient(window.SUPABASE_URL, window.SUPABASE_KEY, {
  auth: { persistSession: true, autoRefreshToken: true, detectSessionInUrl: true },
});
window.supaClient = supaClient;

// Sign-in redirects come back to this page, carrying the asked-for route
// as ?next=<top>/<item> (routes.js signInRedirect / takeNext). The auth
// reply itself arrives in the hash, which supabase-js reads and clears.
const authRedirect = () => window.AreteRoutes.signInRedirect(window.location);

// ---- session ----
function useSupaAuth() {
  const [session, setSession] = React.useState(null);
  const [ready, setReady] = React.useState(false);
  React.useEffect(() => {
    let alive = true;
    supaClient.auth.getSession().then(({ data }) => {
      if (!alive) return;
      setSession(data.session || null);
      setReady(true);
    });
    const { data: sub } = supaClient.auth.onAuthStateChange((_evt, sess) => {
      if (alive) setSession(sess || null);
    });
    return () => { alive = false; sub.subscription.unsubscribe(); };
  }, []);
  return { session, ready };
}

// ---- membership: "checking" | "member" | "denied" | "error" ----
// Re-checks only when the signed-in user changes (not on token refresh).
function useMembership(session) {
  const userId = session?.user?.id || null;
  // the answer is stored with the user it is for, so a new sign-in never
  // sees the last user's answer, even for one render
  const [state, setState] = React.useState({ userId: null, status: "checking" });
  const [tick, setTick] = React.useState(0);
  React.useEffect(() => {
    if (!userId) return;
    let alive = true;
    setState({ userId, status: "checking" });
    supaClient.schema("arete").rpc("is_member").then(({ data, error }) => {
      if (!alive) return;
      if (error) setState({ userId, status: "error", message: error.message });
      else setState({ userId, status: data === true ? "member" : "denied" });
    }, (e) => { if (alive) setState({ userId, status: "error", message: String(e?.message || e) }); });
    return () => { alive = false; };
  }, [userId, tick]);
  const mine = userId && state.userId === userId;
  return {
    status: mine ? state.status : "checking",
    message: mine ? state.message : undefined,
    retry: () => setTick((t) => t + 1),
  };
}

// This site only (Focus stays signed in); always clears the stored login.
function signOut() {
  return window.AreteSignOut.signOutSafely(supaClient, {
    supabaseUrl: window.SUPABASE_URL,
    getStorage: () => window.localStorage,
    reload: () => window.location.reload(),
  });
}

// ---- shared bits ----
function Brand() {
  return (
    <span className="brand">
      <span className="brand-mark" aria-hidden="true">A</span>
      <span>Arete<small>The Charlotte Social</small></span>
    </span>
  );
}
function GateIcon({ name }) {
  return <span className="gate-ic" dangerouslySetInnerHTML={{ __html:
    `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${window.AreteIcons[name]}</svg>` }} />;
}

// ---- sign in (magic link + Google), copied from Focus ----
function SignIn() {
  const [email, setEmail] = React.useState("");
  const [busy, setBusy] = React.useState(false);
  const [sent, setSent] = React.useState(false);
  const [err, setErr] = React.useState(AUTH_ERROR
    ? "That sign-in link did not work (" + AUTH_ERROR + "). Links expire after one use. Try again." : null);

  async function send(e) {
    e.preventDefault();
    if (!email || busy) return;
    setBusy(true); setErr(null);
    try {
      const { error } = await supaClient.auth.signInWithOtp({
        email: email.trim(),
        options: { emailRedirectTo: authRedirect(), shouldCreateUser: false },
      });
      if (error) throw error;
      setSent(true);
    } catch (e) {
      // shouldCreateUser:false — the link only goes to accounts that already exist
      setErr(/signups? not allowed|not found/i.test(e.message || "")
        ? "This email has no account yet. Use Continue with Google, or ask Ryan to invite you."
        : (e.message || "Could not send the link. Try again."));
    } finally { setBusy(false); }
  }

  async function google() {
    if (busy) return;
    setBusy(true); setErr(null);
    try {
      const { error } = await supaClient.auth.signInWithOAuth({
        provider: "google",
        options: { redirectTo: authRedirect() },
      });
      if (error) throw error;
      // the OAuth page takes over from here
    } catch (e) {
      setErr(e.message || "Could not start Google sign-in.");
      setBusy(false);
    }
  }

  return (
    <main className="gate">
      <div className="gate-card">
        <Brand />
        <h1>Sign in</h1>
        {sent ? (
          <>
            <p>Check your inbox at <b>{email}</b> for a sign-in link.</p>
            <button className="linkbtn" onClick={() => setSent(false)}>Use a different email</button>
          </>
        ) : (
          <>
            <p>Use the same account as Focus.</p>
            <button className="btn ghost" onClick={google} disabled={busy}>
              <svg width="18" height="18" viewBox="0 0 18 18" aria-hidden="true">
                <path fill="#4285F4" d="M17.64 9.2c0-.637-.057-1.251-.164-1.84H9v3.481h4.844a4.14 4.14 0 0 1-1.796 2.716v2.259h2.908c1.702-1.567 2.684-3.875 2.684-6.615z"/>
                <path fill="#34A853" d="M9 18c2.43 0 4.467-.806 5.956-2.184l-2.908-2.259c-.806.54-1.837.86-3.048.86-2.344 0-4.328-1.584-5.036-3.711H.957v2.332A8.997 8.997 0 0 0 9 18z"/>
                <path fill="#FBBC05" d="M3.964 10.706A5.41 5.41 0 0 1 3.682 9c0-.593.102-1.17.282-1.706V4.962H.957A8.997 8.997 0 0 0 0 9c0 1.452.348 2.827.957 4.038l3.007-2.332z"/>
                <path fill="#EA4335" d="M9 3.58c1.321 0 2.508.454 3.44 1.345l2.582-2.58C13.463.891 11.426 0 9 0A8.997 8.997 0 0 0 .957 4.962L3.964 7.294C4.672 5.167 6.656 3.58 9 3.58z"/>
              </svg>
              Continue with Google
            </button>
            <div className="divider">or</div>
            <form onSubmit={send} className="field">
              <label htmlFor="signin-email">Email</label>
              <input id="signin-email" type="email" autoComplete="email" required value={email}
                placeholder="you@example.com" onChange={(e) => setEmail(e.target.value)} />
              <button className="btn primary" style={{ marginTop: 10 }} disabled={busy || !email}>
                {busy ? "Sending…" : "Email me a sign-in link"}
              </button>
              {err && <p className="err" role="alert">{err}</p>}
            </form>
          </>
        )}
      </div>
    </main>
  );
}

function Checking() {
  return <div className="boot" aria-live="polite">Checking access…</div>;
}

// Signed in, but this email is not in arete.members.
function NoAccess({ email }) {
  return (
    <main className="gate">
      <div className="gate-card">
        <Brand />
        <GateIcon name="lock" />
        <h1>No access</h1>
        <p>You are signed in as <b>{email || "an unknown account"}</b>. This account is not on the Arete list.</p>
        <p>Ask Ryan to add it, or sign in with a different account.</p>
        <button className="btn ghost" onClick={signOut}>Sign out</button>
      </div>
    </main>
  );
}

// The membership check itself failed (network, or the database not set up yet).
function AccessError({ message, onRetry }) {
  return (
    <main className="gate">
      <div className="gate-card">
        <Brand />
        <h1>Can't check access</h1>
        <p>The site could not reach the access list. Try again in a minute.</p>
        {message && <p className="err">{message}</p>}
        <button className="btn ghost" onClick={onRetry}>Try again</button>
        <button className="linkbtn" onClick={signOut}>Sign out</button>
      </div>
    </main>
  );
}

Object.assign(window, { useSupaAuth, useMembership, signOut,
  SignIn, Checking, NoAccess, AccessError, Brand });
