// Navbar — logo + anchor nav + email login + language switcher
const I18N = {
  zh: {
    nav: { download: '下载', live: '主播', community: '社区' },
    auth: {
      hint: '登录', emailLabel: '邮箱', passwordLabel: '密码', emailPlaceholder: 'you@example.com', passwordPlaceholder: '输入密码',
      loginBtn: '登录', registerBtn: '注册', forgotPassword: '忘记密码?', noAccount: '没有账号？', goRegister: '立即注册',
      hasAccount: '已有账号？', goLogin: '去登录', backToLogin: '返回登录',
      loginSuccess: '登录成功', registerSuccess: '注册成功', welcomeNew: '欢迎新主播加入！',
      emailError: '邮箱格式不正确',
      wrongPassword: '密码错误，请重新输入',
      tooManyFails: '密码多次错误，建议点击下方「忘记密码」重置',
      // 密码强度
      pwdHintTitle: '密码要求：',
      pwdMin6: '至少 6 个字符', pwdLower: '包含小写字母', pwdUpper: '包含大写字母', pwdDigit: '包含数字',
      // 重置密码
      resetTitle: '重置密码', resetDesc: '输入注册邮箱，我们将发送重置密码链接。', sendReset: '发送重置链接',
      resetSent: (email) => `重置链接已发送至 ${email}，请查收邮箱（含垃圾箱）。`,
      notRegistered: '该邮箱尚未注册，正在跳转到注册页面…',
      alreadyRegistered: '该邮箱已注册，正在跳转到登录页面…',
      // 邮箱验证码
      sendCode: '发送验证码', codeLabel: '验证码', codePlaceholder: '输入6位验证码',
      codeSent: (email) => `验证码已发送至 ${email}`, resendCode: '重新发送', changeEmail: '修改',
      // 通用
      submitting: '提交中…', terms: '登录即表示同意服务条款与隐私政策。',
      profile: '个人主页', logout: '退出登录',
      newPwdTitle: '设置新密码', newPwdDesc: '请输入你的新密码。', newPwdBtn: '确认修改', newPwdSuccess: '密码修改成功！', welcomeBack: '欢迎回来！',
    },
    lang: { zh: '中文', en: 'EN' },
  },
  en: {
    nav: { download: 'Download', live: 'Streamers', community: 'Community' },
    auth: {
      hint: 'Sign in', emailLabel: 'Email', passwordLabel: 'Password', emailPlaceholder: 'you@example.com', passwordPlaceholder: 'Enter password',
      loginBtn: 'Sign in', registerBtn: 'Sign up', forgotPassword: 'Forgot password?', noAccount: 'No account? ', goRegister: 'Sign up',
      hasAccount: 'Have an account? ', goLogin: 'Sign in', backToLogin: 'Back to sign in',
      loginSuccess: 'Signed in', registerSuccess: 'Signed up', welcomeNew: 'Welcome, new streamer!',
      emailError: 'Invalid email address',
      wrongPassword: 'Wrong password, please try again',
      tooManyFails: 'Too many failed attempts. Try resetting your password below.',
      pwdHintTitle: 'Password requirements:',
      pwdMin6: 'At least 6 characters', pwdLower: 'Contains lowercase', pwdUpper: 'Contains uppercase', pwdDigit: 'Contains a digit',
      resetTitle: 'Reset password', resetDesc: 'Enter your registered email and we\'ll send a reset link.', sendReset: 'Send reset link',
      resetSent: (email) => `Reset link sent to ${email}. Check your inbox (and spam).`,
      notRegistered: 'This email is not registered. Redirecting to sign up…',
      alreadyRegistered: 'This email is already registered. Redirecting to sign in…',
      // OTP
      sendCode: 'Send code', codeLabel: 'Code', codePlaceholder: '6-digit code',
      codeSent: (email) => `Code sent to ${email}`, resendCode: 'Resend', changeEmail: 'Change',
      submitting: 'Submitting…', terms: 'By continuing you agree to our Terms and Privacy Policy.',
      profile: 'My Profile', logout: 'Sign out',
      newPwdTitle: 'Set new password', newPwdDesc: 'Enter your new password.', newPwdBtn: 'Update password', newPwdSuccess: 'Password updated!', welcomeBack: 'Welcome back!',
    },
    lang: { zh: '中文', en: 'EN' },
  },
};

function useLang() {
  const [lang, setLangState] = React.useState(() => {
    if (typeof window === 'undefined') return 'zh';
    return window.__kiwvoLang || localStorage.getItem('kiwvo.lang') || 'zh';
  });
  React.useEffect(() => {
    const on = (e) => setLangState(e.detail);
    window.addEventListener('kiwvo:lang', on);
    return () => window.removeEventListener('kiwvo:lang', on);
  }, []);
  const setLang = (l) => {
    window.__kiwvoLang = l;
    localStorage.setItem('kiwvo.lang', l);
    window.dispatchEvent(new CustomEvent('kiwvo:lang', { detail: l }));
  };
  return [lang, setLang];
}
window.useLang = useLang;
window.I18N = I18N;

