// auth.jsx — wired to real AWS Cognito
// Uses amazon-cognito-identity-js loaded from CDN in index.html
// Flow: signup → verify email → signin → JWT stored in localStorage

// ── Cognito config ────────────────────────────────────────────────────────
const COGNITO_USER_POOL_ID  = 'eu-central-1_IDzeVSllu';
const COGNITO_CLIENT_ID     = '7nffjheavp985k7b4bgug45jf4';
const COGNITO_REGION        = 'eu-central-1';

// ── Token storage helpers ─────────────────────────────────────────────────
// Tokens are stored in localStorage under these keys.
// The API_BASE fetch calls in upload.jsx read FOSSYL_ID_TOKEN automatically.
const TOKEN_KEYS = {
  idToken:      'fossyl_id_token',
  accessToken:  'fossyl_access_token',
  refreshToken: 'fossyl_refresh_token',
  email:        'fossyl_email',
  expiry:       'fossyl_token_expiry',
};

function saveTokens(authResult, email) {
  localStorage.setItem(TOKEN_KEYS.idToken,      authResult.idToken.jwtToken);
  localStorage.setItem(TOKEN_KEYS.accessToken,  authResult.accessToken.jwtToken);
  localStorage.setItem(TOKEN_KEYS.refreshToken, authResult.refreshToken.token);
  localStorage.setItem(TOKEN_KEYS.email,        email);
  localStorage.setItem(TOKEN_KEYS.expiry, String(Date.now() + 55 * 60 * 1000));
}

function clearTokens() {
  Object.values(TOKEN_KEYS).forEach(k => localStorage.removeItem(k));
  // Remove Cognito auth tokens to prevent focus-based checkToken from re-authing.
  // Intentionally KEEP: LastAuthUser, device keys, fossyl_cognito_sub_* —
  // all needed so getCognitoUser resolves the UUID on the next sign-in.
  const _cp = `CognitoIdentityServiceProvider.${COGNITO_CLIENT_ID}`;
  const _lu = localStorage.getItem(`${_cp}.LastAuthUser`);
  if (_lu) {
    ['idToken', 'accessToken', 'refreshToken'].forEach(k =>
      localStorage.removeItem(`${_cp}.${_lu}.${k}`)
    );
    // LastAuthUser intentionally preserved
  }
}

function getIdToken() {
  return localStorage.getItem(TOKEN_KEYS.idToken) || '';
}

// Expose globally so upload.jsx can read it without prop drilling
window.getIdToken = getIdToken;

// ── Device trust — skip TOTP on recognized devices, re-verify every 30 days ──
//
// Mechanism: Cognito's native device tracking (pool DeviceConfiguration already
// set: ChallengeRequiredOnNewDevice=false, DeviceOnlyRememberedOnUserPrompt=true).
//
//   • After successful TOTP: call setDeviceStatusRemembered() so Cognito marks
//     this browser as trusted.  On success, store a timestamp locally.
//   • On next login: Cognito's authenticateUser detects the stored device key and
//     skips the SOFTWARE_TOKEN_MFA challenge → onSuccess fires without totpRequired.
//   • 30-day enforcement: before each login we check the local timestamp.  If it
//     has expired we delete the Cognito device keys from localStorage, so the pool
//     treats this browser as an unrecognized device and fires totpRequired again.
//   • The timestamp is ONLY stored after setDeviceStatusRemembered confirms
//     Cognito actually remembered the device — never optimistically.
// ─────────────────────────────────────────────────────────────────────────────
const DEVICE_TRUST_MS = 30 * 24 * 60 * 60 * 1000;

function _deviceTrustKey(email) {
  return `fossyl_device_trust_${email.toLowerCase()}`;
}

function _isDeviceTrusted(email) {
  const ts = Number(localStorage.getItem(_deviceTrustKey(email))) || 0;
  return ts > 0 && (Date.now() - ts) < DEVICE_TRUST_MS;
}

