package com.narutohuo.xindazhou.common.auth

import android.content.Context
import androidx.fragment.app.FragmentActivity
import androidx.lifecycle.lifecycleScope
import com.narutohuo.xindazhou.common.auth.datasource.local.AuthLocalDataSource
import com.narutohuo.xindazhou.common.auth.datasource.local.AuthLocalDataSourceImpl
import com.narutohuo.xindazhou.common.auth.datasource.remote.AuthRemoteDataSource
import com.narutohuo.xindazhou.common.auth.datasource.remote.AuthRemoteDataSourceImpl
import com.narutohuo.xindazhou.common.auth.repository.AuthRepository
import com.narutohuo.xindazhou.common.auth.storage.TokenStore
import com.narutohuo.xindazhou.common.auth.utils.JWTUtil
import com.narutohuo.xindazhou.common.log.LogHelper
import com.narutohuo.xindazhou.common.network.NetworkHelper
import com.narutohuo.xindazhou.common.socketio.SocketIOManager
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * 认证管理器
 * 
 * 封装认证相关的完整逻辑，包括：
 * - 用户登录
 * - 用户注册
 * - Token 刷新
 * - 登录状态管理
 * 
 * 使用方式：
 * ```kotlin
 * // 在 Application 中初始化（推荐方式，使用默认实现）
 * AuthManager.init(context)
 * 
 * // 或者使用自定义的 localDataSource
 * AuthManager.init(localDataSource)
 * 
 * // 在 Activity 中登录
 * AuthManager.login(activity, mobile, password) { result ->
 *     result.onSuccess { response ->
 *         // 登录成功，跳转到主界面
 *     }
 *     result.onFailure { error ->
 *         // 登录失败，显示错误
 *     }
 * }
 * ```
 */
object AuthManager {
    
    private var localDataSource: AuthLocalDataSource? = null
    private var remoteDataSource: AuthRemoteDataSource = AuthRemoteDataSourceImpl()
    private var repository: AuthRepository? = null
    
    /**
     * 初始化认证管理器（使用默认实现）
     * 
     * 需要在 Application.onCreate() 中调用
     * 会自动初始化 TokenStore 并使用默认的 AuthLocalDataSourceImpl
     * 会自动配置 NetworkHelper 的 Token Provider
     * 
     * @param context 应用上下文
     */
    fun init(context: Context) {
        // 初始化 TokenStore
        TokenStore.init(context)
        // 使用默认实现
        val defaultLocalDataSource = AuthLocalDataSourceImpl()
        this.localDataSource = defaultLocalDataSource
        this.repository = AuthRepository(remoteDataSource, defaultLocalDataSource)
        
        // 配置 NetworkHelper 的 Token Provider（使用 TokenStore 的同步方法）
        NetworkHelper.setTokenProvider {
            TokenStore.getAccessToken()
        }
        
        LogHelper.d("AuthManager", "认证管理器初始化完成，Token Provider 已配置")
    }
    
    /**
     * 初始化认证管理器（使用自定义实现）
     * 
     * 如果需要自定义本地数据源，可以使用此方法
     * 会自动配置 NetworkHelper 的 Token Provider
     * 
     * @param localDataSource 自定义的本地数据源
     */
    fun init(localDataSource: AuthLocalDataSource) {
        this.localDataSource = localDataSource
        this.repository = AuthRepository(remoteDataSource, localDataSource)
        
        // 配置 NetworkHelper 的 Token Provider（使用 TokenStore 的同步方法）
        NetworkHelper.setTokenProvider {
            TokenStore.getAccessToken()
        }
        
        LogHelper.d("AuthManager", "认证管理器初始化完成（自定义数据源），Token Provider 已配置")
    }
    