function LangSwitch({ lang, setLang }) {
  return (
    <div className="relative flex items-center h-10 rounded-full bg-white/[0.03] border border-white/[0.06] p-1 text-[11.5px] font-mono tracking-[0.08em]">
      {['zh', 'en'].map((l) => (
        <button
          key={l}
          onClick={() => setLang(l)}
          className={`relative z-10 h-full px-3 rounded-full transition-colors ${
            lang === l ? 'text-[#052E21]' : 'text-white/55 hover:text-white'
          }`}
        >
          {l === 'zh' ? '中' : 'EN'}
        </button>
      ))}
      <span
        aria-hidden
        className="absolute top-1 bottom-1 w-[calc(50%-4px)] rounded-full bg-emerald-400/90 transition-transform duration-200"
        style={{ transform: lang === 'zh' ? 'translateX(0)' : 'translateX(calc(100% + 0px))' }}
      />
    </div>
  );
}

// ── 错误提示 Toast ──────────────────────────────────────────────
function ErrorToast({ msg, onClose }) {
  React.useEffect(() => {
    const t = setTimeout(onClose, 4000);
    return () => clearTimeout(t);
  }, [msg]);
  if (!msg) return null;
  return (
    <div className="fixed top-20 left-1/2 -translate-x-1/2 w-[320px] flex items-start gap-2.5 p-3 rounded-xl bg-rose-500/10 border border-rose-400/30 text-[12.5px] text-rose-300 shadow-lg z-[310] animate-[fadeIn_0.15s_ease]">
      <svg width="15" height="15" viewBox="0 0 24 24" fill="none" className="shrink-0 mt-0.5">
        <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="1.6"/>
        <path d="M12 8v4M12 16h.01" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>
      </svg>
      <span className="flex-1 leading-relaxed">{msg}</span>
      <button onClick={onClose} className="shrink-0 text-rose-300/60 hover:text-rose-200 transition-colors">
        <svg width="13" height="13" viewBox="0 0 24 24" fill="none">
          <path d="M18 6L6 18M6 6l12 12" stroke="currentColor" strokeWidth="2" strokeLinecap="round"/>
        </svg>
      </button>
    </div>
  );
}

// ── 错误码 → 本地化 ──────────────────────────────────────────────
const ERR_MAP = {
  zh: {
    invalidCredentials: '邮箱或密码错误',
    invalidEmail: '邮箱格式不正确',
    rateLimit: '操作太频繁，请稍后再试',
    network: '网络异常，请检查连接后重试',
    alreadyRegistered: '该邮箱已注册，请直接登录',
    weakPassword: '密码强度不够，请检查要求',
    otpInvalid: '验证码输入错误，请检查后重新输入',
    recoveryEmail: '发送重置邮件失败，请检查 Supabase 邮件配置',
    fallback: '操作失败，请重试',
  },
  en: {
    invalidCredentials: 'Invalid email or password',
    invalidEmail: 'Invalid email address',
    rateLimit: 'Too many attempts, please wait',
    network: 'Network error, check your connection',
    alreadyRegistered: 'Email already registered, please sign in',
    weakPassword: 'Password too weak, check requirements',
    otpInvalid: 'Incorrect code, please check and try again',
    recoveryEmail: 'Failed to send recovery email, check email config',
    fallback: 'Something went wrong, please retry',
  },
};
function supaErrMsg(err, lang) {
  const m = ERR_MAP[lang] || ERR_MAP.zh;
  if (!err) return m.fallback;
  const msg = (err.message || '').toLowerCase();
  if (msg.includes('invalid login credentials') || msg.includes('invalid password')) return m.invalidCredentials;
  if (msg.includes('email') && msg.includes('invalid')) return m.invalidEmail;
  if (msg.includes('rate limit') || msg.includes('too many') || msg.includes('email rate limit') || msg.includes('security purposes')) return m.rateLimit;
  if (msg.includes('network') || msg.includes('fetch')) return m.network;
  if (msg.includes('user already registered') || msg.includes('already been registered')) return m.alreadyRegistered;
  if (msg.includes('password') && (msg.includes('weak') || msg.includes('short') || msg.includes('least'))) return m.weakPassword;
  if (msg.includes('otp') || (msg.includes('token') && (msg.includes('expired') || msg.includes('invalid')))) return m.otpInvalid;
  if (msg.includes('sending recovery email') || msg.includes('sending reset')) return m.recoveryEmail;
  return err.message || m.fallback;
}

// 常见邮箱后缀（用于输入时自动补全下拉）
const EMAIL_DOMAINS = [
  'gmail.com', 'outlook.com', 'hotmail.com', 'yahoo.com', 'icloud.com',
  'qq.com', '163.com', '126.com', 'foxmail.com', 'sina.com',
];

// 根据已输入内容生成后缀建议
function emailSuggestions(value) {
  if (!value || value.indexOf(' ') !== -1) return [];
  const at = value.indexOf('@');
  if (at === -1) {
    return EMAIL_DOMAINS.map(d => `${value}@${d}`);
  }
  const local = value.slice(0, at);
  if (!local) return [];
  const domainPart = value.slice(at + 1).toLowerCase();
  // 已包含第二个 @ 则不建议
  if (domainPart.indexOf('@') !== -1) return [];
  return EMAIL_DOMAINS
    .filter(d => d.startsWith(domainPart) && d !== domainPart)
    .map(d => `${local}@${d}`);
}

