package com.narutohuo.xindazhou.common.network.interceptor

import com.narutohuo.xindazhou.core.log.ILog
import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response

/**
 * Token 刷新拦截器
 * 
 * 拦截 401/402 响应，自动刷新 Token 并重试请求
 * 
 * **功能**：
 * - 拦截 401/402 响应（Token 过期/无效）
 * - 自动调用 refreshTokenProvider 刷新 Token
 * - 使用新 Token 重试原请求
 * - 并发控制：多个请求同时 401 时，只刷新一次，其他请求等待
 * 
 * **架构说明**：
 * 按照架构设计文档，网络服务统一放在 `base/common/network/` 模块中。
 * 此拦截器与 HeaderInterceptor、NetworkManager、ApiManager 等统一管理。
 * 
 * 使用方式：
 * ```kotlin
 * // 通过 NetworkManager 使用（推荐）
 * NetworkManager.tokenProvider = { TokenStore.getAccessToken() }
 * NetworkManager.refreshTokenProvider = { AuthManager.refreshTokenIfNeeded() }
 * // NetworkManager 会自动创建并使用 TokenRefreshInterceptor
 * ```
 */
class TokenRefreshInterceptor(
    private val tokenProvider: () -> String?,
    private val refreshTokenProvider: (suspend () -> String?)?
) : Interceptor {
    
    private val TAG = "TokenRefreshInterceptor"
    
    @Volatile
    private var isRefreshing = false
    
    private val refreshLock = Any()
    
    override fun intercept(chain: Interceptor.Chain): Response {
        val request = chain.request()
        var response = chain.proceed(request)
        
        // 拦截 401/402 响应（Token 过期/无效）
        if (response.code == 401 || response.code == 402) {
            // 如果没有提供刷新回调，直接返回 401 响应
            if (refreshTokenProvider == null) {
                ILog.w(TAG, "收到 401/402 响应，但未设置 refreshTokenProvider，无法自动刷新")
                return response
            }
            
            synchronized(refreshLock) {
                // 并发控制：如果正在刷新，等待刷新完成
                if (isRefreshing) {
                    ILog.d(TAG, "Token 正在刷新中，等待刷新完成...")
                    // 等待刷新完成，最多等待 3 秒
                    var waitCount = 0
                    while (isRefreshing && waitCount < 30) {
                        Thread.sleep(100)
                        waitCount++
                    }
                    // 刷新完成后，使用新 Token 重试
                    val newToken = tokenProvider()
                    if (!newToken.isNullOrEmpty()) {
                        ILog.d(TAG, "使用刷新后的新 Token 重试请求")
                        val newRequest = request.newBuilder()
                            .header("Authorization", "Bearer $newToken")
                            .removeHeader("Authorization") // 先移除，避免重复
                            .header("Authorization", "Bearer $newToken")
                            .build()
                        // 关闭原响应
                        response.close()
                        response = chain.proceed(newRequest)
                    } else {
                        ILog.w(TAG, "等待刷新完成后，Token 仍为空，返回 401 响应")
                    }
                } else {
                    // 开始刷新
                    isRefreshing = true
                    try {
                        ILog.d(TAG, "检测到 401/402 响应，开始刷新 Token...")
                        val newToken = runBlocking { 
                            refreshTokenProvider.invoke() 
                        }
                        
                        if (!newToken.isNullOrEmpty()) {
                            ILog.d(TAG, "Token 刷新成功，使用新 Token 重试请求")
                            // 重试原请求（使用新 Token）
                            val newRequest = request.newBuilder()
                                .header("Authorization", "Bearer $newToken")
                                .removeHeader("Authorization") // 先移除，避免重复
                                .header("Authorization", "Bearer $newToken")
                                .build()
                            // 关闭原响应
                            response.close()
                            response = chain.proceed(newRequest)
                            
                            // 如果重试后仍然是 401，说明刷新失败或 Token 无效
                            if (response.code == 401 || response.code == 402) {
                                ILog.w(TAG, "使用新 Token 重试后仍返回 401/402，Token 刷新可能失败")
                            }
                        } else {
                            ILog.w(TAG, "Token 刷新失败（返回 null），返回 401 响应")
                        }
                    } catch (e: Exception) {
                        ILog.e(TAG, "Token 刷新异常", e)
                    } finally {
                        isRefreshing = false
                    }
                }
            }
        }
        
        return response
    }
}

