// frontend/js/auth-react.jsx
// 全局共享的 React 鉴权与档案同步模块
// NOTE: 不在顶层解构 React hooks，避免与页面脚本冲突

function getMysticGuestId() {
    let guestId = localStorage.getItem('mystic_guest_id');
    if (!guestId) {
        const randomPart = window.crypto?.randomUUID
            ? window.crypto.randomUUID().replace(/-/g, '')
            : `${Date.now().toString(36)}${Math.random().toString(36).slice(2)}${Math.random().toString(36).slice(2)}`;
        guestId = `guest_${randomPart}`;
        localStorage.setItem('mystic_guest_id', guestId);
    }
    return guestId;
}

function getMysticCalculationHeaders(contentType = true) {
    const headers = {'X-Guest-ID': getMysticGuestId()};
    const token = localStorage.getItem('mystic_token');
    if (token) headers.Authorization = `Bearer ${token}`;
    if (contentType) headers['Content-Type'] = 'application/json';
    return headers;
}

async function syncMysticGuestData(token) {
    const guestId = localStorage.getItem('mystic_guest_id');
    if (guestId) {
        const claimResponse = await fetch('/api/auth/claim-guest', {
            method: 'POST',
            headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`},
            body: JSON.stringify({guest_id: guestId})
        });
        if (!claimResponse.ok) throw new Error('游客测算记录归档失败，请稍后重试');
    }

    const history = JSON.parse(localStorage.getItem('mystic_test_history') || '[]');
    if (history.length) {
        const results = history.map(item => ({
            test_key: item.testKey,
            test_title: item.testTitle,
            result_name: item.resultName,
            summary: item.summary,
            score: Number(item.score) || 0,
            icon: item.icon || '',
            completed_at: item.completedAt || item.date || null,
        })).filter(item => item.test_key && item.test_title && item.result_name && item.summary);
        if (results.length) {
            const syncResponse = await fetch('/api/user/quick-tests/sync', {
                method: 'POST',
                headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`},
                body: JSON.stringify({results: results.slice(0, 30)})
            });
            if (!syncResponse.ok) throw new Error('快速测试记录同步失败，请稍后重试');
        }
    }
}

/**
 * 核心 Auth Hook
 * 用于检查登录状态、获取档案数据、处理登录注册登出
 */