function EmailLogin({ t, lang }) {
  const [open, setOpen] = React.useState(false);
  const [view, setView] = React.useState('login'); // login | register | reset
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');
  const [showPwd, setShowPwd] = React.useState(false);
  const [loading, setLoading] = React.useState(false);
  const [done, setDone] = React.useState(false);
  const [doneMsg, setDoneMsg] = React.useState('');
  const [resetSent, setResetSent] = React.useState(false);
  const [errMsg, setErrMsg] = React.useState('');
  const [showLoginPwdHint, setShowLoginPwdHint] = React.useState(false);
  const [otpSent, setOtpSent] = React.useState(false);
  const [otpCode, setOtpCode] = React.useState('');
  const [countdown, setCountdown] = React.useState(0);
  const [promptMsg, setPromptMsg] = React.useState('');
  const [loginFailCount, setLoginFailCount] = React.useState(0);
  const [emailFocused, setEmailFocused] = React.useState(false);
  const mouseDownOnBackdrop = React.useRef(false);

  // 外部触发登录时携带的提示消息
  React.useEffect(() => {
    if (open && window.__authPromptMsg) {
      setPromptMsg(window.__authPromptMsg);
      window.__authPromptMsg = null;
    }
    if (!open) setPromptMsg('');
  }, [open]);

  React.useEffect(() => {
    if (countdown <= 0) return;
    const t = setTimeout(() => setCountdown(c => c - 1), 1000);
    return () => clearTimeout(t);
  }, [countdown]);

  const emailOk = /^\S+@\S+\.\S+$/.test(email);
  const pwdChecks = {
    min6: password.length >= 6,
    lower: /[a-z]/.test(password),
    upper: /[A-Z]/.test(password),
    digit: /\d/.test(password),
  };
  const pwdStrong = pwdChecks.min6 && pwdChecks.lower && pwdChecks.upper && pwdChecks.digit;

  const canLogin = emailOk && password.length >= 6 && !loading;
  const canRegister = otpCode.length === 6 && emailOk && pwdStrong && !loading;
  const canReset = emailOk && !loading;

  const resetForm = () => {
    setPassword('');
    setShowPwd(false);
    setErrMsg('');
    setResetSent(false);
    setShowLoginPwdHint(false);
    setOtpSent(false);
    setOtpCode('');
    setCountdown(0);
  };
  const switchView = (v) => { setView(v); resetForm(); setLoginFailCount(0); };

  // ── 登录 ──
  const handleLogin = async (e) => {
    e.preventDefault();
    if (!canLogin) return;
    setLoading(true);
    setErrMsg('');
    setShowLoginPwdHint(false);
    try {
      // 直接尝试密码登录（不再做邮箱存在性探测，避免触发 OTP 验证码）
      const { error } = await window.supabaseClient.auth.signInWithPassword({ email, password });
      console.log('[kiwvo:login] signInWithPassword error:', error?.message || '(success)');
      if (!error) {
        setLoginFailCount(0);
        setDone(true);
        setDoneMsg(t.auth.loginSuccess);
        setTimeout(() => { setOpen(false); setDone(false); setEmail(''); setPassword(''); setView('login'); }, 1800);
        return;
      }
      // 密码错误
      const newFails = loginFailCount + 1;
      setLoginFailCount(newFails);
      if (newFails >= 5) {
        setErrMsg(t.auth.tooManyFails);
      } else {
        setErrMsg(t.auth.wrongPassword);
      }
      setShowLoginPwdHint(true);
    } catch (err) {
      console.error('[kiwvo:login] unexpected error:', err);
      setErrMsg(supaErrMsg(err, lang));
    } finally {
      setLoading(false);
    }
  };

  // ── 发送验证码 ──
  const handleSendCode = async () => {
    if (!emailOk || loading) return;
    setLoading(true);
    setErrMsg('');
    try {
      // 1) 先检查邮箱是否已注册（串行，避免提前创建用户）
      const rpcRes = await Promise.race([
        window.supabaseClient.rpc('check_email_exists', { check_email: email }),
        new Promise(r => setTimeout(() => r({ data: null, error: { message: 'timeout' } }), 2000)),
      ]);
      if (!rpcRes.error && rpcRes.data === true) {
        setErrMsg(t.auth.alreadyRegistered);
        setTimeout(() => { switchView('login'); }, 1500);
        return;
      }

      // 2) 发送验证码（Supabase 会创建未确认的用户记录来存储 OTP）
      const { error } = await window.supabaseClient.auth.signInWithOtp({
        email,
        options: { shouldCreateUser: true },
      });
      if (error) throw error;
      setOtpSent(true);
      setCountdown(60);
    } catch (err) {
      setErrMsg(supaErrMsg(err, lang));
    } finally {
      setLoading(false);
    }
  };

  // ── 注册（验证 OTP + 设密码）──
  const handleRegister = async (e) => {
    e.preventDefault();
    if (!canRegister) return;
    setLoading(true);
    setErrMsg('');
    try {
      const { error } = await window.supabaseClient.auth.verifyOtp({
        email,
        token: otpCode,
        type: 'email',
      });
      if (error) throw error;

      const { error: pwdErr } = await window.supabaseClient.auth.updateUser({ password });
      if (pwdErr) throw pwdErr;

      window.supabaseClient.functions.invoke('send-welcome-email', {
        body: { email, lang },
      }).catch((e) => console.warn('[WelcomeEmail] send failed:', e));

      // 注册成功 → 推送 Telegram 通知（邮箱 / 时间 / 位置，fire-and-forget，失败不影响注册）
      (async () => {
        let location = {};
        try {
          const r = await fetch('https://ipapi.co/json/');
          if (r.ok) {
            const j = await r.json();
            location = { ip: j.ip, city: j.city, region: j.region, country: j.country_name };
          }
        } catch (_) { /* 定位失败则留空 */ }
        window.supabaseClient.functions.invoke('notify-telegram', {
          body: { email, created_at: new Date().toISOString(), location },
        }).catch((e) => console.warn('[notify-telegram] send failed:', e));
      })();

      setDone(true);
      setDoneMsg(t.auth.welcomeNew);
      setTimeout(() => { setOpen(false); setDone(false); setEmail(''); setPassword(''); setOtpCode(''); setOtpSent(false); setView('login'); }, 2500);
    } catch (err) {
      setErrMsg(supaErrMsg(err, lang));
    } finally {
      setLoading(false);
    }
  };

  // ── 重置密码 ──
  const handleReset = async (e) => {
    e.preventDefault();
    if (!canReset) return;
    setLoading(true);
    setErrMsg('');
    try {
      // 先检查邮箱是否已注册（尝试用空密码登录，根据错误判断）
      const { error: checkErr } = await window.supabaseClient.auth.signInWithPassword({ email, password: '__check_only__' });
      // 如果返回 "Invalid login credentials" 说明用户存在但密码不对 → 允许重置
      // 如果返回其他错误（如用户不存在），提示先注册
      if (checkErr) {
        const msg = (checkErr.message || '').toLowerCase();
        // Supabase 对不存在的用户也返回 "Invalid login credentials"，所以我们直接发送重置
        // 但如果是 rate limit 等错误则抛出
        if (msg.includes('rate limit') || msg.includes('too many')) throw checkErr;
      }
      const { error } = await window.supabaseClient.auth.resetPasswordForEmail(email, {
        redirectTo: window.location.origin + window.location.pathname,
      });
      if (error) throw error;
      setResetSent(true);
    } catch (err) {
      setErrMsg(supaErrMsg(err, lang));
    } finally {
      setLoading(false);
    }
  };

  // 内联 JSX 片段（避免在组件内定义子组件导致每次渲染重建、autoFocus 抢焦点）
  const emailSugs = emailSuggestions(email);
  const showEmailSugs = emailFocused && emailSugs.length > 0;
  const emailInput = (af) => (
    <>
      <label className="block text-[11px] text-white/45 font-mono tracking-[0.14em] uppercase mb-1.5">{t.auth.emailLabel}</label>
      <div className="relative">
        <div className={`flex items-center gap-2 p-1 rounded-lg bg-[#0A1512] border transition-all ${
          email && !emailOk ? 'border-rose-400/40' : 'border-white/[0.08] focus-within:border-emerald-400/40 focus-within:shadow-[0_0_0_3px_rgba(16,185,129,0.1)]'
        }`}>
          <div className="pl-2 text-white/35">
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
              <rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" strokeWidth="1.6" />
              <path d="M3.5 6.5l8.5 6.5 8.5-6.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
            </svg>
          </div>
          <input
            autoFocus={af}
            type="email"
            autoComplete="off"
            value={email}
            onChange={(e) => { setEmail(e.target.value); setErrMsg(''); }}
            onFocus={() => setEmailFocused(true)}
            onBlur={() => setEmailFocused(false)}
            placeholder={t.auth.emailPlaceholder}
            className="flex-1 bg-transparent outline-none text-[13.5px] text-white placeholder:text-white/30 py-2"
          />
          {emailOk && (
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none" className="mr-2 text-emerald-400">
              <path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
          )}
        </div>
        {showEmailSugs && (
          <div className="absolute left-0 right-0 top-full mt-1 z-20 rounded-lg bg-[#0F1E1A] border border-white/[0.08] shadow-[0_12px_32px_-8px_rgba(0,0,0,0.6)] overflow-hidden max-h-[184px] overflow-y-auto no-scrollbar">
            {emailSugs.map((sug) => (
              <button
                key={sug}
                type="button"
                onMouseDown={(e) => { e.preventDefault(); setEmail(sug); setErrMsg(''); }}
                className="w-full flex items-center gap-2 text-left px-3 py-2 text-[13px] text-white/65 hover:bg-emerald-400/[0.08] hover:text-emerald-200 transition-colors"
              >
                <svg width="13" height="13" viewBox="0 0 24 24" fill="none" className="shrink-0 text-white/25">
                  <rect x="3" y="5" width="18" height="14" rx="2" stroke="currentColor" strokeWidth="1.6" />
                  <path d="M3.5 6.5l8.5 6.5 8.5-6.5" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" />
                </svg>
                <span className="truncate">{sug}</span>
              </button>
            ))}
          </div>
        )}
      </div>
      {email && !emailOk && <p className="mt-1 text-[11px] text-rose-400/90">{t.auth.emailError}</p>}
    </>
  );

  const eyeBtn = (
    <button type="button" tabIndex={-1} onClick={() => setShowPwd(v => !v)} className="shrink-0 mr-2 text-white/35 hover:text-white/60 transition-colors">
      {showPwd ? (
        <svg width="15" height="15" viewBox="0 0 24 24" fill="none"><path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/><line x1="1" y1="1" x2="23" y2="23" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/></svg>
      ) : (
        <svg width="15" height="15" viewBox="0 0 24 24" fill="none"><path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8S1 12 1 12z" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round"/><circle cx="12" cy="12" r="3" stroke="currentColor" strokeWidth="1.6"/></svg>
      )}
    </button>
  );

  const passwordInput = (
    <>
      <label className="block text-[11px] text-white/45 font-mono tracking-[0.14em] uppercase mt-3 mb-1.5">{t.auth.passwordLabel}</label>
      <div className="flex items-center gap-1 p-1 rounded-lg bg-[#0A1512] border border-white/[0.08] focus-within:border-emerald-400/40 focus-within:shadow-[0_0_0_3px_rgba(16,185,129,0.1)] transition-all">
        <div className="pl-2 text-white/35">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
            <rect x="5" y="11" width="14" height="10" rx="2" stroke="currentColor" strokeWidth="1.6"/>
            <path d="M8 11V7a4 4 0 1 1 8 0v4" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
          </svg>
        </div>
        <input
          type={showPwd ? 'text' : 'password'}
          value={password}
          onChange={(e) => { setPassword(e.target.value); setErrMsg(''); }}
          placeholder={t.auth.passwordPlaceholder}
          className="flex-1 min-w-0 bg-transparent outline-none text-[13.5px] text-white placeholder:text-white/30 py-2"
        />
        {eyeBtn}
      </div>
    </>
  );

  const pwdStrength = (
    <div className="mt-2.5 grid grid-cols-2 gap-x-3 gap-y-1">
      {[
        ['min6', t.auth.pwdMin6],
        ['lower', t.auth.pwdLower],
        ['upper', t.auth.pwdUpper],
        ['digit', t.auth.pwdDigit],
      ].map(([key, label]) => (
        <div key={key} className="flex items-center gap-1.5 text-[11px]">
          {pwdChecks[key] ? (
            <svg width="10" height="10" viewBox="0 0 24 24" fill="none" className="text-emerald-400 shrink-0">
              <path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" strokeWidth="3" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
          ) : (
            <div className="w-[10px] h-[10px] rounded-full border border-white/20 shrink-0" />
          )}
          <span className={pwdChecks[key] ? 'text-emerald-300/80' : 'text-white/35'}>{label}</span>
        </div>
      ))}
    </div>
  );

  const spinner = (
    <svg className="animate-spin" width="14" height="14" viewBox="0 0 24 24" fill="none">
      <circle cx="12" cy="12" r="9" stroke="currentColor" strokeWidth="2.5" opacity="0.25"/>
      <path d="M21 12a9 9 0 0 0-9-9" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"/>
    </svg>
  );

  return (
    <>
      <button
        data-auth-trigger
        onClick={() => setOpen((v) => !v)}
        className="group inline-flex items-center gap-2 h-10 px-4 rounded-full bg-white/[0.04] hover:bg-emerald-400/[0.08] border border-white/[0.08] hover:border-emerald-400/35 text-white/80 hover:text-emerald-200 text-[13px] font-medium tracking-[-0.005em] transition-all duration-200 hover:shadow-[0_0_0_4px_rgba(16,185,129,0.08)]"
      >
        <svg width="15" height="15" viewBox="0 0 24 24" fill="none">
          <circle cx="12" cy="8" r="4" stroke="currentColor" strokeWidth="1.6"/>
          <path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
        </svg>
        <span>{t.auth.hint}</span>
      </button>

      <button
        onClick={() => { setDone(false); switchView('register'); setOpen(true); }}
        className="inline-flex items-center gap-2 h-10 px-4 rounded-full bg-emerald-500 hover:bg-emerald-400 text-[#052E21] text-[13px] font-semibold tracking-[-0.005em] transition-all duration-200 shadow-[0_4px_20px_-4px_rgba(16,185,129,0.5)]"
      >
        <span>{t.auth.registerBtn}</span>
      </button>

      {errMsg && ReactDOM.createPortal(<ErrorToast msg={errMsg} onClose={() => setErrMsg('')} />, document.body)}

      {open && ReactDOM.createPortal(
        <div className="fixed inset-0 z-[300] flex items-center justify-center bg-black/60 backdrop-blur-sm animate-[fadeIn_0.15s_ease]"
          onMouseDown={e => { mouseDownOnBackdrop.current = (e.target === e.currentTarget); }}
          onClick={e => { if (e.target === e.currentTarget && mouseDownOnBackdrop.current) setOpen(false); mouseDownOnBackdrop.current = false; }}
        >
          <div className="w-[380px] rounded-2xl bg-[#0F1E1A] border border-emerald-400/15 shadow-[0_24px_60px_-20px_rgba(0,0,0,0.7),0_0_0_1px_rgba(16,185,129,0.06)] p-5">

          {/* ── 成功状态 ── */}
          {done ? (
            <div className="flex flex-col items-center py-6 text-center">
              <div className="w-10 h-10 rounded-full bg-emerald-500/15 border border-emerald-400/40 flex items-center justify-center mb-3">
                <svg width="18" height="18" viewBox="0 0 24 24" fill="none">
                  <path d="M5 12.5l4.5 4.5L19 7.5" stroke="#6EE7B7" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round" />
                </svg>
              </div>
              <div className="text-[14px] text-white font-medium">{doneMsg}</div>
              <div className="text-[12px] text-white/45 mt-1">{email}</div>
            </div>
          ) : view === 'login' ? (
            /* ── 登录视图 ── */
            <form onSubmit={handleLogin}>
              {promptMsg && (
                <div className="flex items-center gap-2 p-3 rounded-lg bg-emerald-500/10 border border-emerald-400/20 mb-4">
                  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" className="shrink-0 text-emerald-400">
                    <path d="M12 2l1.2 3.3 3.5.3-2.6 2.3.8 3.4L12 9.2l-2.9 2.1.8-3.4-2.6-2.3 3.5-.3L12 2z" fill="currentColor"/>
                    <path d="M5 10l.7 2 2.1.2-1.6 1.3.5 2L5 14.3 3.3 15.5l.5-2L2.2 12.2l2.1-.2L5 10zM19 10l.7 2 2.1.2-1.6 1.3.5 2L19 14.3l-1.7 1.2.5-2-1.6-1.3 2.1-.2L19 10zM8 16l.5 1.4 1.5.1-1.1.9.3 1.4L8 19l-1.2.8.3-1.4-1.1-.9 1.5-.1L8 16zM16 16l.5 1.4 1.5.1-1.1.9.3 1.4-1.2-.8-1.2.8.3-1.4-1.1-.9 1.5-.1L16 16z" fill="currentColor" opacity="0.6"/>
                  </svg>
                  <span className="text-[12.5px] text-emerald-200/90">{promptMsg}</span>
                </div>
              )}
              {emailInput(true)}
              {passwordInput}
              {showLoginPwdHint && pwdStrength}

              <div className="flex justify-end mt-1.5">
                <button type="button" onClick={() => switchView('reset')} className="text-[11.5px] text-emerald-300/70 hover:text-emerald-300 transition-colors">
                  {t.auth.forgotPassword}
                </button>
              </div>

              <button
                type="submit"
                disabled={!canLogin}
                className={`mt-3 w-full h-10 rounded-lg text-[13px] font-semibold transition-all inline-flex items-center justify-center gap-2 ${
                  canLogin
                    ? 'bg-emerald-500 hover:bg-emerald-400 text-[#052E21] shadow-[0_4px_20px_-4px_rgba(16,185,129,0.5)]'
                    : 'bg-white/[0.04] text-white/30 cursor-not-allowed'
                }`}
              >
                {loading ? <>{spinner} {t.auth.submitting}</> : t.auth.loginBtn}
              </button>

              <p className="mt-3 text-[12px] text-white/45 text-center">
                {t.auth.noAccount}<button type="button" onClick={() => switchView('register')} className="text-emerald-300 hover:text-emerald-200 transition-colors font-medium">{t.auth.goRegister}</button>
              </p>
              <p className="mt-2 text-[11px] text-white/35 text-center leading-relaxed">{t.auth.terms}</p>
            </form>

          ) : view === 'register' ? (
            /* ── 注册视图（单页：邮箱 + 验证码 + 密码） ── */
            <form onSubmit={handleRegister}>
              {emailInput(true)}

              {/* 验证码输入 + 发送按钮 */}
              <label className="block text-[11px] text-white/45 font-mono tracking-[0.14em] uppercase mt-3 mb-1.5">{t.auth.codeLabel}</label>
              <div className="flex items-center gap-2 p-1 rounded-lg bg-[#0A1512] border border-white/[0.08] focus-within:border-emerald-400/40 focus-within:shadow-[0_0_0_3px_rgba(16,185,129,0.1)] transition-all">
                <div className="pl-2 text-white/35">
                  <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
                    <rect x="4" y="4" width="16" height="16" rx="2" stroke="currentColor" strokeWidth="1.6"/>
                    <path d="M9 12h6" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
                  </svg>
                </div>
                <input
                  type="text"
                  inputMode="numeric"
                  maxLength={6}
                  value={otpCode}
                  onChange={(e) => { setOtpCode(e.target.value.replace(/\D/g, '')); setErrMsg(''); }}
                  placeholder={t.auth.codePlaceholder}
                  className={`flex-1 bg-transparent outline-none text-[13.5px] text-white placeholder:text-white/30 py-2 ${otpCode ? 'font-mono tracking-[0.3em]' : ''}`}
                />
                {countdown > 0 ? (
                  <span className="shrink-0 mr-2 text-[11.5px] text-white/30 font-mono">{countdown}s</span>
                ) : (
                  <button type="button" onClick={handleSendCode} disabled={!emailOk || loading} className={`shrink-0 mr-1 px-3 py-1.5 rounded-md text-[11.5px] font-medium transition-colors whitespace-nowrap ${emailOk && !loading ? 'bg-emerald-500/15 text-emerald-300 hover:bg-emerald-500/25' : 'text-white/20 cursor-not-allowed'}`}>{t.auth.sendCode}</button>
                )}
              </div>
              {otpSent && (
                <p className="mt-1.5 text-[11px] text-emerald-300/60">{t.auth.codeSent(email)}</p>
              )}

              {passwordInput}
              {pwdStrength}

              <button
                type="submit"
                disabled={!canRegister}
                className={`mt-4 w-full h-10 rounded-lg text-[13px] font-semibold transition-all inline-flex items-center justify-center gap-2 ${
                  canRegister
                    ? 'bg-emerald-500 hover:bg-emerald-400 text-[#052E21] shadow-[0_4px_20px_-4px_rgba(16,185,129,0.5)]'
                    : 'bg-white/[0.04] text-white/30 cursor-not-allowed'
                }`}
              >
                {loading ? <>{spinner} {t.auth.submitting}</> : t.auth.registerBtn}
              </button>

              <p className="mt-3 text-[12px] text-white/45 text-center">
                {t.auth.hasAccount}<button type="button" onClick={() => switchView('login')} className="text-emerald-300 hover:text-emerald-200 transition-colors font-medium">{t.auth.goLogin}</button>
              </p>
              <p className="mt-2 text-[11px] text-white/35 text-center leading-relaxed">{t.auth.terms}</p>
            </form>

          ) : (
            /* ── 重置密码视图 ── */
            <form onSubmit={handleReset}>
              <h3 className="text-[15px] text-white font-semibold mb-2">{t.auth.resetTitle}</h3>
              <p className="text-[12.5px] text-white/50 mb-4 leading-relaxed">{t.auth.resetDesc}</p>

              {emailInput(true)}

              {resetSent ? (
                <div className="mt-3 p-3 rounded-lg bg-emerald-500/10 border border-emerald-400/25">
                  <p className="text-[12px] text-emerald-300/90 leading-relaxed flex items-start gap-2">
                    <svg width="14" height="14" viewBox="0 0 24 24" fill="none" className="shrink-0 mt-0.5">
                      <path d="M5 12.5l4.5 4.5L19 7.5" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round" strokeLinejoin="round"/>
                    </svg>
                    {t.auth.resetSent(email)}
                  </p>
                </div>
              ) : (
                <button
                  type="submit"
                  disabled={!canReset}
                  className={`mt-4 w-full h-10 rounded-lg text-[13px] font-semibold transition-all inline-flex items-center justify-center gap-2 ${
                    canReset
                      ? 'bg-emerald-500 hover:bg-emerald-400 text-[#052E21] shadow-[0_4px_20px_-4px_rgba(16,185,129,0.5)]'
                      : 'bg-white/[0.04] text-white/30 cursor-not-allowed'
                  }`}
                >
                  {loading ? <>{spinner} {t.auth.submitting}</> : t.auth.sendReset}
                </button>
              )}

              <p className="mt-3 text-center">
                <button type="button" onClick={() => switchView('login')} className="text-[12px] text-emerald-300/70 hover:text-emerald-300 transition-colors">
                  {t.auth.backToLogin}
                </button>
              </p>
            </form>
          )}
          </div>
        </div>,
        document.body
      )}
    </>
  );
}

