/* global React, Button, Icon, LoadingSpinner, LiveMonitorPanel, apiFetch, extractInvitationToken, setAuthNextPath, useAuth, validateBrowserReturnPath */
const { useEffect: useEffectAuthPage, useMemo: useMemoAuthPage, useRef: useRefAuthPage, useState: useStateAuthPage } = React;

const SIGNUP_PENDING_STORAGE_KEY = 'armature.signupPending';
const RESEND_COOLDOWN_SECONDS = 30;

function readSignupPending() {
  try {
    const raw = window.sessionStorage.getItem(SIGNUP_PENDING_STORAGE_KEY);
    if (!raw) return null;
    const parsed = JSON.parse(raw);
    if (!parsed || typeof parsed.email !== 'string') return null;
    return { email: parsed.email, lastResendAt: Number(parsed.lastResendAt) || 0 };
  } catch {
    return null;
  }
}

function writeSignupPending(value) {
  try {
    window.sessionStorage.setItem(SIGNUP_PENDING_STORAGE_KEY, JSON.stringify(value));
  } catch {
    // sessionStorage may be unavailable (e.g. private mode) — resend just won't survive a refresh
  }
}

function clearSignupPending() {
  try {
    window.sessionStorage.removeItem(SIGNUP_PENDING_STORAGE_KEY);
  } catch {
    // ignore
  }
}

function remainingCooldownSeconds(lastResendAt) {
  if (!lastResendAt) return 0;
  const elapsed = Math.floor((Date.now() - lastResendAt) / 1000);
  return Math.max(0, RESEND_COOLDOWN_SECONDS - elapsed);
}

function parseAuthQuery(queryString) {
  const params = new URLSearchParams(queryString || '');
  return {
    invite: params.get('invite') || extractInvitationToken(params.get('invite_link') || ''),
    plan: params.get('plan') || '',
    billing: params.get('billing') || params.get('period') || 'monthly',
    demo: params.get('demo') === '1' ? '1' : '',
    next: params.get('next') || '',
  };
}

function isValidEmail(value) {
  const email = String(value || '').trim();
  // Keep this aligned with backend lookup validation.
  return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}

function planIntentQuerySuffix(query, inviteToken = '') {
  const params = new URLSearchParams();
  if (!inviteToken && query.plan) {
    params.set('plan', query.plan);
    params.set('billing', query.billing);
    if (query.demo) params.set('demo', query.demo);
  }
  const queryString = params.toString();
  return queryString ? `?${queryString}` : '';
}

/**
 * @param {{ children: React.ReactNode, title: React.ReactNode, subtitle: React.ReactNode, monitorCaption?: string, panelClassName?: string, eyebrow?: string, phaseKey?: string }} props
 */
function AuthMarketingShell({ children, title, subtitle, monitorCaption, panelClassName = '', eyebrow = '', phaseKey = '' }) {
  const isCentered = panelClassName === 'auth-panel-centered';
  const contentClassName = isCentered ? 'auth-panel-main auth-panel-main-centered' : 'auth-panel-main';
  return (
    <div className="auth-page auth-page-split">
      <div className={`auth-panel auth-panel-wide ${panelClassName}`.trim()}>
        <div className="auth-logo">
          <img src="/frontend/assets/armature-wordmark-dark.svg" alt="Armature" />
        </div>
        <div className={contentClassName} key={phaseKey || undefined}>
          {eyebrow ? <div className="auth-eyebrow">{eyebrow}</div> : null}
          {title ? <h1>{title}</h1> : null}
          {subtitle ? <p className="muted auth-subtitle">{subtitle}</p> : null}
          {children}
        </div>
      </div>
      <LiveMonitorPanel captionIntro={monitorCaption} />
      <a className="auth-help" href="mailto:help@armature.tech">
        <Icon name="mail" size={13} />Stuck? Email us
      </a>
    </div>
  );
}

