import React, { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState, } from 'react' import { Alert } from 'react-native' import { clearPbSession, loadPbSession, savePbSession, type StoredPbSession } from '@/lib/authStorage' import { isLiveAllowed, pbAuthRefresh, pbAuthWithPassword, type PbUserRecord, } from '@/lib/pocketbase' type Ctx = { session: StoredPbSession | null ready: boolean loginVisible: boolean openLogin: () => void closeLogin: () => void login: (email: string, password: string) => Promise logout: () => Promise refreshSession: () => Promise /** 用于远程 API 请求头 */ pbToken: string | null /** 开始/重启直播前调用;未登录则弹出登录;无权限则 false */ ensureCanControlLive: () => Promise } const AuthContext = createContext(null) export function AuthProvider({ children }: { children: React.ReactNode }) { const [session, setSession] = useState(null) const [ready, setReady] = useState(false) const [loginVisible, setLoginVisible] = useState(false) const pendingGate = useRef<((ok: boolean) => void) | null>(null) useEffect(() => { void (async () => { const s = await loadPbSession() if (s) { try { const r = await pbAuthRefresh(s.token) const next: StoredPbSession = { token: r.token, record: r.record } setSession(next) await savePbSession(next) } catch { await clearPbSession() setSession(null) } } setReady(true) })() }, []) const openLogin = useCallback(() => setLoginVisible(true), []) const closeLogin = useCallback(() => { setLoginVisible(false) const p = pendingGate.current pendingGate.current = null p?.(false) }, []) const login = useCallback(async (email: string, password: string) => { const r = await pbAuthWithPassword(email, password) if (!isLiveAllowed(r.record)) { throw new Error('该账号暂无直播权限,请联系管理员') } const next: StoredPbSession = { token: r.token, record: r.record } setSession(next) await savePbSession(next) setLoginVisible(false) const p = pendingGate.current pendingGate.current = null p?.(true) }, []) const logout = useCallback(async () => { await clearPbSession() setSession(null) }, []) const refreshSession = useCallback(async () => { if (!session?.token) return false try { const r = await pbAuthRefresh(session.token) const next: StoredPbSession = { token: r.token, record: r.record } setSession(next) await savePbSession(next) return isLiveAllowed(r.record) } catch { await clearPbSession() setSession(null) return false } }, [session?.token]) const ensureCanControlLive = useCallback(async (): Promise => { if (session?.token) { try { const r = await pbAuthRefresh(session.token) const next: StoredPbSession = { token: r.token, record: r.record } setSession(next) await savePbSession(next) if (!isLiveAllowed(r.record)) { Alert.alert('无权限', '账号已被管理员停用远程直播权限。') return false } return true } catch { await clearPbSession() setSession(null) } } return new Promise((resolve) => { pendingGate.current = (ok) => resolve(ok) setLoginVisible(true) }) }, [session?.token]) const pbToken = session?.token ?? null const value = useMemo( () => ({ session, ready, loginVisible, openLogin, closeLogin, login, logout, refreshSession, pbToken, ensureCanControlLive, }), [ session, ready, loginVisible, openLogin, closeLogin, login, logout, refreshSession, pbToken, ensureCanControlLive, ], ) return {children} } export function useAuth(): Ctx { const c = useContext(AuthContext) if (!c) throw new Error('useAuth outside AuthProvider') return c } export function useAuthOptional(): Ctx | null { return useContext(AuthContext) }