// 已登录用户菜单
function UserMenu({ user, signOut, t }) {
  const [open, setOpen] = React.useState(false);
  const ref = React.useRef(null);
  const email = user.email || '';
  const initial = email.charAt(0).toUpperCase();
  const hue = email.charCodeAt(0) % 60 + 140;
  const [avatarUrl, setAvatarUrl] = React.useState(null);
  const [nickname, setNickname] = React.useState('');

  // 读取头像和昵称，并监听更新
  React.useEffect(() => {
    window.supabaseClient
      .from('profiles')
      .select('nickname, avatar_url')
      .eq('id', user.id)
      .single()
      .then(({ data }) => {
        if (data?.avatar_url) setAvatarUrl(data.avatar_url);
        if (data?.nickname) setNickname(data.nickname);
      })
      .catch(() => {});

    const onUpdate = (e) => {
      if (e.detail?.avatar_url !== undefined) setAvatarUrl(e.detail.avatar_url);
      if (e.detail?.nickname !== undefined) setNickname(e.detail.nickname);
    };
    window.addEventListener('kiwvo:profile-updated', onUpdate);
    return () => window.removeEventListener('kiwvo:profile-updated', onUpdate);
  }, [user.id]);

  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (ref.current && !ref.current.contains(e.target)) setOpen(false); };
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  const openProfile = () => {
    setOpen(false);
    window.dispatchEvent(new CustomEvent('kiwvo:open-profile'));
  };

  const displayName = nickname || email.split('@')[0];

  return (
    <div ref={ref} className="relative">
      <button
        onClick={() => setOpen(v => !v)}
        className="group flex items-center gap-2 h-10 pl-1 pr-3 rounded-full bg-white/[0.04] hover:bg-emerald-400/[0.08] border border-white/[0.08] hover:border-emerald-400/35 transition-all duration-200"
      >
        <div
          className="w-8 h-8 rounded-full overflow-hidden flex items-center justify-center text-[12px] font-semibold text-emerald-100 shrink-0"
          style={{ background: avatarUrl ? 'transparent' : `oklch(0.32 0.08 ${hue})` }}
        >
          {avatarUrl
            ? <img src={avatarUrl} alt="" className="w-full h-full object-cover" />
            : initial
          }
        </div>
        <span className="text-[12.5px] text-white/70 group-hover:text-emerald-200 transition-colors max-w-[120px] truncate hidden sm:block">
          {displayName}
        </span>
        <svg width="11" height="11" viewBox="0 0 24 24" fill="none" className={`text-white/40 transition-transform ${open ? 'rotate-180' : ''}`}>
          <path d="M6 9l6 6 6-6" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" />
        </svg>
      </button>

      {open && (
        <div className="absolute top-full right-0 mt-2 w-[220px] rounded-xl bg-[#0F1E1A] border border-emerald-400/15 shadow-[0_24px_60px_-20px_rgba(0,0,0,0.7)] p-2 z-50 animate-[fadeIn_0.15s_ease]">
          <div className="px-3 py-2 border-b border-white/[0.06] mb-1">
            <div className="text-[12.5px] text-white/80 font-medium truncate">{displayName}</div>
            <div className="text-[11px] text-white/35 font-mono mt-0.5 truncate">{email}</div>
          </div>
          <button
            onClick={openProfile}
            className="w-full flex items-center gap-2.5 h-9 px-3 rounded-lg text-[13px] text-white/60 hover:text-emerald-300 hover:bg-emerald-400/[0.06] transition-colors"
          >
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
              <circle cx="12" cy="8" r="4" stroke="currentColor" strokeWidth="1.6"/>
              <path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round"/>
            </svg>
            {t.auth.profile}
          </button>
          <button
            onClick={() => { setOpen(false); signOut(); }}
            className="w-full flex items-center gap-2.5 h-9 px-3 rounded-lg text-[13px] text-white/60 hover:text-rose-300 hover:bg-rose-500/[0.08] transition-colors"
          >
            <svg width="14" height="14" viewBox="0 0 24 24" fill="none">
              <path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4M16 17l5-5-5-5M21 12H9" stroke="currentColor" strokeWidth="1.6" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            {t.auth.logout}
          </button>
        </div>
      )}
    </div>
  );
}