    /**
     * 用户登录
     * 
     * @param activity Activity 实例
     * @param mobile 手机号
     * @param password 密码
     * @param onResult 登录结果回调
     */
    fun login(
        activity: FragmentActivity,
        mobile: String,
        password: String,
        onResult: (Result<com.narutohuo.xindazhou.common.auth.model.LoginResponse>) -> Unit
    ) {
        activity.lifecycleScope.launch {
            try {
                val repo = repository ?: run {
                    LogHelper.e("AuthManager", "AuthManager 未初始化，请先调用 AuthManager.init()")
                    onResult(Result.failure(Exception("AuthManager 未初始化")))
                    return@launch
                }
                
                val result = repo.login(mobile, password)
                
                // 登录成功后，自动触发 Socket.IO 连接
                result.onSuccess {
                    LogHelper.d("AuthManager", "登录成功，自动触发 Socket.IO 连接")
                    SocketIOManager.ensureConnected()
                }
                
                onResult(result as Result<com.narutohuo.xindazhou.common.auth.model.LoginResponse>)
            } catch (e: Exception) {
                LogHelper.e("AuthManager", "登录异常", e)
                onResult(Result.failure(e))
            }
        }
    }
    
    /**
     * 用户注册
     * 
     * @param activity Activity 实例
     * @param mobile 手机号
     * @param password 密码
     * @param onResult 注册结果回调
     */
    fun register(
        activity: FragmentActivity,
        mobile: String,
        password: String,
        onResult: (Result<com.narutohuo.xindazhou.common.auth.model.LoginResponse>) -> Unit
    ) {
        activity.lifecycleScope.launch {
            try {
                val repo = repository ?: run {
                    LogHelper.e("AuthManager", "AuthManager 未初始化，请先调用 AuthManager.init()")
                    onResult(Result.failure(Exception("AuthManager 未初始化")))
                    return@launch
                }
                
                val result = repo.register(mobile, password)
                
                // 注册成功后，自动触发 Socket.IO 连接
                result.onSuccess {
                    LogHelper.d("AuthManager", "注册成功，自动触发 Socket.IO 连接")
                    SocketIOManager.ensureConnected()
                }
                
                onResult(result as Result<com.narutohuo.xindazhou.common.auth.model.LoginResponse>)
            } catch (e: Exception) {
                LogHelper.e("AuthManager", "注册异常", e)
                onResult(Result.failure(e))
            }
        }
    }
    
    /**
     * 刷新 Token
     * 
     * @param activity Activity 实例
     * @param refreshToken 刷新令牌
     * @param onResult 刷新结果回调
     */
    fun refreshToken(
        activity: FragmentActivity,
        refreshToken: String,
        onResult: (Result<com.narutohuo.xindazhou.common.auth.model.LoginResponse>) -> Unit
    ) {
        activity.lifecycleScope.launch {
            try {
                val repo = repository ?: run {
                    LogHelper.e("AuthManager", "AuthManager 未初始化，请先调用 AuthManager.init()")
                    onResult(Result.failure(Exception("AuthManager 未初始化")))
                    return@launch
                }
                
                val result = repo.refreshToken(refreshToken)
                onResult(result as Result<com.narutohuo.xindazhou.common.auth.model.LoginResponse>)
            } catch (e: Exception) {
                LogHelper.e("AuthManager", "Token 刷新异常", e)
                onResult(Result.failure(e))
            }
        }
    }
    
    // ========== 便捷方法 ==========
    
    /**
     * 检查是否已登录（同步，仅检查 Access Token，不刷新）
     * 
     * 注意：此方法只检查 Access Token 是否存在且未过期，不会尝试刷新
     * 如果需要自动刷新功能，请使用 isLoggedInAsync()
     * 
     * @return true 表示已登录
     */
    fun isLoggedIn(): Boolean {
        return TokenStore.isLoggedIn()
    }
    