function useAuth() {
    const { useState, useEffect } = React;
    const [user, setUser] = useState(null);
    const [profile, setProfile] = useState(null);
    const [loading, setLoading] = useState(true);

    const fetchProfile = async (token) => {
        try {
            const res = await fetch('/api/user/profile', {
                headers: { 'Authorization': `Bearer ${token}` }
            });
            if (res.ok) {
                const data = await res.json();
                setProfile(data.data);
                localStorage.setItem('mystic_profile', JSON.stringify(data.data));
            }
        } catch (e) {
            console.error("Profile fetch failed:", e);
        }
    };

    const checkLogin = async () => {
        setLoading(true);
        const token = localStorage.getItem('mystic_token');
        if (!token) {
            setUser(null);
            setProfile(null);
            setLoading(false);
            return;
        }

        try {
            const res = await fetch('/api/auth/me', {
                headers: { 'Authorization': `Bearer ${token}` }
            });
            if (res.ok) {
                const userData = await res.json();
                setUser(userData);
                await fetchProfile(token);
            } else {
                localStorage.removeItem('mystic_token');
                setUser(null);
            }
        } catch (e) {
            console.error(e);
        } finally {
            setLoading(false);
        }
    };

    useEffect(() => {
        // 先尝试从本地读取
        const cachedProfile = localStorage.getItem('mystic_profile');
        if (cachedProfile) {
            try {
                setProfile(JSON.parse(cachedProfile));
            } catch (e) {}
        }
        checkLogin();
    }, []);

    const logout = async () => {
        const token = localStorage.getItem('mystic_token');
        if (token) {
            fetch('/api/auth/logout', { method: 'POST', headers: { 'Authorization': `Bearer ${token}` } });
        }
        localStorage.removeItem('mystic_token');
        localStorage.removeItem('mystic_profile');
        localStorage.removeItem('mystic_guest_id');
        setUser(null);
        setProfile(null);
    };

    const silentUpdateProfile = async (updateData) => {
        const token = localStorage.getItem('mystic_token');
        if (!token || !updateData) return;
        
        try {
            const res = await fetch('/api/user/profile', {
                method: 'POST',
                headers: { 
                    'Authorization': `Bearer ${token}`,
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify(updateData)
            });
            if (res.ok) {
                await fetchProfile(token);
            }
        } catch (e) {
            console.error("Silent sync failed", e);
        }
    };

    return { user, profile, loading, checkLogin, logout, silentUpdateProfile };
}

/**
 * 通用精美登录/注册弹窗组件
 */
function LoginModal({ isOpen, onClose, onSuccess, initialMode = 'login' }) {
    const { useState, useEffect } = React;
    const [mode, setMode] = useState('password');
    const [methods, setMethods] = useState({sms_enabled: false, password_enabled: true});
    const [phone, setPhone] = useState('');
    const [code, setCode] = useState('');
    const [username, setUsername] = useState('');
    const [password, setPassword] = useState('');
    const [nickname, setNickname] = useState('');
    const [birthDate, setBirthDate] = useState('');
    const [birthTime, setBirthTime] = useState('12:00');
    const [gender, setGender] = useState('女');
    const [cityName, setCityName] = useState('北京');
    const [realName, setRealName] = useState('');
    const [mbti, setMbti] = useState('');
    const [smsNeedsProfile, setSmsNeedsProfile] = useState(false);
    const [newPassword, setNewPassword] = useState('');
    const [error, setError] = useState('');
    const [isSubmitting, setIsSubmitting] = useState(false);
    const [sendingCode, setSendingCode] = useState(false);
    const [cooldown, setCooldown] = useState(0);

    useEffect(() => {
        if (!isOpen) return;
        setError('');
        setSmsNeedsProfile(false);
        fetch('/api/auth/methods')
            .then(res => res.json())
            .then(data => {
                setMethods(data);
                setMode(initialMode === 'register' ? 'register' : (data.sms_enabled ? 'sms' : 'password'));
            })
            .catch(() => setMode(initialMode === 'register' ? 'register' : 'password'));
    }, [isOpen, initialMode]);

    useEffect(() => {
        if (cooldown <= 0) return;
        const timer = setInterval(() => setCooldown(value => Math.max(0, value - 1)), 1000);
        return () => clearInterval(timer);
    }, [cooldown]);

    if (!isOpen) return null;

    const readResponse = async (res) => {
        const data = await res.json().catch(() => ({}));
        if (!res.ok) {
            const detail = Array.isArray(data.detail)
                ? data.detail.map(item => item.msg).filter(Boolean).join('；')
                : data.detail;
            throw new Error(detail || data.message || '请求失败，请稍后再试');
        }
        return data;
    };

    const finishLogin = async (data) => {
        localStorage.setItem('mystic_token', data.token);
        await syncMysticGuestData(data.token);
        if (onSuccess) await onSuccess();
        onClose();
    };

    const registrationProfile = () => ({
        nickname: nickname.trim(),
        real_name: realName.trim() || null,
        birth_date: birthDate,
        birth_time: birthTime,
        gender,
        city_name: cityName.trim(),
        mbti: mbti || null,
    });

    const validateRegistrationProfile = () => {
        if (!nickname.trim()) throw new Error('请填写昵称');
        if (!birthDate) throw new Error('请选择出生日期');
        if (!birthTime) throw new Error('请选择出生时间');
        if (!gender) throw new Error('请选择性别');
        if (!cityName.trim()) throw new Error('请填写出生城市');
    };

    const sendCode = async () => {
        if (!/^1[3-9]\d{9}$/.test(phone)) return setError('请输入正确的手机号');
        setError('');
        setSendingCode(true);
        try {
            const purpose = mode === 'reset' ? 'reset' : 'login';
            const res = await fetch('/api/auth/sms/send', {
                method: 'POST',
                headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({phone, purpose})
            });
            const data = await readResponse(res);
            setCooldown(60);
            if (data.debug_code) setCode(data.debug_code);
            setError('验证码已发送');
        } catch (err) {
            setError(err.message);
        } finally {
            setSendingCode(false);
        }
    };

    const handleSubmit = async (event) => {
        event.preventDefault();
        setError('');
        setIsSubmitting(true);
        try {
            if (mode === 'sms') {
                if (!/^1[3-9]\d{9}$/.test(phone)) throw new Error('请输入正确的手机号');
                if (!/^\d{6}$/.test(code)) throw new Error('请输入6位验证码');
                if (smsNeedsProfile) validateRegistrationProfile();
                const res = await fetch('/api/auth/sms/login', {
                    method: 'POST', headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({phone, code, ...(smsNeedsProfile ? registrationProfile() : {})})
                });
                if (res.status === 409) {
                    const data = await res.json().catch(() => ({}));
                    setSmsNeedsProfile(true);
                    throw new Error(data.detail || '首次使用请完善个人档案');
                }
                return await finishLogin(await readResponse(res));
            }
            if (mode === 'reset') {
                if (newPassword.length < 8) throw new Error('新密码至少8位');
                const res = await fetch('/api/auth/password/reset', {
                    method: 'POST', headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({phone, code, new_password: newPassword})
                });
                await readResponse(res);
                setMode('password');
                setError('密码已重置，请使用账号密码登录');
                return;
            }
            if (username.trim().length < 2) throw new Error('账号至少2个字符');
            const minimum = mode === 'register' ? 8 : 6;
            if (password.length < minimum) throw new Error(`密码至少${minimum}位`);
            if (mode === 'register') validateRegistrationProfile();
            const endpoint = mode === 'register' ? '/api/auth/register' : '/api/auth/login';
            const res = await fetch(endpoint, {
                method: 'POST', headers: {'Content-Type': 'application/json'},
                body: JSON.stringify({
                    username: username.trim(), password,
                    ...(mode === 'register' ? registrationProfile() : {})
                })
            });
            await readResponse(res);
            if (mode === 'register') {
                const loginRes = await fetch('/api/auth/login', {
                    method: 'POST', headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({username: username.trim(), password})
                });
                return await finishLogin(await readResponse(loginRes));
            }
            return await finishLogin(await readResponse(res));
        } catch (err) {
            setError(err.message);
        } finally {
            setIsSubmitting(false);
        }
    };

    return (
        <div className="fixed inset-0 z-[10000] flex items-center justify-center px-4 bg-black/60 backdrop-blur-sm transition-all">
            <div className="bg-white rounded-[24px] p-6 w-full max-w-[340px] max-h-[88dvh] overflow-y-auto no-scrollbar relative shadow-[0_20px_50px_rgba(0,0,0,0.3)] animate-[scaleIn_0.3s_ease-out]">
                <button onClick={onClose} className="absolute top-4 right-4 w-8 h-8 flex items-center justify-center rounded-full bg-slate-100 text-slate-500 hover:bg-slate-200 transition-colors">
                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
                </button>
                <div className="text-center mb-5 pr-8">
                    <h2 className="text-xl font-black text-slate-800">登录知了</h2>
                    <p className="text-xs text-slate-500 mt-1.5">同步记录，让陪伴记得住你</p>
                </div>

                {methods.sms_enabled && mode !== 'register' && (
                    <div className="flex bg-slate-100 rounded-xl p-1 mb-4">
                        <button type="button" onClick={() => {setMode('sms'); setError('');}} className={`flex-1 py-2 text-xs font-bold rounded-lg ${mode === 'sms' ? 'bg-white text-purple-700 shadow-sm' : 'text-slate-500'}`}>手机号登录</button>
                        <button type="button" onClick={() => {setMode('password'); setError('');}} className={`flex-1 py-2 text-xs font-bold rounded-lg ${mode === 'password' || mode === 'reset' ? 'bg-white text-purple-700 shadow-sm' : 'text-slate-500'}`}>账号密码</button>
                    </div>
                )}

                <form onSubmit={handleSubmit} className="flex flex-col gap-3">
                    {(mode === 'sms' || mode === 'reset') ? (
                        <>
                            <input inputMode="numeric" autoComplete="tel" value={phone} onChange={e => setPhone(e.target.value.replace(/\D/g, '').slice(0, 11))} placeholder="手机号" className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                            <div className="flex gap-2">
                                <input inputMode="numeric" autoComplete="one-time-code" value={code} onChange={e => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))} placeholder="6位验证码" className="min-w-0 flex-1 bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                                <button type="button" onClick={sendCode} disabled={sendingCode || cooldown > 0} className="w-[104px] rounded-xl bg-purple-50 text-purple-700 text-xs font-bold disabled:text-slate-400">{cooldown > 0 ? `${cooldown}s` : (sendingCode ? '发送中' : '获取验证码')}</button>
                            </div>
                            {mode === 'reset' && <input type="password" autoComplete="new-password" value={newPassword} onChange={e => setNewPassword(e.target.value)} placeholder="设置新密码（至少8位）" className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />}
                        </>
                    ) : (
                        <>
                            <input autoComplete="username" value={username} onChange={e => setUsername(e.target.value)} placeholder="账号" className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                            <input type="password" autoComplete={mode === 'register' ? 'new-password' : 'current-password'} value={password} onChange={e => setPassword(e.target.value)} placeholder={mode === 'register' ? '密码（至少8位）' : '密码'} className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                        </>
                    )}

                    {(mode === 'register' || (mode === 'sms' && smsNeedsProfile)) && (
                        <div className="flex flex-col gap-2.5 pt-1 border-t border-slate-100">
                            <p className="text-[11px] font-bold text-slate-500 pt-1">基础档案</p>
                            <input value={nickname} onChange={e => setNickname(e.target.value)} placeholder="昵称（必填）" className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                            <input value={realName} onChange={e => setRealName(e.target.value)} placeholder="真实姓名（选填）" className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                            <div className="grid grid-cols-2 gap-2">
                                <input type="date" value={birthDate} onChange={e => setBirthDate(e.target.value)} className="min-w-0 w-full bg-slate-50 px-3 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                                <input type="time" value={birthTime} onChange={e => setBirthTime(e.target.value)} className="min-w-0 w-full bg-slate-50 px-3 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                            </div>
                            <div className="flex gap-4 px-1 text-xs font-bold text-slate-600">
                                {['女','男','其他'].map(item => <label key={item} className="flex items-center gap-1.5"><input type="radio" checked={gender===item} onChange={()=>setGender(item)} className="accent-purple-500" />{item}</label>)}
                            </div>
                            <input value={cityName} onChange={e => setCityName(e.target.value)} placeholder="出生城市（必填）" className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-purple-200" />
                            <select value={mbti} onChange={e => setMbti(e.target.value)} className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none text-slate-600">
                                <option value="">MBTI（选填）</option>
                                {['INTJ','INTP','ENTJ','ENTP','INFJ','INFP','ENFJ','ENFP','ISTJ','ISFJ','ESTJ','ESFJ','ISTP','ISFP','ESTP','ESFP'].map(item => <option key={item} value={item}>{item}</option>)}
                            </select>
                        </div>
                    )}

                    {error && <p className={`text-xs text-center ${error.includes('已发送') || error.includes('已重置') ? 'text-emerald-600' : 'text-rose-500'}`}>{error}</p>}
                    <button disabled={isSubmitting} type="submit" className="w-full bg-gradient-to-r from-purple-500 to-rose-400 text-white font-bold text-sm py-3 rounded-xl mt-1 shadow-lg shadow-purple-200/50 disabled:opacity-60">
                        {isSubmitting ? '请稍候...' : mode === 'sms' ? '登录 / 注册' : mode === 'reset' ? '重置密码' : mode === 'register' ? '注册并登录' : '登录'}
                    </button>
                </form>

                <div className="flex justify-center gap-4 mt-4 text-xs">
                    {mode !== 'register' && <button type="button" onClick={() => {setMode('register'); setError('');}} className="text-slate-500">注册账号</button>}
                    {mode === 'register' && <button type="button" onClick={() => {setMode(methods.sms_enabled ? 'sms' : 'password'); setError('');}} className="text-slate-500">返回登录</button>}
                    {methods.sms_enabled && (mode === 'password' || mode === 'register') && <button type="button" onClick={() => {setMode('reset'); setError('');}} className="text-purple-600">忘记密码</button>}
                </div>
                <p className="text-[10px] leading-5 text-center text-slate-400 mt-5">登录即表示同意 <a href="/terms.html" className="underline">用户协议</a> 与 <a href="/privacy.html" className="underline">隐私政策</a></p>
            </div>
            <style dangerouslySetInnerHTML={{__html: `
                @keyframes scaleIn { from { opacity: 0; transform: scale(0.95) translateY(10px); } to { opacity: 1; transform: scale(1) translateY(0); } }
            `}} />
        </div>
    );
}

