package com.narutohuo.xindazhou.common.network.operator

import com.narutohuo.xindazhou.common.network.response.ApiResponse
import kotlinx.coroutines.delay
import kotlin.time.Duration
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.seconds

/**
 * 重试机制（参考 Sandwich Retry）
 * 
 * 支持自动重试失败的请求，使用指数退避策略
 * 
 * 使用方式：
 * ```kotlin
 * val response = retryRequest(
 *     times = 3,
 *     initialDelayMillis = 1000,
 *     shouldRetry = { it is ApiResponse.Exception }
 * ) {
 *     api.getData()
 * }
 * ```
 */

/**
 * 重试请求
 * 
 * 如果请求失败且满足重试条件，会自动重试指定次数
 * 
 * @param times 最大重试次数（包含首次请求）
 * @param initialDelayMillis 初始延迟时间（毫秒）
 * @param maxDelayMillis 最大延迟时间（毫秒），防止延迟过长
 * @param factor 延迟因子，每次重试延迟时间 = 上次延迟 * factor
 * @param shouldRetry 判断是否应该重试的函数，返回 true 则重试
 * @param block 需要重试的请求函数
 * @return 最后一次请求的结果
 * 
 * 示例：
 * ```kotlin
 * val response = retryRequest(
 *     times = 3,                      // 最多重试 3 次（包含首次）
 *     initialDelayMillis = 1000,      // 初始延迟 1 秒
 *     maxDelayMillis = 10000,         // 最大延迟 10 秒
 *     factor = 2.0,                   // 延迟翻倍（指数退避）
 *     shouldRetry = { response ->     // 只有网络异常才重试
 *         response is ApiResponse.Exception
 *     }
 * ) {
 *     api.login(request)
 * }
 * ```
 */
suspend inline fun <T> retryRequest(
    times: Int = 3,
    initialDelayMillis: Long = 1000,
    maxDelayMillis: Long = 10000,
    factor: Double = 2.0,
    crossinline shouldRetry: (ApiResponse<T>) -> Boolean = { it is ApiResponse.Exception },
    crossinline block: suspend () -> ApiResponse<T>
): ApiResponse<T> {
    require(times > 0) { "重试次数必须大于 0" }
    require(initialDelayMillis > 0) { "初始延迟必须大于 0" }
    require(factor > 0) { "延迟因子必须大于 0" }
    
    var currentDelay = initialDelayMillis
    var lastResponse: ApiResponse<T>? = null
    
    // 执行首次请求
    lastResponse = block()
    
    // 如果首次成功或不需要重试，直接返回
    if (!shouldRetry(lastResponse)) {
        return lastResponse
    }
    
    // 重试剩余次数（times - 1 次，因为已经执行了首次）
    repeat(times - 1) {
        // 等待延迟时间（指数退避）
        delay(currentDelay)
        
        // 执行重试请求
        lastResponse = block()
        
        // 如果成功或不需要重试，提前返回
        if (!shouldRetry(lastResponse)) {
            return lastResponse
        }
        
        // 计算下次延迟时间（指数退避）
        currentDelay = (currentDelay * factor).toLong().coerceAtMost(maxDelayMillis)
    }
    
    // 返回最后一次请求的结果
    return lastResponse ?: block()
}

/**
 * 重试请求（Duration 版本，更现代）
 * 
 * 如果请求失败且满足重试条件，会自动重试指定次数
 * 
 * @param times 最大重试次数（包含首次请求）
 * @param initialDelay 初始延迟时间
 * @param maxDelay 最大延迟时间，防止延迟过长
 * @param factor 延迟因子，每次重试延迟时间 = 上次延迟 * factor
 * @param shouldRetry 判断是否应该重试的函数，返回 true 则重试
 * @param block 需要重试的请求函数
 * @return 最后一次请求的结果
 * 
 * 示例：
 * ```kotlin
 * val response = retryRequest(
 *     times = 3,                      // 最多重试 3 次（包含首次）
 *     initialDelay = 1.seconds,      // 初始延迟 1 秒
 *     maxDelay = 10.seconds,         // 最大延迟 10 秒
 *     factor = 2.0,                   // 延迟翻倍（指数退避）
 *     shouldRetry = { response ->     // 只有网络异常才重试
 *         response is ApiResponse.Exception
 *     }
 * ) {
 *     api.login(request)
 * }
 * ```
 */
suspend inline fun <T> retryRequest(
    times: Int = 3,
    initialDelay: Duration = 1.seconds,
    maxDelay: Duration = 10.seconds,
    factor: Double = 2.0,
    crossinline shouldRetry: (ApiResponse<T>) -> Boolean = { it is ApiResponse.Exception },
    crossinline block: suspend () -> ApiResponse<T>
): ApiResponse<T> {
    return retryRequest(
        times = times,
        initialDelayMillis = initialDelay.inWholeMilliseconds,
        maxDelayMillis = maxDelay.inWholeMilliseconds,
        factor = factor,
        shouldRetry = shouldRetry,
        block = block
    )
}

/**
 * 重试请求（简化版本）
 * 
 * 使用默认配置重试请求
 * 
 * @param times 最大重试次数（默认 3 次）
 * @param shouldRetry 判断是否应该重试的函数（默认：只有网络异常才重试）
 * @param block 需要重试的请求函数
 * @return 最后一次请求的结果
 * 
 * 示例：
 * ```kotlin
 * val response = retryRequest(
 *     times = 3,
 *     shouldRetry = { it is ApiResponse.Exception }
 * ) {
 *     api.getData()
 * }
 * ```
 */
suspend inline fun <T> retryRequest(
    times: Int = 3,
    crossinline shouldRetry: (ApiResponse<T>) -> Boolean = { it is ApiResponse.Exception },
    crossinline block: suspend () -> ApiResponse<T>
): ApiResponse<T> {
    return retryRequest(
        times = times,
        initialDelayMillis = 1000,
        maxDelayMillis = 10000,
        factor = 2.0,
        shouldRetry = shouldRetry,
        block = block
    )
}

/**
 * 重试请求（最简版本）
 * 
 * 只指定重试次数，使用默认的指数退避策略和重试条件
 * 
 * @param times 最大重试次数（默认 3 次）
 * @param block 需要重试的请求函数
 * @return 最后一次请求的结果
 * 
 * 示例：
 * ```kotlin
 * val response = retryRequest(times = 3) {
 *     api.getData()
 * }
 * ```
 */
suspend inline fun <T> retryRequest(
    times: Int = 3,
    crossinline block: suspend () -> ApiResponse<T>
): ApiResponse<T> {
    return retryRequest(
        times = times,
        shouldRetry = { it is ApiResponse.Exception },
        block = block
    )
}
