package com.yd.csf.service.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;
import java.util.stream.Collectors;

/**
 * 异步聚合查询工具类
 * 专门用于接口中聚合查询多个数据实体的场景
 */
@Slf4j
@Component
public class AsyncQueryUtil {

    /**
     * 异步执行单个查询任务
     *
     * @param supplier 查询任务
     * @param taskName 任务名称（用于日志）
     * @return CompletableFuture
     */
    @Async("asyncQueryExecutor")
    public <T> CompletableFuture<T> asyncQuery(Supplier<T> supplier, String taskName) {
        long startTime = System.currentTimeMillis();
        try {
            log.info("开始异步查询任务: {}", taskName);
            T result = supplier.get();
            long costTime = System.currentTimeMillis() - startTime;
            log.info("异步查询任务完成: {}, 耗时: {}ms", taskName, costTime);
            return CompletableFuture.completedFuture(result);
        } catch (Exception e) {
            log.error("异步查询任务失败: {}, 错误: {}", taskName, e.getMessage(), e);
            // 使用兼容性工具类替代CompletableFuture.failedFuture()
            return CompletableFutureUtil.failedFuture(e);
        }
    }

    /**
     * 批量异步查询，等待所有任务完成
     *
     * @param tasks 查询任务列表
     * @return 所有查询结果的CompletableFuture
     */
    public <T> CompletableFuture<List<T>> batchAsyncQuery(List<CompletableFuture<T>> tasks) {
        return CompletableFutureUtil.allOf(tasks.toArray(new CompletableFuture[0]))
                .thenApply(v -> tasks.stream()
                        .map(CompletableFutureUtil::safeJoin)  // 使用安全的join方法
                        .collect(Collectors.toList()));
    }

    /**
     * 异步查询并设置超时时间
     *
     * @param supplier  查询任务
     * @param taskName  任务名称
     * @param timeoutMs 超时时间（毫秒）
     * @return CompletableFuture
     */
    @Async("asyncQueryExecutor")
    public <T> CompletableFuture<T> asyncQueryWithTimeout(Supplier<T> supplier, String taskName, long timeoutMs) {
        // 使用兼容性工具类的超时方法
        return CompletableFutureUtil.supplyAsyncWithTimeout(supplier, timeoutMs, TimeUnit.MILLISECONDS)
                .whenComplete((result, throwable) -> {
                    if (throwable != null) {
                        log.error("异步查询任务超时或失败: {}, 错误: {}", taskName, throwable.getMessage());
                    } else {
                        log.info("异步查询任务完成: {}", taskName);
                    }
                });
    }

    /**
     * 增强的异步查询方法，支持自定义异常处理
     */
    @Async("asyncQueryExecutor")
    public <T> CompletableFuture<T> enhancedAsyncQuery(Supplier<T> supplier, String taskName,
                                                       java.util.function.Function<Exception, T> exceptionHandler) {
        long startTime = System.currentTimeMillis();
        try {
            log.info("开始增强异步查询任务: {}", taskName);
            T result = supplier.get();
            long costTime = System.currentTimeMillis() - startTime;
            log.info("增强异步查询任务完成: {}, 耗时: {}ms", taskName, costTime);
            return CompletableFuture.completedFuture(result);
        } catch (Exception e) {
            log.error("增强异步查询任务失败: {}, 错误: {}", taskName, e.getMessage(), e);
            try {
                // 使用自定义异常处理器
                T fallbackResult = exceptionHandler.apply(e);
                return CompletableFuture.completedFuture(fallbackResult);
            } catch (Exception handlerException) {
                log.error("异常处理器执行失败: {}, 错误: {}", taskName, handlerException.getMessage(), handlerException);
                return CompletableFutureUtil.failedFuture(handlerException);
            }
        }
    }

    /**
     * 并行执行多个查询任务，返回第一个成功的结果
     */
    @SafeVarargs
    public final <T> CompletableFuture<T> firstSuccessAsyncQuery(String taskName, Supplier<T>... suppliers) {
        @SuppressWarnings("unchecked")
        CompletableFuture<T>[] futures = new CompletableFuture[suppliers.length];

        for (int i = 0; i < suppliers.length; i++) {
            final int index = i;
            futures[i] = asyncQuery(suppliers[i], taskName + "-" + (i + 1))
                    .exceptionally(e -> {
                        log.warn("查询任务 {} 失败: {}", taskName + "-" + (index + 1), e.getMessage());
                        return null; // 返回null表示失败，让其他任务继续
                    });
        }

        return CompletableFutureUtil.anyOf(futures)
                .thenApply(result -> {
                    if (result == null) {
                        throw new RuntimeException("所有查询任务都失败了: " + taskName);
                    }
                    return result;
                });
    }

    /**
     * 重试机制的异步查询
     */
    @Async("asyncQueryExecutor")
    public <T> CompletableFuture<T> retryAsyncQuery(Supplier<T> supplier, String taskName, int maxRetries, long retryDelayMs) {
        return retryAsyncQueryInternal(supplier, taskName, maxRetries, retryDelayMs, 0);
    }

    private <T> CompletableFuture<T> retryAsyncQueryInternal(Supplier<T> supplier, String taskName,
                                                             int maxRetries, long retryDelayMs, int currentRetry) {
        long startTime = System.currentTimeMillis();
        try {
            log.info("开始重试异步查询任务: {}, 重试次数: {}/{}", taskName, currentRetry, maxRetries);
            T result = supplier.get();
            long costTime = System.currentTimeMillis() - startTime;
            log.info("重试异步查询任务完成: {}, 重试次数: {}, 耗时: {}ms", taskName, currentRetry, costTime);
            return CompletableFuture.completedFuture(result);
        } catch (Exception e) {
            log.warn("重试异步查询任务失败: {}, 重试次数: {}, 错误: {}", taskName, currentRetry, e.getMessage());

            if (currentRetry < maxRetries) {
                // 延迟重试 - 使用thenCompose展平嵌套的CompletableFuture
                return CompletableFutureUtil.delayedFuture(retryDelayMs, TimeUnit.MILLISECONDS, () -> null)
                        .thenCompose(ignored -> retryAsyncQueryInternal(supplier, taskName, maxRetries, retryDelayMs, currentRetry + 1));
            } else {
                log.error("重试异步查询任务最终失败: {}, 最大重试次数: {}", taskName, maxRetries);
                return CompletableFutureUtil.failedFuture(e);
            }
        }
    }
}