function canUseSupabaseAuth(auth) {
  return Boolean(auth?.config?.authConfigured && auth?.client);
}

function canUseDevAccess(auth) {
  return Boolean(auth?.config?.devAuthEnabled && auth?.config?.devAuthToken);
}

function AuthUnavailableMessage() {
  return (
    <div className="auth-message">
      Authentication is temporarily unavailable. Refresh and try again, or contact support if this continues.
    </div>
  );
}

function DevAccessForm({ navigate, nextPath, firstName = '' }) {
  const auth = useAuth();
  const configuredToken = auth?.config?.devAuthToken || '';
  const [token, setToken] = useStateAuthPage(configuredToken);
  const [message, setMessage] = useStateAuthPage('');
  const [busy, setBusy] = useStateAuthPage(false);

  useEffectAuthPage(() => {
    setToken(configuredToken);
  }, [configuredToken]);

  async function submit(event) {
    event.preventDefault();
    setBusy(true);
    setMessage('');
    try {
      await auth.useAccessToken(token, { flush: true });
      if (firstName.trim()) {
        await apiFetch('/api/me/profile', {
          method: 'POST',
          body: JSON.stringify({ first_name: firstName, last_name: '' }),
        });
        await auth.refreshMe({ flush: true });
      }
      navigate(nextPath);
    } catch (error) {
      setMessage(error.message || 'Dev access failed');
    } finally {
      setBusy(false);
    }
  }

  return (
    <form className="auth-form" onSubmit={submit}>
      <div className="auth-message">Local dev auth is enabled. Use the dev token to test the app.</div>
      <input className="input mono" value={token} onChange={(e) => setToken(e.target.value)} />
      <Button variant="primary" type="submit" loading={busy} loadingLabel="Opening workspace...">
        <Icon name="key" size={13} />Use dev token
      </Button>
      {message && <div className="auth-message">{message}</div>}
    </form>
  );
}