    /**
     * 检查是否已登录（异步，支持自动刷新）
     * 
     * 检查 Access Token 是否存在且未过期
     * 如果 Access Token 过期，会尝试使用 Refresh Token 刷新
     * 只有在 Refresh Token 也过期或刷新失败时，才返回 false
     * 
     * @return true 表示已登录
     */
    suspend fun isLoggedInAsync(): Boolean {
        // 1. 先检查 Access Token 是否存在
        val accessToken = TokenStore.getAccessToken()
        
        // 2. 如果 Access Token 不存在，检查是否有 Refresh Token
        if (accessToken.isNullOrEmpty()) {
            val refreshToken = TokenStore.getRefreshToken()
            if (!refreshToken.isNullOrEmpty()) {
                // 有 Refresh Token，尝试刷新 Access Token
                LogHelper.d("AuthManager", "Access Token 不存在，尝试使用 Refresh Token 刷新...")
                val newToken = refreshTokenIfNeeded()
                return !newToken.isNullOrEmpty()
            }
            // 没有 Refresh Token，返回 false
            return false
        }
        
        // 3. 检查 Access Token 是否过期
        if (!JWTUtil.isTokenValid(accessToken)) {
            // Access Token 已过期，检查是否有 Refresh Token
            val refreshToken = TokenStore.getRefreshToken()
            if (!refreshToken.isNullOrEmpty()) {
                // 有 Refresh Token，尝试刷新 Access Token
                LogHelper.d("AuthManager", "Access Token 已过期，尝试使用 Refresh Token 刷新...")
                val newToken = refreshTokenIfNeeded()
                
                // 如果刷新成功，验证新 Token 是否有效
                if (!newToken.isNullOrEmpty() && JWTUtil.isTokenValid(newToken)) {
                    LogHelper.d("AuthManager", "Access Token 刷新成功，用户仍然处于登录状态")
                    return true
                } else {
                    LogHelper.w("AuthManager", "Access Token 刷新失败或新 Token 无效，用户需要重新登录")
                    return false
                }
            } else {
                // 没有 Refresh Token，返回 false
                LogHelper.w("AuthManager", "Access Token 已过期且没有 Refresh Token，用户需要重新登录")
                return false
            }
        }
        
        // 4. Access Token 存在且未过期，返回 true
        return true
    }
    
    /**
     * 获取当前 Access Token
     * 
     * @return Access Token，如果未登录返回 null
     */
    fun getAccessToken(): String? {
        return TokenStore.getAccessToken()
    }
    
    /**
     * 获取当前 Refresh Token
     * 
     * @return Refresh Token，如果未登录返回 null
     */
    fun getRefreshToken(): String? {
        return TokenStore.getRefreshToken()
    }
    
    /**
     * 刷新 Token（如果需要）
     * 
     * 在后台协程中自动刷新 Token，无需 Activity 生命周期
     * 
     * @param scope 协程作用域（例如：applicationScope）
     * @param onResult 刷新结果回调（可选）
     * @return 新的 accessToken，如果刷新失败返回 null
     */
    suspend fun refreshTokenIfNeeded(
        scope: CoroutineScope? = null,
        onResult: ((Result<String?>) -> Unit)? = null
    ): String? {
        val refreshToken = TokenStore.getRefreshToken()
        if (refreshToken.isNullOrEmpty()) {
            LogHelper.w("AuthManager", "RefreshToken 为空，无法刷新")
            onResult?.invoke(Result.failure(Exception("RefreshToken 为空")))
            return null
        }
        
        return try {
            val repo = repository ?: run {
                val error = Exception("AuthManager 未初始化")
                LogHelper.e("AuthManager", "AuthManager 未初始化，请先调用 AuthManager.init()")
                onResult?.invoke(Result.failure(error))
                return null
            }
            
            val result = repo.refreshToken(refreshToken)
            
            result.getOrNull()?.let { loginResponse ->
                // Token 已由 AuthRepository 自动保存
                LogHelper.d("AuthManager", "Token 刷新成功")
                
                // Token 刷新成功后，确保 Socket.IO 使用新 Token 重连
                SocketIOManager.ensureConnected()
                
                onResult?.invoke(Result.success(loginResponse.accessToken))
                loginResponse.accessToken
            } ?: run {
                val error = result.exceptionOrNull() ?: Exception("Token 刷新失败")
                LogHelper.w("AuthManager", "Token 刷新失败: ${error.message}")
                onResult?.invoke(Result.failure(error))
                null
            }
        } catch (e: Exception) {
            LogHelper.e("AuthManager", "Token 刷新异常", e)
            onResult?.invoke(Result.failure(e))
            null
        }
    }
    
    /**
     * 在后台协程中刷新 Token（如果需要）
     * 
     * @param scope 协程作用域
     * @param onResult 刷新结果回调（可选）
     */
    fun refreshTokenIfNeededAsync(
        scope: CoroutineScope,
        onResult: ((Result<String?>) -> Unit)? = null
    ) {
        scope.launch(Dispatchers.IO) {
            refreshTokenIfNeeded(scope, onResult)
        }
    }
    
    /**
     * 登出
     * 
     * 清除所有 Token 和用户信息
     */
    fun logout() {
        TokenStore.clearToken()
        LogHelper.d("AuthManager", "用户已登出")
    }
}