/**
 * 独立资料修改弹窗组件 ProfileEditModal
 */
function ProfileEditModal({ isOpen, onClose, onSuccess }) {
    const { useState, useEffect } = React;
    const [profileForm, setProfileForm] = useState({
        nickname: '',
        real_name: '',
        gender: '女',
        birth_date: '',
        birth_time: '12:00',
        city_name: '北京',
        mbti: '',
        avatar_seed: 'zhiliao-avatar'
    });
    const [publicId, setPublicId] = useState('');
    const [error, setError] = useState('');
    const [isSubmitting, setIsSubmitting] = useState(false);
    const [isLoading, setIsLoading] = useState(true);

    useEffect(() => {
        if (isOpen) {
            setIsLoading(true);
            const token = localStorage.getItem('mystic_token');
            fetch('/api/user/profile', {
                headers: { 'Authorization': `Bearer ${token}` }
            })
            .then(res => res.json())
            .then(data => {
                if (data.success && data.data) {
                    setProfileForm({
                        nickname: data.data.nickname || '',
                        real_name: data.data.real_name || '',
                        gender: data.data.gender || '女',
                        birth_date: data.data.birth_date || '',
                        birth_time: data.data.birth_time || '12:00',
                        city_name: data.data.city_name || '北京',
                        mbti: data.data.mbti || '',
                        avatar_seed: data.data.avatar_seed || `zhiliao-${data.data.public_id || 'avatar'}`
                    });
                    setPublicId(data.data.public_id || '');
                }
            })
            .catch(() => setError("获取档案失败"))
            .finally(() => setIsLoading(false));
        }
    }, [isOpen]);

    if (!isOpen) return null;

    const handleProfileSubmit = async (e) => {
        e.preventDefault();
        setError('');
        if (!profileForm.nickname.trim()) return setError("请填写昵称");
        if (!profileForm.birth_date) return setError("请选择出生日期");
        if (!profileForm.birth_time) return setError("请选择出生时间");
        if (!profileForm.gender) return setError("请选择性别");
        if (!profileForm.city_name.trim()) return setError("请填写出生城市");

        setIsSubmitting(true);
        try {
            const token = localStorage.getItem('mystic_token');
            const profilePayload = {
                ...profileForm,
                mbti: profileForm.mbti || null,
                real_name: profileForm.real_name?.trim() || null,
                city_name: profileForm.city_name?.trim() || null
            };
            const res = await fetch('/api/user/profile?complete=true', {
                method: 'POST',
                headers: { 
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${token}`
                },
                body: JSON.stringify(profilePayload)
            });
            if (!res.ok) {
                const data = await res.json().catch(() => ({}));
                const detail = Array.isArray(data.detail)
                    ? data.detail.map(item => item.msg).filter(Boolean).join('；')
                    : data.detail;
                throw new Error(detail || '档案保存失败');
            }
            if (onSuccess) await onSuccess();
            onClose();
        } catch (err) {
            setError(err.message);
        } finally {
            setIsSubmitting(false);
        }
    };

    return (
        <div className="fixed inset-0 z-[10000] flex items-center justify-center px-3 py-3 bg-black/60 backdrop-blur-sm transition-all">
            <div
                className="bg-white rounded-[24px] p-5 w-[92%] max-w-[360px] overflow-hidden relative shadow-[0_20px_50px_rgba(0,0,0,0.3)] animate-[scaleIn_0.3s_ease-out] flex flex-col"
                style={{maxHeight:'calc(var(--app-height, 100dvh) - 24px)'}}
            >
                <button onClick={onClose} className="absolute top-4 right-4 w-8 h-8 flex items-center justify-center rounded-full bg-slate-100 text-slate-500 hover:bg-slate-200 transition-colors">
                    <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" d="M6 18L18 6M6 6l12 12"></path></svg>
                </button>

                <div className="flex flex-col min-h-0">
                    <div className="text-center mb-4 shrink-0">
                        <h2 className="text-xl font-black text-rose-950 tracking-wider">修改个人档案</h2>
                    </div>
                    
                    {isLoading ? (
                        <div className="flex justify-center py-10"><div className="w-6 h-6 border-2 border-rose-500 border-t-transparent rounded-full animate-spin"></div></div>
                    ) : (
                        <form onSubmit={handleProfileSubmit} className="flex flex-col gap-3 min-h-0 overflow-y-auto overscroll-contain px-1 pb-[env(safe-area-inset-bottom,0px)]">
                            <div className="flex flex-col items-center mb-1">
                                <img src={`https://api.dicebear.com/7.x/notionists/svg?seed=${encodeURIComponent(profileForm.avatar_seed)}&backgroundColor=f5f5f5`} className="w-20 h-20 rounded-full bg-slate-100 border-4 border-white shadow-md" />
                                <button type="button" onClick={() => setProfileForm({...profileForm, avatar_seed: `zhiliao-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`})} className="mt-2 px-3 py-1.5 rounded-full bg-purple-50 text-purple-600 text-[11px] font-bold">换一个头像</button>
                                {publicId && <span className="text-[9px] text-slate-400 font-bold mt-1">知了号 {publicId.slice(0, 8).toUpperCase()}</span>}
                            </div>
                            <input type="text" value={profileForm.nickname} onChange={e => setProfileForm({...profileForm, nickname: e.target.value})} placeholder="您的称呼 (昵称)" required className="w-full bg-slate-50 px-5 py-3 rounded-xl border-none text-sm font-medium focus:ring-2 focus:ring-rose-200 focus:bg-white outline-none transition-all placeholder-slate-400" />
                            
                            <div>
                                <input type="text" value={profileForm.real_name} onChange={e => setProfileForm({...profileForm, real_name: e.target.value})} placeholder="真实姓名 (可选)" className="w-full bg-slate-50 px-5 py-3 rounded-xl border-none text-sm font-medium focus:ring-2 focus:ring-rose-200 focus:bg-white outline-none transition-all placeholder-slate-400" />
                                <p className="text-[10px] text-rose-500/80 ml-2 mt-1">💡 真实姓名会算的准</p>
                            </div>

                            <div className="flex gap-6 px-2 py-1">
                                <label className="flex items-center gap-2 text-sm text-slate-600 cursor-pointer font-bold">
                                    <input type="radio" checked={profileForm.gender === '男'} onChange={() => setProfileForm({...profileForm, gender: '男'})} className="accent-rose-500 w-4 h-4" /> 男
                                </label>
                                <label className="flex items-center gap-2 text-sm text-slate-600 cursor-pointer font-bold">
                                    <input type="radio" checked={profileForm.gender === '女'} onChange={() => setProfileForm({...profileForm, gender: '女'})} className="accent-rose-500 w-4 h-4" /> 女
                                </label>
                            </div>

                            <div className="flex gap-2">
                                <div className="flex-1">
                                    <label className="block text-[10px] text-slate-500 mb-1 ml-1 font-bold">出生日期 <span className="text-rose-400 ml-1">(请填写公历生日)</span></label>
                                    <input type="date" value={profileForm.birth_date} onChange={e => setProfileForm({...profileForm, birth_date: e.target.value})} required className="w-full bg-slate-50 px-4 py-3 rounded-xl border-none text-sm font-medium focus:ring-2 focus:ring-rose-200 focus:bg-white outline-none transition-all text-slate-700" />
                                </div>
                                <div className="w-[100px]">
                                    <label className="block text-[10px] text-slate-500 mb-1 ml-1 font-bold">出生时间</label>
                                    <input type="time" value={profileForm.birth_time} onChange={e => setProfileForm({...profileForm, birth_time: e.target.value})} className="w-full bg-slate-50 px-4 py-3 rounded-xl border-none text-sm font-medium focus:ring-2 focus:ring-rose-200 focus:bg-white outline-none transition-all text-slate-700" />
                                </div>
                            </div>

                            <div>
                                <label className="block text-[10px] text-slate-500 mb-1 ml-1 font-bold">出生城市</label>
                                <input type="text" value={profileForm.city_name} onChange={e => setProfileForm({...profileForm, city_name: e.target.value})} placeholder="如: 北京" className="w-full bg-slate-50 px-5 py-3 rounded-xl border-none text-sm font-medium focus:ring-2 focus:ring-rose-200 focus:bg-white outline-none transition-all placeholder-slate-400" />
                            </div>

                            <div>
                                <label className="block text-[10px] text-slate-500 mb-1 ml-1 font-bold">MBTI (16型人格)</label>
                                <select value={profileForm.mbti} onChange={e => setProfileForm({...profileForm, mbti: e.target.value})} className="w-full bg-slate-50 px-5 py-3 rounded-xl border-none text-sm font-medium focus:ring-2 focus:ring-rose-200 focus:bg-white outline-none transition-all text-slate-700 appearance-none">
                                    <option value="">不确定 / 暂不填写</option>
                                    <option value="INTJ">INTJ 建筑师</option>
                                    <option value="INTP">INTP 逻辑学家</option>
                                    <option value="ENTJ">ENTJ 指挥官</option>
                                    <option value="ENTP">ENTP 辩论家</option>
                                    <option value="INFJ">INFJ 提倡者</option>
                                    <option value="INFP">INFP 调停者</option>
                                    <option value="ENFJ">ENFJ 主人公</option>
                                    <option value="ENFP">ENFP 竞选者</option>
                                    <option value="ISTJ">ISTJ 物流师</option>
                                    <option value="ISFJ">ISFJ 守卫者</option>
                                    <option value="ESTJ">ESTJ 总经理</option>
                                    <option value="ESFJ">ESFJ 执政官</option>
                                    <option value="ISTP">ISTP 鉴赏家</option>
                                    <option value="ISFP">ISFP 探险家</option>
                                    <option value="ESTP">ESTP 企业家</option>
                                    <option value="ESFP">ESFP 表演者</option>
                                </select>
                            </div>
                            
                            {error && <p className="text-xs text-center font-medium text-rose-500 mt-1">{error}</p>}

                            <button disabled={isSubmitting} type="submit" className="sticky bottom-0 z-10 w-full bg-gradient-to-r from-rose-400 to-pink-500 hover:from-rose-500 hover:to-pink-600 text-white font-bold text-sm py-3.5 rounded-xl mt-3 transition-all shadow-[0_-8px_20px_rgba(255,255,255,0.95),0_8px_20px_rgba(244,114,182,0.25)] active:scale-95 disabled:opacity-70">
                                {isSubmitting ? '保存中...' : '保存修改'}
                            </button>
                        </form>
                    )}
                </div>
            </div>
        </div>
    );
}

function PasswordChangeModal({ isOpen, onClose }) {
    const { useState, useEffect } = React;
    const [currentPassword, setCurrentPassword] = useState('');
    const [newPassword, setNewPassword] = useState('');
    const [confirmPassword, setConfirmPassword] = useState('');
    const [message, setMessage] = useState('');
    const [submitting, setSubmitting] = useState(false);
    const [security, setSecurity] = useState(null);
    const [phone, setPhone] = useState('');
    const [code, setCode] = useState('');
    const [cooldown, setCooldown] = useState(0);

    const loadSecurity = () => {
        const token = localStorage.getItem('mystic_token');
        fetch('/api/auth/security', {headers: {'Authorization': `Bearer ${token}`}})
            .then(res => res.json())
            .then(data => setSecurity(data.data ? {...data.data, sms_enabled: data.sms_enabled} : null))
            .catch(() => setMessage('账号安全信息加载失败'));
    };

    useEffect(() => { if (isOpen) loadSecurity(); }, [isOpen]);
    useEffect(() => {
        if (cooldown <= 0) return;
        const timer = setInterval(() => setCooldown(value => Math.max(0, value - 1)), 1000);
        return () => clearInterval(timer);
    }, [cooldown]);

    if (!isOpen) return null;

    const handleSubmit = async (event) => {
        event.preventDefault();
        setMessage('');
        if (newPassword.length < 8) return setMessage('新密码至少 8 位');
        if (newPassword !== confirmPassword) return setMessage('两次输入的新密码不一致');
        setSubmitting(true);
        try {
            const token = localStorage.getItem('mystic_token');
            const response = await fetch('/api/auth/password', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'Authorization': `Bearer ${token}`
                },
                body: JSON.stringify({
                    current_password: currentPassword,
                    new_password: newPassword
                })
            });
            const data = await response.json();
            if (!response.ok) throw new Error(typeof data.detail === 'string' ? data.detail : '修改失败');
            setMessage('密码修改成功');
            setTimeout(onClose, 800);
        } catch (error) {
            setMessage(error.message || '修改失败，请稍后再试');
        } finally {
            setSubmitting(false);
        }
    };

    const sendBindCode = async () => {
        if (!/^1[3-9]\d{9}$/.test(phone)) return setMessage('请输入正确的手机号');
        setMessage('');
        try {
            const token = localStorage.getItem('mystic_token');
            const response = await fetch('/api/auth/sms/send', {
                method: 'POST',
                headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`},
                body: JSON.stringify({phone, purpose: 'bind'})
            });
            const data = await response.json().catch(() => ({}));
            if (!response.ok) throw new Error(data.detail || '验证码发送失败');
            if (data.debug_code) setCode(data.debug_code);
            setCooldown(60);
            setMessage('验证码已发送');
        } catch (error) {
            setMessage(error.message || '验证码发送失败');
        }
    };

    const bindPhone = async () => {
        if (!/^\d{6}$/.test(code)) return setMessage('请输入6位验证码');
        setSubmitting(true);
        setMessage('');
        try {
            const token = localStorage.getItem('mystic_token');
            const response = await fetch('/api/auth/phone/bind', {
                method: 'POST',
                headers: {'Content-Type': 'application/json', 'Authorization': `Bearer ${token}`},
                body: JSON.stringify({phone, code})
            });
            const data = await response.json().catch(() => ({}));
            if (!response.ok) throw new Error(data.detail || '绑定失败');
            setMessage('手机号绑定成功');
            setPhone('');
            setCode('');
            loadSecurity();
        } catch (error) {
            setMessage(error.message || '绑定失败');
        } finally {
            setSubmitting(false);
        }
    };

    return (
        <div className="fixed inset-0 z-[10000] flex items-center justify-center px-4 bg-black/60 backdrop-blur-sm">
            <div className="bg-white rounded-2xl p-5 w-full max-w-[340px] max-h-[88dvh] overflow-y-auto shadow-2xl relative">
                <button type="button" onClick={onClose} aria-label="关闭" className="absolute top-3 right-3 w-8 h-8 rounded-full bg-slate-100 text-slate-500">×</button>
                <h2 className="text-lg font-black text-slate-800 mb-4">账号安全</h2>

                <section className="rounded-xl bg-purple-50/70 p-4 mb-5">
                    <div className="flex items-center justify-between mb-3">
                        <div>
                            <h3 className="text-sm font-bold text-slate-700">绑定手机号</h3>
                            <p className="text-[11px] text-slate-500 mt-1">用于验证码登录和找回密码</p>
                        </div>
                        {security?.phone_bound && <span className="text-xs font-bold text-emerald-600">{security.phone_masked}</span>}
                    </div>
                    {!security?.phone_bound && security?.sms_enabled && (
                        <div className="flex flex-col gap-2">
                            <input inputMode="numeric" value={phone} onChange={e => setPhone(e.target.value.replace(/\D/g, '').slice(0, 11))} placeholder="手机号" className="w-full bg-white px-3 py-2.5 rounded-lg text-sm outline-none" />
                            <div className="flex gap-2">
                                <input inputMode="numeric" value={code} onChange={e => setCode(e.target.value.replace(/\D/g, '').slice(0, 6))} placeholder="验证码" className="min-w-0 flex-1 bg-white px-3 py-2.5 rounded-lg text-sm outline-none" />
                                <button type="button" onClick={sendBindCode} disabled={cooldown > 0} className="w-[92px] rounded-lg bg-white text-purple-700 text-xs font-bold disabled:text-slate-400">{cooldown > 0 ? `${cooldown}s` : '获取验证码'}</button>
                            </div>
                            <button type="button" onClick={bindPhone} disabled={submitting} className="w-full rounded-lg bg-purple-500 text-white text-xs font-bold py-2.5 disabled:opacity-60">确认绑定</button>
                        </div>
                    )}
                    {!security?.phone_bound && security && !security.sms_enabled && <p className="text-xs text-slate-500">短信服务配置完成后即可绑定</p>}
                </section>

                <h3 className="text-sm font-bold text-slate-700 mb-3">修改密码</h3>
                <form onSubmit={handleSubmit} className="flex flex-col gap-3">
                    <input type="password" autoComplete="current-password" value={currentPassword} onChange={e => setCurrentPassword(e.target.value)} placeholder="当前密码" required className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-rose-200" />
                    <input type="password" autoComplete="new-password" value={newPassword} onChange={e => setNewPassword(e.target.value)} placeholder="新密码（至少 8 位）" required className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-rose-200" />
                    <input type="password" autoComplete="new-password" value={confirmPassword} onChange={e => setConfirmPassword(e.target.value)} placeholder="再次输入新密码" required className="w-full bg-slate-50 px-4 py-3 rounded-xl text-sm outline-none focus:ring-2 focus:ring-rose-200" />
                    {message && <p className={`text-xs text-center ${message.includes('成功') ? 'text-emerald-600' : 'text-rose-500'}`}>{message}</p>}
                    <button disabled={submitting} type="submit" className="w-full bg-rose-500 text-white font-bold text-sm py-3 rounded-xl disabled:opacity-60">
                        {submitting ? '提交中...' : '确认修改'}
                    </button>
                </form>
            </div>
        </div>
    );
}

window.AuthComponents = { useAuth, LoginModal, ProfileEditModal, PasswordChangeModal };