function EmailFirstAuthPage({ navigate, queryString = '', variant = 'signup' }) {
  const auth = useAuth();
  const query = useMemoAuthPage(() => parseAuthQuery(queryString), [queryString]);
  const [preview, setPreview] = useStateAuthPage(null);
  const [phase, setPhase] = useStateAuthPage('email');
  const [firstName, setFirstName] = useStateAuthPage('');
  const [email, setEmail] = useStateAuthPage('');
  const [password, setPassword] = useStateAuthPage('');
  const [showPassword, setShowPassword] = useStateAuthPage(false);
  const [busyAction, setBusyAction] = useStateAuthPage('');
  const [message, setMessage] = useStateAuthPage('');
  const firstInputRef = useRefAuthPage(null);
  const firstNameInputRef = useRefAuthPage(null);
  const passwordInputRef = useRefAuthPage(null);
  const inviteToken = query.invite;
  const orgName = preview?.organization?.name;
  const isSignupVariant = variant === 'signup';
  const canUseSupabase = canUseSupabaseAuth(auth);
  const authErrorMessage = auth?.error?.message || '';
  const businessEmailWarn = /@(gmail|yahoo|hotmail|outlook)\./i.test(email.trim());
  const onboardingNextPath = inviteToken ? `/invite/${inviteToken}/accept` : '/onboarding/workspace';
  const planQuerySuffix = planIntentQuerySuffix(query, inviteToken);
  const emailConfirmationNextPath = `${onboardingNextPath}${planQuerySuffix}`;
  const oauthNextPath = inviteToken ? onboardingNextPath : (query.plan ? `/onboarding/plan${planQuerySuffix}` : '/dashboard');
  const planQuerySuffixSignin = planIntentQuerySuffix(query, query.invite);
  const oauthAuthorizeNext = typeof validateAuthNextTarget === 'function' ? validateAuthNextTarget(query.next) : null;
  const googleNextPath = oauthAuthorizeNext || oauthNextPath;
  const nextPathAfterSignin = oauthAuthorizeNext || (query.invite ? `/invite/${query.invite}/accept` : (query.plan ? `/onboarding/plan${planQuerySuffixSignin}` : '/dashboard'));
  const devNextPath = isSignupVariant ? emailConfirmationNextPath : nextPathAfterSignin;

  useEffectAuthPage(() => {
    requestAnimationFrame(() => {
      if (phase === 'email') firstInputRef.current?.focus();
      else if (phase === 'signup') firstNameInputRef.current?.focus();
      else if (phase === 'signin') passwordInputRef.current?.focus();
    });
  }, [phase]);

  useEffectAuthPage(() => {
    let cancelled = false;
    async function loadPreview() {
      if (!inviteToken) {
        setPreview(null);
        return;
      }
      try {
        const result = await apiFetch(`/api/invitations/${inviteToken}`);
        if (!cancelled) setPreview(result);
      } catch (error) {
        if (!cancelled) setMessage(error.message || 'Invite could not be loaded');
      }
    }
    loadPreview();
    return () => {
      cancelled = true;
    };
  }, [inviteToken]);

  async function run(action, key) {
    setBusyAction(key);
    setMessage('');
    try {
      await action();
    } catch (error) {
      const msg = error?.message || '';
      if (/already registered|already been registered|user already exists/i.test(msg)) {
        setMessage('An account with this email already exists. Sign in instead.');
        setPhase('signin');
        setPassword('');
        return;
      }
      setMessage(msg || 'Authentication failed');
    } finally {
      setBusyAction('');
    }
  }

  async function continueFromEmail(event) {
    event.preventDefault();
    const trimmed = email.trim();
    if (!trimmed) throw new Error('Enter your email address');
    if (!isValidEmail(trimmed)) throw new Error('Enter a valid email address');
    try {
      const result = await apiFetch(`/api/auth/lookup-email?email=${encodeURIComponent(trimmed)}`);
      if (result.lookupAvailable === false) {
        setPhase('signup');
        return;
      }
      setPhase(result.exists ? 'signin' : 'signup');
    } catch (error) {
      throw new Error(error.message || 'Could not continue. Try again or use Google.');
    }
  }

  async function submitSignin(event) {
    event.preventDefault();
    const trimmedEmail = email.trim();
    const skipMeRefresh = Boolean(query.invite);
    await auth.signInWithPassword(trimmedEmail, password, { flush: true, skipMeRefresh });
    if (oauthAuthorizeNext) {
      window.location.assign(oauthAuthorizeNext);
      return;
    }
    navigate(nextPathAfterSignin);
  }

  async function submitSignup(event) {
    event.preventDefault();
    if (password.length < 8) throw new Error('Password must be at least 8 characters');
    const trimmedEmail = email.trim();
    const skipMeRefresh = Boolean(inviteToken);
    const result = await auth.signUpWithPassword(trimmedEmail, password, { nextPath: emailConfirmationNextPath, skipMeRefresh });
    if (!result?.data?.session) {
      // Supabase obfuscates duplicate signups by returning user metadata
      // without a session — empty `identities`, and (sometimes) populated
      // confirmation / sign-in timestamps. Those response-level signals are
      // the only safe duplicate detector here: a re-fetch of
      // `/api/auth/lookup-email` would always say `exists:true` because
      // `auth.signUpWithPassword` just inserted into `auth.users` (PR #398
      // made the lookup authoritative against that table), so every brand
      // new signup would be misrouted to "account already exists".
      const identities = result?.data?.user?.identities;
      const existingBySupabaseHint = Array.isArray(identities) && identities.length === 0;
      const existingByConfirmedHint = Boolean(
        result?.data?.user?.email_confirmed_at
        || result?.data?.user?.confirmed_at
        || result?.data?.user?.last_sign_in_at,
      );
      if (existingBySupabaseHint || existingByConfirmedHint) {
        setMessage('An account with this email already exists. Sign in instead.');
        setPhase('signin');
        setPassword('');
        return;
      }
      writeSignupPending({ email: trimmedEmail, lastResendAt: 0 });
      const params = new URLSearchParams();
      params.set('email', trimmedEmail);
      if (inviteToken) params.set('invite', inviteToken);
      if (!inviteToken && query.plan) {
        params.set('plan', query.plan);
        params.set('billing', query.billing);
        if (query.demo) params.set('demo', query.demo);
      }
      navigate(`/signup/verify-email?${params.toString()}`);
      return;
    }
    await apiFetch('/api/me/profile', {
      method: 'POST',
      body: JSON.stringify({ first_name: firstName, last_name: '' }),
    });
    if (inviteToken) {
      navigate(emailConfirmationNextPath);
      return;
    }
    await auth.refreshMe({ flush: true });
    navigate(emailConfirmationNextPath);
  }

  async function google() {
    setAuthNextPath(googleNextPath);
    await auth.signInWithGoogle({ nextPath: googleNextPath });
  }

  function backToEmail() {
    setPhase('email');
    setPassword('');
    setMessage('');
  }

  function backToSignin() {
    setPhase('signin');
    setMessage('');
  }

  function startForgotPassword() {
    setPhase('forgot');
    setMessage('');
  }

  async function submitForgotPassword(event) {
    event.preventDefault();
    const trimmed = email.trim();
    if (!trimmed) throw new Error('Enter your email address');
    if (!isValidEmail(trimmed)) throw new Error('Enter a valid email address');
    await auth.resetPasswordForEmail(trimmed, { nextPath: '/reset-password' });
    setPhase('forgot-sent');
  }

  const signupReady = firstName.trim() && email.trim() && password.length >= 8;
  const inviteTitle = inviteToken && orgName ? (
    <>Join <span className="auth-headline-hl">{orgName}</span></>
  ) : null;
  const continueTitle = <>Continue to <span className="auth-headline-hl">Armature</span></>;
  const welcomeBackTitle = <>Welcome <span className="auth-headline-hl">back</span></>;
  const almostThereTitle = inviteTitle || <>Almost <span className="auth-headline-hl">there</span></>;
  const forgotTitle = <>Reset your <span className="auth-headline-hl">password</span></>;
  const forgotSentTitle = <>Check your <span className="auth-headline-hl">inbox</span></>;

  const shellTitle =
    phase === 'email'
      ? continueTitle
      : phase === 'signin'
        ? welcomeBackTitle
        : phase === 'forgot'
          ? forgotTitle
          : phase === 'forgot-sent'
            ? forgotSentTitle
            : almostThereTitle;
  const shellSubtitle =
    phase === 'email'
      ? (inviteToken ? 'Accept your workspace invite to continue.' : '')
      : phase === 'signin'
        ? <>Signing in as <span className="mono">{email.trim() || '…'}</span></>
        : phase === 'forgot'
          ? <>We'll send a reset link to <span className="mono">{email.trim() || '…'}</span></>
          : phase === 'forgot-sent'
            ? <>We sent a reset link to <span className="mono">{email.trim() || '…'}</span>. Open it to set a new password.</>
            : <>Creating an account for <span className="mono">{email.trim() || '…'}</span></>;

  const monitorCaption =
    phase === 'email' && !isSignupVariant
      ? 'while you sign in - workspace checks are running'
      : 'while you continue - workspace checks are running';

  if (!auth.config) {
    if (auth.error) {
      return (
        <AuthMarketingShell title={continueTitle} subtitle="" monitorCaption={monitorCaption} panelClassName="auth-panel-centered" phaseKey="config-error">
          <div className="auth-message">{auth.error.message || 'Could not load authentication configuration.'}</div>
        </AuthMarketingShell>
      );
    }
    return (
      <AuthMarketingShell
        title={continueTitle}
        subtitle="Connecting..."
        monitorCaption={monitorCaption}
        panelClassName="auth-panel-centered"
        phaseKey="config-loading">
        <div className="auth-form">
          <LoadingSpinner label="Connecting..." />
        </div>
      </AuthMarketingShell>
    );
  }

  return (
    <AuthMarketingShell
      title={shellTitle}
      subtitle={shellSubtitle}
      monitorCaption={monitorCaption}
      panelClassName="auth-panel-centered"
      phaseKey={phase}>
      {inviteToken && preview?.status === 'active' && (
        <div className="invite-inline">
          You have been invited to <strong>{orgName}</strong> as <strong>{preview.role}</strong>.
        </div>
      )}
      {canUseSupabase ? (
        <>
          {phase === 'email' && (
            <form className="auth-form" onSubmit={(event) => run(() => continueFromEmail(event), 'continue')}>
              <Button className="auth-oauth" type="button" disabled={Boolean(busyAction)} loading={busyAction === 'google'} loadingLabel="Opening Google..." onClick={() => run(google, 'google')}>
                <img className="google-mark" src="/frontend/assets/google-g.png" alt="" aria-hidden="true" />Continue with Google
              </Button>
              <div className="auth-divider"><span>or</span></div>
              <input
                ref={firstInputRef}
                className="input"
                type="email"
                inputMode="email"
                autoComplete="email"
                placeholder="Work email"
                value={email}
                onChange={(e) => setEmail(e.target.value)}
              />
              {businessEmailWarn && <div className="field-help">A work email is best for team invites, but this address is allowed.</div>}
              <Button variant="primary" className="auth-submit" type="submit" disabled={!email.trim() || Boolean(busyAction)} loading={busyAction === 'continue'} loadingLabel="Continuing...">
                <Icon name="mail" size={13} />Continue with email
              </Button>
            </form>
          )}
          {phase === 'signin' && (
            <form className="auth-form" onSubmit={(event) => run(() => submitSignin(event), 'password')}>
              <div className="password-field">
                <input ref={passwordInputRef} className="input" placeholder="Password" type="password" autoComplete="current-password" value={password} onChange={(e) => setPassword(e.target.value)} />
              </div>
              <div className="auth-row-end">
                <button type="button" className="auth-link" disabled={Boolean(busyAction)} onClick={startForgotPassword}>
                  Forgot password?
                </button>
              </div>
              <Button variant="primary" className="auth-submit" type="submit" disabled={!password || Boolean(busyAction)} loading={busyAction === 'password'} loadingLabel="Signing in...">
                <Icon name="key" size={13} />Sign in
              </Button>
              <div className="auth-switch auth-inline-switch">
                <button type="button" disabled={Boolean(busyAction)} onClick={backToEmail}>Use a different email</button>
              </div>
            </form>
          )}
          {phase === 'forgot' && (
            <form className="auth-form" onSubmit={(event) => run(() => submitForgotPassword(event), 'forgot')}>
              <Button variant="primary" className="auth-submit" type="submit" disabled={!email.trim() || Boolean(busyAction)} loading={busyAction === 'forgot'} loadingLabel="Sending reset link...">
                <Icon name="mail" size={13} />Send reset link
              </Button>
              <div className="auth-switch auth-inline-switch">
                <button type="button" disabled={Boolean(busyAction)} onClick={backToSignin}>Back to sign in</button>
              </div>
            </form>
          )}
          {phase === 'forgot-sent' && (
            <div className="auth-form">
              <Button className="auth-oauth" type="button" disabled={Boolean(busyAction)} loading={busyAction === 'forgot'} loadingLabel="Resending..." onClick={() => run(() => submitForgotPassword({ preventDefault() {} }), 'forgot')}>
                <Icon name="refresh" size={13} />Resend reset link
              </Button>
              <div className="auth-switch auth-inline-switch">
                <button type="button" disabled={Boolean(busyAction)} onClick={backToSignin}>Back to sign in</button>
              </div>
            </div>
          )}
          {phase === 'signup' && (
            <form className="auth-form" onSubmit={(event) => run(() => submitSignup(event), 'password')}>
              <input ref={firstNameInputRef} className="input" placeholder="First name" autoComplete="given-name" value={firstName} onChange={(e) => setFirstName(e.target.value)} />
              {businessEmailWarn && <div className="field-help">A work email is best for team invites, but this address is allowed.</div>}
              <div className="password-field">
                <input ref={passwordInputRef} className="input" placeholder="Password" type={showPassword ? 'text' : 'password'} autoComplete="new-password" value={password} onChange={(e) => setPassword(e.target.value)} />
                <button type="button" className="password-toggle" onClick={() => setShowPassword((v) => !v)}>
                  {showPassword ? 'Hide' : 'Show'}
                </button>
              </div>
              <Button variant="primary" className="auth-submit" type="submit" disabled={!signupReady || Boolean(busyAction)} loading={busyAction === 'password'} loadingLabel="Creating account...">
                <Icon name="key" size={13} />{inviteToken && orgName ? `Join ${orgName}` : 'Create account'}
              </Button>
              <div className="auth-switch auth-inline-switch">
                <button type="button" disabled={Boolean(busyAction)} onClick={backToEmail}>Use a different email</button>
              </div>
            </form>
          )}
        </>
      ) : canUseDevAccess(auth) ? (
        <DevAccessForm navigate={navigate} nextPath={devNextPath} firstName={firstName} />
      ) : (
        <AuthUnavailableMessage />
      )}
      {authErrorMessage && <div className="auth-message">{authErrorMessage}</div>}
      {message && <div className="auth-message">{message}</div>}
    </AuthMarketingShell>
  );
}

