/**
 * AuthProvider - 全局会话上下文
 * 
 * 提供：
 * - 会话状态（user, roles, isAdmin）
 * - 登录/登出方法
 * - 会话恢复（启动时自动刷新）
 */

import {
  useEffect,
  useState,
  useCallback,
  type ReactNode,
} from 'react'
import { useNavigate } from 'react-router-dom'
import type { SessionUser, Role, TokenBundle } from '@/types'
import { get } from '@/lib/http'
import {
  setRefreshToken,
  clearRefreshToken,
  hasSessionPresenceCookie,
} from '@/lib/storage'
import {
  setAccessToken,
  getCurrentUser,
  setCurrentUser,
  getCurrentRoles,
  setCurrentRoles,
  clearSession,
  isAuthenticated,
  isAccessTokenExpired,
} from '@/lib/http/auth-session'
import { initCSRFToken, clearCSRFToken } from '@/lib/http/csrf'
import { logout as logoutRequest, refreshSession } from '@/services/auth'
import { AuthContext, type AuthContextValue } from './auth-context'

// ==================== Provider ====================

interface AuthProviderProps {
  children: ReactNode
}

export function AuthProvider({ children }: AuthProviderProps) {
  const [user, setUser] = useState<SessionUser | null>(getCurrentUser())
  const [roles, setRoles] = useState<Role[]>(getCurrentRoles())
  const [isLoading, setIsLoading] = useState(true)
  const navigate = useNavigate()

  // 判断是否为管理员
  const isAdmin = roles.some((role) => role.code === 'admin')

  /**
   * 获取用户角色
   */
  const fetchUserRoles = useCallback(async (userId: number): Promise<Role[]> => {
    try {
      const result = await get<Role[]>(`/users/${userId}/roles`)
      return result
    } catch {
      return []
    }
  }, [])

  const applyAuthState = useCallback((nextUser: SessionUser | null, nextRoles: Role[]) => {
    setUser(nextUser)
    setRoles(nextRoles)
  }, [])

  const clearLocalAuthState = useCallback(() => {
    applyAuthState(null, [])
  }, [applyAuthState])

  const persistSessionUser = useCallback((nextUser: SessionUser) => {
    setCurrentUser(nextUser)
    setUser(nextUser)
  }, [])

  const persistSessionRoles = useCallback((nextRoles: Role[]) => {
    setCurrentRoles(nextRoles)
    setRoles(nextRoles)
  }, [])

  const loadRolesForUser = useCallback(async (userId: number): Promise<Role[]> => {
    const userRoles = await fetchUserRoles(userId)
    persistSessionRoles(userRoles)
    return userRoles
  }, [fetchUserRoles, persistSessionRoles])

  /**
   * 登录成功回调
   */
  const onLoginSuccess = useCallback(async (tokenBundle: TokenBundle) => {
    // 保存 tokens
    setAccessToken(tokenBundle.access_token, tokenBundle.expires_in)
    setRefreshToken(tokenBundle.refresh_token)

    // 保存用户信息与角色
    persistSessionUser(tokenBundle.user)
    await loadRolesForUser(tokenBundle.user.id)

    // 初始化 CSRF Token
    await initCSRFToken()
  }, [loadRolesForUser, persistSessionUser])

  /**
   * 刷新用户信息
   */
  const refreshUser = useCallback(async () => {
    try {
      const userInfo = await get<SessionUser>('/auth/userinfo')
      persistSessionUser(userInfo)
      await loadRolesForUser(userInfo.id)
    } catch {
      // 保留当前 provider 状态，避免短暂的 userinfo 抖动清空已登录会话
    }
  }, [loadRolesForUser, persistSessionUser])

  /**
   * 登出
   */
  const logout = useCallback(async () => {
    try {
      await logoutRequest()
    } catch {
      // 忽略登出请求错误
    } finally {
      // 无论请求成功与否，都清除本地会话和 CSRF Token
      clearRefreshToken()
      clearSession()
      clearCSRFToken()
      clearLocalAuthState()
      navigate('/login')
    }
  }, [clearLocalAuthState, navigate])

  /**
   * 会话恢复（应用启动时，只运行一次）
   */
  useEffect(() => {
    const restoreSession = async () => {
      // 如果已有 access_token 且未过期，直接使用
      if (isAuthenticated() && !isAccessTokenExpired()) {
        const currentUser = getCurrentUser()
        const currentRoles = getCurrentRoles()

        if (currentUser) {
          applyAuthState(currentUser, currentRoles)
          await initCSRFToken()
          setIsLoading(false)
          return
        }
      }

      if (!hasSessionPresenceCookie()) {
        clearRefreshToken()
        clearSession()
        clearLocalAuthState()
        setIsLoading(false)
        return
      }

      try {
        const result = await refreshSession()

        // 保存 tokens
        setAccessToken(result.access_token, result.expires_in)
        setRefreshToken(result.refresh_token)

        // 保存用户信息与角色
        persistSessionUser(result.user)
        await loadRolesForUser(result.user.id)
        await initCSRFToken()
      } catch {
        // 刷新失败，清除会话
        clearRefreshToken()
        clearSession()
        clearLocalAuthState()
      }

      setIsLoading(false)
    }

    restoreSession()
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []) // 只在挂载时运行一次，不依赖 location.pathname

  const value: AuthContextValue = {
    user,
    roles,
    isAdmin,
    isAuthenticated: user !== null,
    isLoading,
    onLoginSuccess,
    logout,
    refreshUser,
  }

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  )
}
