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<void>
  logout: () => Promise<void>
  refreshSession: () => Promise<boolean>
  /** 用于远程 API 请求头 */
  pbToken: string | null
  /** 开始/重启直播前调用；未登录则弹出登录；无权限则 false */
  ensureCanControlLive: () => Promise<boolean>
}

const AuthContext = createContext<Ctx | null>(null)

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [session, setSession] = useState<StoredPbSession | null>(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<boolean> => {
    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<boolean>((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 <AuthContext.Provider value={value}>{children}</AuthContext.Provider>
}

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)
}