function SignupPage(props) {
  return <EmailFirstAuthPage {...props} variant="signup" />;
}

function SigninPage(props) {
  return <EmailFirstAuthPage {...props} variant="signin" />;
}

function webmailUrlForEmail(email) {
  const domain = (email.split('@')[1] || '').toLowerCase();
  if (!domain) return null;
  if (domain === 'gmail.com' || domain === 'googlemail.com') {
    return { label: 'Open Gmail', href: 'https://mail.google.com/mail/u/0/#inbox' };
  }
  if (domain === 'outlook.com' || domain === 'hotmail.com' || domain === 'live.com' || domain === 'msn.com') {
    return { label: 'Open Outlook', href: 'https://outlook.live.com/mail/0/inbox' };
  }
  if (domain === 'yahoo.com' || domain === 'yahoo.co.uk' || domain === 'ymail.com') {
    return { label: 'Open Yahoo Mail', href: 'https://mail.yahoo.com/' };
  }
  return null;
}

function VerifyEmailPage({ navigate, queryString = '' }) {
  const auth = useAuth();
  const params = useMemoAuthPage(() => new URLSearchParams(queryString || ''), [queryString]);
  const querySuffix = queryString ? `?${queryString}` : '';
  const pending = useMemoAuthPage(() => readSignupPending(), []);
  const urlEmail = (params.get('email') || '').trim().toLowerCase();
  const storedEmail = (pending?.email || '').trim().toLowerCase();
  const trustedEmail = pending?.email && (!urlEmail || urlEmail === storedEmail) ? pending.email : '';
  const displayEmail = trustedEmail || pending?.email || '';
  const afterConfirmationPath = params.get('invite')
    ? `/invite/${params.get('invite')}/accept`
    : `/onboarding/workspace${params.get('plan') ? `?plan=${encodeURIComponent(params.get('plan'))}&billing=${encodeURIComponent(params.get('billing') || 'monthly')}${params.get('demo') === '1' ? '&demo=1' : ''}` : ''}`;

  useEffectAuthPage(() => {
    if (auth.session) {
      clearSignupPending();
      navigate(afterConfirmationPath);
      return;
    }
    if (!pending) navigate(`/signup${querySuffix}`);
  }, [auth.session, pending, navigate, querySuffix, afterConfirmationPath]);

  const [resendBusy, setResendBusy] = useStateAuthPage(false);
  const [resendMessage, setResendMessage] = useStateAuthPage('');
  const [resendError, setResendError] = useStateAuthPage('');
  const [cooldown, setCooldown] = useStateAuthPage(() => remainingCooldownSeconds(pending?.lastResendAt));
  const webmail = useMemoAuthPage(() => webmailUrlForEmail(displayEmail), [displayEmail]);

  useEffectAuthPage(() => {
    if (cooldown <= 0) return undefined;
    const timer = setTimeout(() => setCooldown((s) => Math.max(0, s - 1)), 1000);
    return () => clearTimeout(timer);
  }, [cooldown]);

  async function handleResend() {
    if (!trustedEmail || resendBusy || cooldown > 0) return;
    setResendBusy(true);
    setResendMessage('');
    setResendError('');
    try {
      await auth.resendSignupEmail(trustedEmail, { nextPath: afterConfirmationPath });
      const lastResendAt = Date.now();
      writeSignupPending({ email: trustedEmail, lastResendAt });
      setResendMessage('Confirmation email sent. Check your inbox.');
      setCooldown(RESEND_COOLDOWN_SECONDS);
    } catch (error) {
      setResendError(error.message || 'Could not resend confirmation email');
    } finally {
      setResendBusy(false);
    }
  }

  function backToSignup() {
    const back = new URLSearchParams();
    if (params.get('invite')) back.set('invite', params.get('invite'));
    if (params.get('plan')) back.set('plan', params.get('plan'));
    if (params.get('billing')) back.set('billing', params.get('billing'));
    if (params.get('demo') === '1') back.set('demo', '1');
    clearSignupPending();
    const qs = back.toString();
    navigate(`/signup${qs ? `?${qs}` : ''}`);
  }

  const verifyTitle = <>Check your <span className="auth-headline-hl">inbox</span></>;
  const verifySubtitle = displayEmail ? (
    <>We sent a confirmation link to <span className="mono">{displayEmail}</span>. Open it to finish creating your account.</>
  ) : 'We sent you a confirmation link. Open it to finish creating your account.';

  return (
    <AuthMarketingShell
      title={verifyTitle}
      subtitle={verifySubtitle}
      monitorCaption="while you confirm your email - workspace checks are running"
      panelClassName="auth-panel-centered"
      phaseKey="verify">
      <div className="auth-form">
        {webmail && (
          <Button
            variant="primary"
            className="auth-submit"
            href={webmail.href}
            target="_blank"
            rel="noopener noreferrer">
            <Icon name="mail" size={13} />{webmail.label}
          </Button>
        )}
        {trustedEmail && (
          <Button
            className="auth-oauth"
            onClick={handleResend}
            disabled={resendBusy || cooldown > 0}
            loading={resendBusy}
            loadingLabel="Resending...">
            <Icon name="refresh" size={13} />
            {cooldown > 0 ? `Resend confirmation email (${cooldown}s)` : 'Resend confirmation email'}
          </Button>
        )}
        {resendMessage && <div className="auth-message auth-message-success">{resendMessage}</div>}
        {resendError && <div className="auth-message">{resendError}</div>}
      </div>
      <p className="muted verify-email-tips">The link expires after a short time. If you do not see it, check your spam folder.</p>
      <div className="auth-switch">
        Wrong email? <button onClick={backToSignup}>Go back</button>
      </div>
      <div className="auth-switch">
        Already confirmed? <button onClick={() => { clearSignupPending(); navigate(`/signin${querySuffix}`); }}>Sign in</button>
      </div>
    </AuthMarketingShell>
  );
}

