import Foundation

/// Token管理器
/// 负责管理应用的认证令牌，包括验证、刷新和过期处理
class TokenManager {
    /// 单例实例
    static let shared = TokenManager()
    
    /// token有效期阈值（秒），在token即将过期前进行刷新
    /// 例如：设置为300表示在token过期前5分钟开始刷新
    private let tokenValidityThreshold: TimeInterval = 300
    
    /// 私有化初始化方法，确保单例模式
    private init() {}
    
    // MARK: - Token 状态检查
    
    /// 检查是否存在有效的访问令牌
    var hasToken: Bool {
        return KeychainHelper.getAccessToken()?.isEmpty == false
    }
    
    // MARK: - Token 验证
    
    /// 验证并刷新token（如果需要）
    /// - 检查token是否存在
    /// - 检查token是否有效
    /// - 在token即将过期时自动刷新
    /// - Parameter completion: 完成回调，返回验证/刷新结果
    ///   - isValid: token是否有效
    ///   - error: 错误信息（如果有）
    func validateAndRefreshTokenIfNeeded(completion: @escaping (Bool, Error?) -> Void) {
        // 1. 检查token是否存在
        guard let token = KeychainHelper.getAccessToken(), !token.isEmpty else {
            // token不存在，返回未授权错误
            let error = NSError(
                domain: "TokenManager",
                code: 401,
                userInfo: [NSLocalizedDescriptionKey: "未找到访问令牌"]
            )
            completion(false, error)
            return
        }
        
        // 2. 检查token是否有效
        if isTokenValid(token) {
            // token有效，直接返回成功
            completion(true, nil)
            return
        }
        
        // 3. token无效或即将过期，尝试刷新
        refreshToken { [weak self] success, error in
            if success {
                // 刷新成功，返回成功
                completion(true, nil)
            } else {
                // 刷新失败，返回错误信息
                let finalError = error ?? NSError(
                    domain: "TokenManager",
                    code: 401,
                    userInfo: [NSLocalizedDescriptionKey: "Token刷新失败"]
                )
                completion(false, finalError)
            }
        }
    }
    
    /// 检查token是否有效
    /// - Parameter token: 要检查的token字符串
    /// - Returns: 如果token有效返回true，否则返回false
    /// 
    /// 该方法会检查token的有效性，包括检查token是否为空、是否过期以及通过网络请求验证token。
    /// 
    /// - Note: 该方法会打印一些调试信息，包括token验证开始、token过期时间等。
    public func isTokenValid(_ token: String) -> Bool {
        print("🔍 TokenManager: 开始验证token...")
        
        // 1. 基础验证：检查token是否为空
        guard !token.isEmpty else {
            print("❌ TokenManager: Token为空")
            return false
        }
        
        // 2. 检查token是否过期（如果可能）
        if let expiryDate = getTokenExpiryDate(token) {
            print("⏰ TokenManager: Token过期时间: \(expiryDate)")
            if Date() > expiryDate {
                print("❌ TokenManager: Token已过期")
                return false
            }
        }
        
        // 3. 创建信号量用于同步网络请求
        let semaphore = DispatchSemaphore(value: 0)
        var isValid = false
        var requestCompleted = false
        
        print("🌐 TokenManager: 发送验证请求到服务器...")
        
        // 4. 发送验证请求
        let task = URLSession.shared.dataTask(with: createValidationRequest(token: token)) { data, response, error in
            defer {
                requestCompleted = true
                semaphore.signal()
            }
            
            // 检查网络错误
            if let error = error {
                print("❌ TokenManager: 验证请求错误: \(error.localizedDescription)")
                return
            }
            
            // 检查响应状态码
            guard let httpResponse = response as? HTTPURLResponse else {
                print("❌ TokenManager: 无效的服务器响应")
                return
            }
            
            print("📡 TokenManager: 服务器响应状态码: \(httpResponse.statusCode)")
            
            // 检查状态码
            guard (200...299).contains(httpResponse.statusCode) else {
                print("❌ TokenManager: 服务器返回错误状态码: \(httpResponse.statusCode)")
                return
            }
            
            // 检查是否有数据
            if let data = data, !data.isEmpty {
                do {
                    // 尝试解析响应数据
                    let response = try JSONDecoder().decode(IdentityCheckResponse.self, from: data)
                    isValid = response.isValid
                    print("✅ TokenManager: Token验证\(isValid ? "成功" : "失败")")
                } catch {
                    print("❌ TokenManager: 解析响应数据失败: \(error.localizedDescription)")
                    // 如果解析失败但状态码是200，我们假设token是有效的
                    isValid = true
                    print("ℹ️ TokenManager: 状态码200，假设token有效")
                }
            } else {
                // 如果没有返回数据但状态码是200，我们假设token是有效的
                print("ℹ️ TokenManager: 没有返回数据，但状态码为200，假设token有效")
                isValid = true
            }
        }
        
        task.resume()
        
        // 5. 设置超时时间（10秒）
        let timeoutResult = semaphore.wait(timeout: .now() + 15)
        
        // 检查是否超时
        if !requestCompleted && timeoutResult == .timedOut {
            print("⚠️ TokenManager: 验证请求超时")
            task.cancel()
            return false
        }
        
        return isValid
    }
    