function _markDeviceTrusted(cognitoUser, email) {
  console.log('[fossyl-auth] _markDeviceTrusted: username=', cognitoUser.username,
    '| deviceKey=', cognitoUser.deviceKey, '| session valid=', !!cognitoUser.signInUserSession);
  cognitoUser.setDeviceStatusRemembered({
    onSuccess: () => {
      localStorage.setItem(_deviceTrustKey(email), String(Date.now()));
      // Cognito stores device keys under the user's sub UUID, NOT the email.
      // Cache the UUID so getCognitoUser() can use it on every subsequent login.
      localStorage.setItem(`fossyl_cognito_sub_${email.toLowerCase()}`, cognitoUser.username);
      console.log('[fossyl-auth] setDeviceStatusRemembered SUCCESS — sub cached as', cognitoUser.username);
    },
    onFailure: (err) => {
      console.error('[fossyl-auth] setDeviceStatusRemembered FAILED:', err);
    },
  });
}

function _expireDeviceTrust(email) {
  localStorage.removeItem(_deviceTrustKey(email));
  const clientPrefix = `CognitoIdentityServiceProvider.${COGNITO_CLIENT_ID}`;
  // Use cached sub UUID — device keys live under UUID path, not email path
  const sub        = localStorage.getItem(`fossyl_cognito_sub_${email.toLowerCase()}`);
  const storedUser = sub || localStorage.getItem(`${clientPrefix}.LastAuthUser`) || email;
  ['deviceKey', 'deviceGroupKey', 'randomPasswordKey'].forEach(k =>
    localStorage.removeItem(`${clientPrefix}.${storedUser}.${k}`)
  );
  console.log('[fossyl-auth] _expireDeviceTrust: cleared device keys for', storedUser);
}

// ── Cognito SDK helpers ───────────────────────────────────────────────────
function getCognitoUserPool() {
  const { CognitoUserPool } = window.AmazonCognitoIdentity;
  return new CognitoUserPool({
    UserPoolId: COGNITO_USER_POOL_ID,
    ClientId:   COGNITO_CLIENT_ID,
  });
}

function getCognitoUser(email) {
  const { CognitoUser } = window.AmazonCognitoIdentity;
  // Cognito stores device keys under the user's sub UUID (not the email address).
  // If we have a cached UUID for this email, use it so authenticateUser finds
  // the device key in localStorage and includes it in the auth request.
  const sub = localStorage.getItem(`fossyl_cognito_sub_${email.toLowerCase()}`);
  return new CognitoUser({
    Username: sub || email,
    Pool:     getCognitoUserPool(),
  });
}