function Navbar() {
  const [scrolled, setScrolled] = React.useState(false);
  const [lang, setLang] = useLang();
  const t = I18N[lang];
  const { user, loading, signOut } = useGlobalAuth();

  React.useEffect(() => {
    const onScroll = () => setScrolled(window.scrollY > 8);
    window.addEventListener('scroll', onScroll);
    return () => window.removeEventListener('scroll', onScroll);
  }, []);

  const links = [
    { href: '#download', label: t.nav.download },
    { href: '#live', label: t.nav.live },
    { href: '#community', label: t.nav.community },
  ];

  // 平滑滚动
  const handleNav = (e, href) => {
    e.preventDefault();
    const el = document.querySelector(href);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <header
      className={`fixed top-0 inset-x-0 z-50 transition-all duration-300 ${
        scrolled ? 'bg-[#0A1512]/85 backdrop-blur-xl border-b border-emerald-400/[0.06]' : 'bg-transparent'
      }`}
    >
      <div className="max-w-[1280px] mx-auto px-8 h-[68px] flex items-center justify-between">
        <a href="#top" onClick={(e) => handleNav(e, '#top')} className="flex items-center gap-2.5 group">
          <KiwvoLogo size={26} />
        </a>

        <nav className="hidden md:flex items-center gap-10">
          {links.map((l) => (
            <a
              key={l.href}
              href={l.href}
              onClick={(e) => handleNav(e, l.href)}
              className="text-[13.5px] text-white/55 hover:text-white transition-colors tracking-wide"
            >
              {l.label}
            </a>
          ))}
        </nav>

        <div className="flex items-center gap-3">
          <LangSwitch lang={lang} setLang={setLang} />
          {loading ? (
            <div className="w-10 h-10 rounded-full bg-white/[0.04] animate-pulse" />
          ) : user ? (
            <UserMenu user={user} signOut={signOut} t={t} />
          ) : (
            <EmailLogin t={t} lang={lang} />
          )}
        </div>
      </div>
    </header>
  );
}

window.Navbar = Navbar;