function ResetPasswordPage({ navigate, queryString = '' }) {
  const auth = useAuth();
  const params = useMemoAuthPage(() => new URLSearchParams(queryString || ''), [queryString]);
  const passwordInputRef = useRefAuthPage(null);
  const [password, setPassword] = useStateAuthPage('');
  const [confirm, setConfirm] = useStateAuthPage('');
  const [showPassword, setShowPassword] = useStateAuthPage(false);
  const [busy, setBusy] = useStateAuthPage(false);
  const [message, setMessage] = useStateAuthPage('');
  const [done, setDone] = useStateAuthPage(false);
  const sessionEmail = auth?.session?.user?.email || auth?.me?.profile?.email || '';

  useEffectAuthPage(() => {
    requestAnimationFrame(() => passwordInputRef.current?.focus());
  }, []);

  // No session = the user navigated here directly (or the recovery link
  // expired). Send them back to /signin so they can request a new reset.
  useEffectAuthPage(() => {
    if (auth.config && !auth.session && auth.status !== 'bootstrapping') {
      navigate(`/signin${queryString ? `?${queryString}` : ''}`);
    }
  }, [auth.config, auth.session, auth.status, navigate, queryString]);

  const ready = password.length >= 8 && password === confirm;

  async function submit(event) {
    event.preventDefault();
    setMessage('');
    if (password.length < 8) {
      setMessage('Password must be at least 8 characters');
      return;
    }
    if (password !== confirm) {
      setMessage('Passwords do not match');
      return;
    }
    setBusy(true);
    try {
      await auth.updatePassword(password, { flush: true });
      setDone(true);
      setTimeout(() => {
        const nextPath = validateBrowserReturnPath(params.get('next')) || '/dashboard';
        navigate(nextPath);
      }, 1200);
    } catch (error) {
      setMessage(error?.message || 'Could not update password');
    } finally {
      setBusy(false);
    }
  }

  const title = done
    ? <>Password <span className="auth-headline-hl">updated</span></>
    : <>Set a new <span className="auth-headline-hl">password</span></>;
  const subtitle = done
    ? 'Signing you in...'
    : sessionEmail
      ? <>Choose a new password for <span className="mono">{sessionEmail}</span></>
      : 'Choose a new password to finish recovery.';

  return (
    <AuthMarketingShell
      title={title}
      subtitle={subtitle}
      monitorCaption="while you set a new password - workspace checks are running"
      panelClassName="auth-panel-centered"
      phaseKey={done ? 'reset-done' : 'reset'}>
      {done ? (
        <div className="auth-form">
          <LoadingSpinner label="Redirecting..." />
        </div>
      ) : (
        <form className="auth-form" onSubmit={submit}>
          <div className="password-field">
            <input
              ref={passwordInputRef}
              className="input"
              placeholder="New password"
              type={showPassword ? 'text' : 'password'}
              autoComplete="new-password"
              value={password}
              onChange={(e) => setPassword(e.target.value)} />
            <button type="button" className="password-toggle" onClick={() => setShowPassword((v) => !v)}>
              {showPassword ? 'Hide' : 'Show'}
            </button>
          </div>
          <input
            className="input"
            placeholder="Confirm new password"
            type={showPassword ? 'text' : 'password'}
            autoComplete="new-password"
            value={confirm}
            onChange={(e) => setConfirm(e.target.value)} />
          <Button variant="primary" className="auth-submit" type="submit" disabled={!ready || busy} loading={busy} loadingLabel="Updating...">
            <Icon name="key" size={13} />Update password
          </Button>
          {message && <div className="auth-message">{message}</div>}
        </form>
      )}
    </AuthMarketingShell>
  );
}

window.SignupPage = SignupPage;
window.SigninPage = SigninPage;
window.VerifyEmailPage = VerifyEmailPage;
window.ResetPasswordPage = ResetPasswordPage;