    /// 创建验证请求
    private func createValidationRequest(token: String) -> URLRequest {
        let url = URL(string: APIConfig.baseURL + "/iam/identity-check")!
        var request = URLRequest(url: url)
        request.httpMethod = "POST"
        request.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization")
        request.setValue("application/json", forHTTPHeaderField: "Accept")
        return request
    }
    
    /// 从token中提取过期时间（示例实现）
    private func getTokenExpiryDate(_ token: String) -> Date? {
        // 这里需要根据实际的JWT或其他token格式来解析过期时间
        // 以下是JWT token的示例解析
        let parts = token.components(separatedBy: ".")
        guard parts.count > 1, let payloadData = base64UrlDecode(parts[1]) else {
            return nil
        }
        
        do {
            if let payload = try JSONSerialization.jsonObject(with: payloadData) as? [String: Any],
               let exp = payload["exp"] as? TimeInterval {
                return Date(timeIntervalSince1970: exp)
            }
        } catch {
            print("❌ TokenManager: 解析token过期时间失败: \(error.localizedDescription)")
        }
        
        return nil
    }
    
    private func base64UrlDecode(_ base64Url: String) -> Data? {
        var base64 = base64Url
            .replacingOccurrences(of: "-", with: "+")
            .replacingOccurrences(of: "_", with: "/")
        
        // 添加必要的填充
        let length = Double(base64.lengthOfBytes(using: .utf8))
        let requiredLength = 4 * ceil(length / 4.0)
        let paddingLength = requiredLength - length
        if paddingLength > 0 {
            let padding = "".padding(toLength: Int(paddingLength), withPad: "=", startingAt: 0)
            base64 = base64 + padding
        }
        
        return Data(base64Encoded: base64)
    }
    
    /// 刷新token
    /// - Parameter completion: 刷新完成回调
    ///   - success: 是否刷新成功
    ///   - error: 错误信息（如果有）
    func refreshToken(completion: @escaping (Bool, Error?) -> Void) {
        // 获取刷新令牌
        guard let refreshToken = KeychainHelper.getRefreshToken(), !refreshToken.isEmpty else {
            // 没有可用的刷新令牌
            let error = NSError(
                domain: "TokenManager",
                code: 401,
                userInfo: [NSLocalizedDescriptionKey: "未找到刷新令牌"]
            )
            completion(false, error)
            return
        }
        
        // 准备刷新请求参数
        let parameters: [String: Any] = [
            "refresh_token": refreshToken,
            "grant_type": "refresh_token"
        ]
        
        // 发送刷新请求
        NetworkService.shared.post(path: "/v1/iam/access-token-refresh", parameters: parameters) { 
            (result: Result<TokenResponse, NetworkError>) in
            
            switch result {
            case .success(let tokenResponse):
                // 1. 保存新的访问令牌
                KeychainHelper.saveAccessToken(tokenResponse.accessToken)
                
                // 2. 如果返回了新的刷新令牌，也保存起来
                if let newRefreshToken = tokenResponse.refreshToken {
                    KeychainHelper.saveRefreshToken(newRefreshToken)
                }
                
                print("✅ Token刷新成功")
                completion(true, nil)
                
            case .failure(let error):
                print("❌ Token刷新失败: \(error.localizedDescription)")
                
                // 刷新失败，清除本地token，需要用户重新登录
                KeychainHelper.clearTokens()
                
                completion(false, error)
            }
        }
    }
    
    /// 清除所有存储的 token
    func clearTokens() {
        print("🗑️ TokenManager: 清除所有 token")
        KeychainHelper.clearTokens()
        // 清除其他与 token 相关的存储
        UserDefaults.standard.removeObject(forKey: "tokenExpiryDate")
        UserDefaults.standard.synchronize()
    }
}

// MARK: - Token响应模型
/// 用于解析token刷新接口的响应数据
private struct TokenResponse: Codable {
    /// 访问令牌
    let accessToken: String
    
    /// 刷新令牌（可选）
    let refreshToken: String?
    
    /// 过期时间（秒）
    let expiresIn: TimeInterval?
    
    /// 令牌类型（如：Bearer）
    let tokenType: String?
    
    // 使用CodingKeys自定义键名映射
    enum CodingKeys: String, CodingKey {
        case accessToken = "access_token"
        case refreshToken = "refresh_token"
        case expiresIn = "expires_in"
        case tokenType = "token_type"
    }
}

// MARK: - 身份验证响应模型
/// 用于解析身份验证接口的响应数据
private struct IdentityCheckResponse: Codable {
    /// 是否有效
    let isValid: Bool
    
    /// 用户ID（可选）
    let userId: String?
    
    /// 过期时间（可选）
    let expiresAt: Date?
    
    enum CodingKeys: String, CodingKey {
        case isValid = "is_valid"
        case userId = "user_id"
        case expiresAt = "expires_at"
    }
}

// MARK: - 通知名称
/// 定义应用中使用的通知名称
extension Notification.Name {
    /// 用户登出通知
    /// 当token失效或用户主动登出时发送
    static let userDidLogout = Notification.Name("UserDidLogoutNotification")
}