// Sign up — returns Promise<void>
// On success Cognito sends a verification email automatically.
function cognitoSignUp(email, password, name, organisation) {
  const { CognitoUserAttribute } = window.AmazonCognitoIdentity;
  const pool = getCognitoUserPool();
  const attributes = [
    new CognitoUserAttribute({ Name: 'email',              Value: email }),
    new CognitoUserAttribute({ Name: 'name',               Value: name || email }),
    new CognitoUserAttribute({ Name: 'custom:organisation', Value: organisation || '' }),
  ];
  return new Promise((resolve, reject) => {
    pool.signUp(email, password, attributes, null, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

// Confirm signup with the 6-digit code from email
function cognitoConfirm(email, code) {
  const user = getCognitoUser(email);
  return new Promise((resolve, reject) => {
    user.confirmRegistration(code, true, (err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

// Resend verification code
function cognitoResend(email) {
  const user = getCognitoUser(email);
  return new Promise((resolve, reject) => {
    user.resendConfirmationCode((err, result) => {
      if (err) reject(err);
      else resolve(result);
    });
  });
}

// Sign in — resolves {result, user} on success.
// When the device is trusted Cognito's authenticateUser skips totpRequired entirely
// and resolves directly via onSuccess.  When it isn't, totpRequired fires and the
// caller is responsible for collecting the code and calling cognitoSubmitTotp.
function cognitoSignIn(email, password, onTotpRequired) {
  const { AuthenticationDetails } = window.AmazonCognitoIdentity;
  const user    = getCognitoUser(email);
  const details = new AuthenticationDetails({ Username: email, Password: password });
  return new Promise((resolve, reject) => {
    user.authenticateUser(details, {
      onSuccess: (result) => {
        console.log('[fossyl-auth] authenticateUser onSuccess — TOTP was NOT required (device trusted by Cognito)');
        resolve({ result, user });
      },
      onFailure: reject,
      newPasswordRequired: () => reject(new Error('Password reset required — contact support.')),
      totpRequired: () => {
        console.log('[fossyl-auth] authenticateUser totpRequired — Cognito does not recognise this device');
        if (onTotpRequired) onTotpRequired(user);
        else reject(new Error('Two-factor authentication required.'));
      },
    });
  });
}

// Submit TOTP code — resolves {result, user} so caller can call setDeviceStatusRemembered.
function cognitoSubmitTotp(user, code) {
  return new Promise((resolve, reject) => {
    user.sendMFACode(code, {
      onSuccess: (result) => resolve({ result, user }),
      onFailure: reject,
    }, 'SOFTWARE_TOKEN_MFA');
  });
}

// Forgot password — sends reset code
function cognitoForgotPassword(email) {
  const user = getCognitoUser(email);
  return new Promise((resolve, reject) => {
    user.forgotPassword({
      onSuccess: resolve,
      onFailure: reject,
    });
  });
}

// Confirm forgot password with code + new password
function cognitoConfirmNewPassword(email, code, newPassword) {
  const user = getCognitoUser(email);
  return new Promise((resolve, reject) => {
    user.confirmPassword(code, newPassword, {
      onSuccess: resolve,
      onFailure: reject,
    });
  });
}

// ── AuthPage component ────────────────────────────────────────────────────
// Stages: 'form' | 'verify' | 'forgot' | 'forgot_confirm'

function AuthPage({ mode = 'signin' }) {
  const { go }              = useNav();
  const { signIn: ctxSignIn, signUp: ctxSignUp, paid } = useAuth();
  const { toast }           = useToast();

  const [tab,          setTab]          = useState(mode);  // 'signin' | 'signup'
  const [stage,        setStage]        = useState('form'); // 'form' | 'verify' | 'forgot' | 'forgot_confirm'
  const [loading,      setLoading]      = useState(false);
  const [pendingEmail, setPendingEmail] = useState('');
  const [termsAccepted, setTermsAccepted] = useState(false);
  const [showTerms,     setShowTerms]     = useState(false);

  // Form field refs (uncontrolled — preserves design inputs exactly)
  const nameRef     = useRef();
  const orgRef      = useRef();
  const emailRef    = useRef();
  const passwordRef = useRef();
  const codeRef     = useRef();
  const newPwRef    = useRef();

  // TOTP challenge state (set when Cognito requires MFA after password auth)
  const [totpUser, setTotpUser] = useState(null);
  const totpRef = useRef();

  const switchTab = (t) => { setTab(t); setStage('form'); };

  // ── Sign in ──────────────────────────────────────────────────────────
  const handleSignIn = async (e) => {
    e && e.preventDefault();
    const email    = emailRef.current?.value?.trim();
    const password = passwordRef.current?.value;
    if (!email || !password) { toast('Email and password required', { tone: 'error' }); return; }

    const trusted = _isDeviceTrusted(email);
    const _sub = localStorage.getItem(`fossyl_cognito_sub_${email.toLowerCase()}`);
    const _cp  = `CognitoIdentityServiceProvider.${COGNITO_CLIENT_ID}`;
    const _lu  = _sub || localStorage.getItem(`${_cp}.LastAuthUser`) || email;
    console.log('[fossyl-auth] handleSignIn: trusted=', trusted,
      '| sub=', _sub, '| deviceKey=', localStorage.getItem(`${_cp}.${_lu}.deviceKey`));
    if (!trusted) _expireDeviceTrust(email);

    setLoading(true);
    try {
      const auth = await cognitoSignIn(email, password, (user) => {
        setPendingEmail(email);
        setTotpUser(user);
        setStage('totp');
        setLoading(false);
      });
      if (!auth) return; // TOTP challenge — loading cleared above
      // Auth succeeded without MFA (Cognito recognized a trusted device)
      saveTokens(auth.result, email);
      ctxSignIn();
      go(paid ? 'upload' : 'pricing');
    } catch (err) {
      if (err.code === 'UserNotConfirmedException') {
        setPendingEmail(email);
        setStage('verify');
        toast('Please verify your email first', { tone: 'error' });
      } else {
        toast(err.message || 'Sign in failed', { tone: 'error' });
      }
    } finally {
      setLoading(false);
    }
  };

  // ── Sign up ──────────────────────────────────────────────────────────
  const handleSignUp = async (e) => {
    e && e.preventDefault();
    const email    = emailRef.current?.value?.trim();
    const password = passwordRef.current?.value;
    const name     = nameRef.current?.value?.trim();
    const org      = orgRef.current?.value?.trim();
    if (!email || !password) { toast('Email and password required', { tone: 'error' }); return; }
    if (password.length < 8)  { toast('Password must be at least 8 characters', { tone: 'error' }); return; }
    if (!termsAccepted)       { setShowTerms(true); return; }

    setLoading(true);
    try {
      await cognitoSignUp(email, password, name, org);
      setPendingEmail(email);
      setStage('verify');
      toast('Verification code sent to ' + email, { tone: 'success' });
    } catch (err) {
      if (err.code === 'UsernameExistsException') {
        toast('Account already exists — sign in instead', { tone: 'error' });
        switchTab('signin');
      } else {
        toast(err.message || 'Sign up failed', { tone: 'error' });
      }
    } finally {
      setLoading(false);
    }
  };

  // ── Verify email ─────────────────────────────────────────────────────
  const handleVerify = async (e) => {
    e && e.preventDefault();
    const code = codeRef.current?.value?.trim();
    if (!code) { toast('Enter the 6-digit code', { tone: 'error' }); return; }

    setLoading(true);
    try {
      await cognitoConfirm(pendingEmail, code);
      toast('Email verified — signing you in…', { tone: 'success' });
      // Auto sign in after verification if we have the password
      const password = passwordRef.current?.value;
      if (password) {
        const auth = await cognitoSignIn(pendingEmail, password);
        saveTokens(auth.result, pendingEmail);
        ctxSignUp();
        go('pricing');
      } else {
        setStage('form');
        setTab('signin');
      }
    } catch (err) {
      toast(err.message || 'Verification failed', { tone: 'error' });
    } finally {
      setLoading(false);
    }
  };

  const handleResend = async () => {
    try {
      await cognitoResend(pendingEmail);
      toast('New code sent to ' + pendingEmail, { tone: 'success' });
    } catch (err) {
      toast(err.message || 'Could not resend code', { tone: 'error' });
    }
  };

  // ── Forgot password ───────────────────────────────────────────────────
  const handleForgot = async () => {
    const email = emailRef.current?.value?.trim();
    if (!email) { toast('Enter your email first', { tone: 'error' }); return; }
    setLoading(true);
    try {
      await cognitoForgotPassword(email);
      setPendingEmail(email);
      setStage('forgot_confirm');
      toast('Reset code sent to ' + email, { tone: 'success' });
    } catch (err) {
      toast(err.message || 'Could not send reset code', { tone: 'error' });
    } finally {
      setLoading(false);
    }
  };

  const handleForgotConfirm = async (e) => {
    e && e.preventDefault();
    const code     = codeRef.current?.value?.trim();
    const newPw    = newPwRef.current?.value;
    if (!code || !newPw) { toast('Code and new password required', { tone: 'error' }); return; }
    setLoading(true);
    try {
      await cognitoConfirmNewPassword(pendingEmail, code, newPw);
      toast('Password updated — sign in now', { tone: 'success' });
      setStage('form');
      setTab('signin');
    } catch (err) {
      toast(err.message || 'Reset failed', { tone: 'error' });
    } finally {
      setLoading(false);
    }
  };

  // ── TOTP challenge ────────────────────────────────────────────────────
  const handleTotpConfirm = async (e) => {
    e && e.preventDefault();
    const code = totpRef.current?.value?.trim();
    if (!code || code.length !== 6) { toast('Enter the 6-digit code from your app', { tone: 'error' }); return; }
    setLoading(true);
    try {
      const auth = await cognitoSubmitTotp(totpUser, code);
      saveTokens(auth.result, pendingEmail);
      // Mark this device as trusted for the next 30 days.
      // Future logins from this browser will skip TOTP until the window expires.
      _markDeviceTrusted(auth.user, pendingEmail);
      ctxSignIn();
      go(paid ? 'upload' : 'pricing');
    } catch (err) {
      toast(err.message || 'Verification failed', { tone: 'error' });
    } finally {
      setLoading(false);
    }
  };

  // ── Layout — left brand panel is always the same ──────────────────────
  return (
    <div style={{ minHeight: '100vh', display: 'grid', gridTemplateColumns: '1fr 1fr', background: 'var(--bg)' }}>

      {/* Left: brand panel */}
      <div style={{ padding: '48px 56px', borderRight: '1px solid var(--line)', background: 'var(--bg-1)', position: 'relative', overflow: 'hidden' }}>
        <div className="row jc-b ai-c">
          <a onClick={() => go('landing')} style={{ cursor: 'pointer' }}><Logo size={22}/></a>
          <span className="mono" style={{ fontSize: 11, color: 'var(--muted)' }}>
            getfossyl.dev / {tab === 'signin' ? 'sign in' : stage === 'verify' ? 'verify' : 'sign up'}
          </span>
        </div>
        <div style={{ marginTop: 96, maxWidth: 480 }}>
          <span className="caps">Specimen access</span>
          <h1 className="display" style={{ fontSize: 52, fontWeight: 400, letterSpacing: '-0.02em', margin: '20px 0 24px', lineHeight: 1.02 }}>
            {stage === 'verify'         ? 'Check your inbox.'       :
             stage === 'forgot_confirm' ? 'Set a new password.'     :
             stage === 'totp'           ? 'One more step.'          :
             tab   === 'signin'
               ? <span>Foss<span style={{ color: 'var(--bone)' }}>y</span>l.</span>
               : 'Begin the excavation.'}
          </h1>
          <p style={{ fontSize: 15, lineHeight: 1.55, color: 'var(--ink-dim)', margin: 0 }}>
            {stage === 'verify'
              ? `A 6-digit code was sent to ${pendingEmail}. Enter it to activate your account.`
              : 'Your reports stay in your account for 30 days. After that they are purged — Fossyl does not retain uploaded source beyond a scan\'s lifetime.'}
          </p>
        </div>

      </div>

      {showTerms && (
        <TermsModal
          onAccept={() => { setTermsAccepted(true); setShowTerms(false); }}
          onDecline={() => { setTermsAccepted(false); setShowTerms(false); }}
        />
      )}

      {/* Right: form panel */}
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '48px' }}>
        <div style={{ width: 380 }}>

          {/* ── Stage: TOTP challenge ───────────────────────────────── */}
          {stage === 'totp' && (
            <form onSubmit={handleTotpConfirm} className="col g-14">
              <div className="col g-8">
                <span className="caps">Two-factor authentication</span>
                <p style={{ fontSize: 13, color: 'var(--ink-dim)', margin: 0 }}>
                  Enter the 6-digit code from your authenticator app.
                </p>
              </div>
              <div>
                <span className="label">Authenticator code</span>
                <input ref={totpRef} className="input mono" placeholder="000000" maxLength={6}
                  style={{ letterSpacing: '0.3em', fontSize: 20, textAlign: 'center' }} autoFocus
                  onChange={e => { e.target.value = e.target.value.replace(/\D/g, ''); }}/>
              </div>
              <button type="submit" className="btn btn-primary btn-lg" disabled={loading}
                style={{ justifyContent: 'center', width: '100%' }}>
                {loading ? 'Verifying…' : 'Verify →'}
              </button>
              <a className="mono" style={{ fontSize: 11, color: 'var(--muted)', cursor: 'pointer', textAlign: 'center' }}
                onClick={() => { setStage('form'); setTotpUser(null); }}>← Back to sign in</a>
            </form>
          )}

          {/* ── Stage: verify email ─────────────────────────────────── */}
          {stage === 'verify' && (
            <form onSubmit={handleVerify} className="col g-14">
              <div className="col g-8">
                <span className="caps">Verify email</span>
                <p style={{ fontSize: 13, color: 'var(--ink-dim)', margin: 0 }}>
                  Enter the 6-digit code sent to <span className="mono" style={{ color: 'var(--bone)' }}>{pendingEmail}</span>
                </p>
              </div>
              <div>
                <span className="label">Verification code</span>
                <input ref={codeRef} className="input mono" placeholder="000000" maxLength={6}
                  style={{ letterSpacing: '0.3em', fontSize: 20, textAlign: 'center' }} autoFocus/>
              </div>
              <button type="submit" className="btn btn-primary btn-lg" disabled={loading}
                style={{ justifyContent: 'center', width: '100%' }}>
                {loading ? 'Verifying…' : 'Confirm account →'}
              </button>
              <div className="row jc-b ai-c">
                <a className="mono" style={{ fontSize: 11, color: 'var(--muted)', cursor: 'pointer' }}
                  onClick={handleResend}>Resend code</a>
                <a className="mono" style={{ fontSize: 11, color: 'var(--muted)', cursor: 'pointer' }}
                  onClick={() => setStage('form')}>← Back</a>
              </div>
            </form>
          )}

          {/* ── Stage: forgot password confirm ──────────────────────── */}
          {stage === 'forgot_confirm' && (
            <form onSubmit={handleForgotConfirm} className="col g-14">
              <div className="col g-8">
                <span className="caps">Reset password</span>
                <p style={{ fontSize: 13, color: 'var(--ink-dim)', margin: 0 }}>
                  Enter the code sent to <span className="mono" style={{ color: 'var(--bone)' }}>{pendingEmail}</span> and your new password.
                </p>
              </div>
              <div>
                <span className="label">Reset code</span>
                <input ref={codeRef} className="input mono" placeholder="000000" maxLength={6}
                  style={{ letterSpacing: '0.3em', fontSize: 20, textAlign: 'center' }} autoFocus/>
              </div>
              <div>
                <span className="label">New password</span>
                <input ref={newPwRef} className="input mono" type="password" placeholder="min. 8 characters"/>
              </div>
              <button type="submit" className="btn btn-primary btn-lg" disabled={loading}
                style={{ justifyContent: 'center', width: '100%' }}>
                {loading ? 'Updating…' : 'Set new password →'}
              </button>
              <a className="mono" style={{ fontSize: 11, color: 'var(--muted)', cursor: 'pointer', textAlign: 'center' }}
                onClick={() => setStage('form')}>← Back to sign in</a>
            </form>
          )}

          {/* ── Stage: main form (signin / signup) ──────────────────── */}
          {(stage === 'form' || stage === 'forgot') && (
            <form onSubmit={tab === 'signin' ? handleSignIn : handleSignUp} className="col g-0">
              <div className="row g-0" style={{ marginBottom: 28, borderBottom: '1px solid var(--line)' }}>
                <AuthTab active={tab === 'signin'} onClick={() => switchTab('signin')}>Sign in</AuthTab>
                <AuthTab active={tab === 'signup'} onClick={() => switchTab('signup')}>Create account</AuthTab>
              </div>

              {tab === 'signup' && (
                <div className="col g-14" style={{ marginBottom: 14 }}>
                  <div>
                    <span className="label">Full name</span>
                    <input ref={nameRef} className="input" placeholder="Jane Doe"/>
                  </div>
                  <div>
                    <span className="label">Organisation</span>
                    <input ref={orgRef} className="input" placeholder="Charité — Universitätsmedizin Berlin"/>
                  </div>
                </div>
              )}

              <div className="col g-14">
                <div>
                  <span className="label">Work email</span>
                  <input ref={emailRef} className="input mono" type="email" placeholder="you@organisation.com"/>
                </div>
                <div>
                  <div className="row jc-b">
                    <span className="label">Password</span>
                    {tab === 'signin' && (
                      <a className="mono"
                        style={{ fontSize: 10.5, color: 'var(--muted)', cursor: 'pointer' }}
                        onClick={(e) => { e.preventDefault(); handleForgot(); }}>
                        forgot?
                      </a>
                    )}
                  </div>
                  <input ref={passwordRef} className="input mono" type="password"
                    placeholder={tab === 'signup' ? 'min. 8 chars, 1 uppercase, 1 number' : '••••••••••••'}/>
                </div>

                {tab === 'signup' && (
                  <label className="row g-8 ai-c" style={{ fontSize: 12, color: 'var(--ink-dim)', cursor: 'pointer' }}>
                    <input type="checkbox" checked={termsAccepted} onChange={e => { if (e.target.checked) setShowTerms(true); else setTermsAccepted(false); }} style={{ accentColor: 'var(--bone)' }}/>
                    <span>I agree to the <a className="bone" style={{ cursor: 'pointer' }} onClick={e => { e.preventDefault(); setShowTerms(true); }}>terms</a> and <a className="bone" style={{ cursor: 'pointer' }} onClick={e => { e.preventDefault(); setShowTerms(true); }}>data handling policy</a>.</span>
                  </label>
                )}

                <button type="submit" className="btn btn-primary btn-lg" disabled={loading}
                  style={{ justifyContent: 'center', width: '100%' }}>
                  {loading
                    ? (tab === 'signin' ? 'Signing in…' : 'Creating account…')
                    : (tab === 'signin' ? 'Enter dig site →' : 'Open first excavation →')}
                </button>

                <div className="row g-12 ai-c" style={{ margin: '4px 0' }}>
                  <div style={{ flex: 1, height: 1, background: 'var(--line)' }}/>
                  <span className="mono" style={{ fontSize: 10.5, color: 'var(--dim)' }}>or</span>
                  <div style={{ flex: 1, height: 1, background: 'var(--line)' }}/>
                </div>

                <button type="button" className="btn" style={{ justifyContent: 'center', width: '100%' }}
                  onClick={() => {
                    window.location.href = 'https://github.com/login/oauth/authorize?' +
                      new URLSearchParams({
                        client_id:    'Ov23liUjE6L748b63csT',
                        scope:        'user:email',
                        redirect_uri: 'https://r5vefiej3l.execute-api.eu-central-1.amazonaws.com/prod/auth/github/callback',
                      });
                  }}>
                  Continue with GitHub
                </button>
                <button type="button" className="btn" style={{ justifyContent: 'center', width: '100%' }}
                  onClick={() => toast('SSO (SAML) — available on Agency plan')}>
                  Continue with SSO (SAML)
                </button>
              </div>

              <p className="mono" style={{ fontSize: 10.5, color: 'var(--dim)', marginTop: 32, textAlign: 'center' }}>
                F-auth · session expires after 30 days of inactivity
              </p>
            </form>
          )}

        </div>
      </div>
    </div>
  );
}

function AuthTab({ active, onClick, children }) {
  return (
    <button type="button" onClick={onClick} style={{
      flex: 1, background: 'transparent', border: 0, padding: '10px 0',
      borderBottom: active ? '1px solid var(--ink)' : '1px solid transparent',
      marginBottom: -1,
      color: active ? 'var(--ink)' : 'var(--muted)',
      fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 500,
      cursor: 'pointer', letterSpacing: '-0.005em',
    }}>{children}</button>
  );
}

Object.assign(window, { AuthPage, getIdToken, clearTokens });