package com.ycwl.basic.integration.kafka.scheduler;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 账号级别的人脸识别调度器管理
 * 每个账号（accessKeyId/appId）拥有独立的:
 * 1. 线程池 - 资源隔离
 * 2. QPS调度器 - 精确控制每个账号的QPS
 * 3. 任务队列 - 独立排队
 * <p>
 * 核心优势:
 * - 多个阿里云账号互不影响,充分利用多账号QPS优势
 * - 百度云和阿里云任务完全隔离
 * - 每个账号严格按自己的QPS限制调度
 */
@Slf4j
@Component
public class AccountFaceSchedulerManager {

    // 账号 -> 调度器上下文的映射
    private final ConcurrentHashMap<String, AccountSchedulerContext> schedulers = new ConcurrentHashMap<>();

    /**
     * 获取或创建账号的调度器上下文
     *
     * @param accountKey 账号唯一标识 (accessKeyId 或 appId)
     * @param cloudType  云类型 ("ALI" 或 "BAIDU")
     * @param qps        该账号的QPS限制
     * @return 调度器上下文
     */
    public AccountSchedulerContext getOrCreateScheduler(
            String accountKey,
            String cloudType,
            float qps
    ) {
        return schedulers.computeIfAbsent(accountKey, key -> {
            log.info("创建账号调度器: accountKey={}, cloudType={}, qps={}",
                    accountKey, cloudType, qps);
            return createSchedulerContext(accountKey, cloudType, qps);
        });
    }

    /**
     * 创建调度器上下文
     */
    private AccountSchedulerContext createSchedulerContext(
            String accountKey,
            String cloudType,
            float qps
    ) {
        // 根据云类型和QPS计算线程池参数
        ThreadPoolConfig poolConfig = calculateThreadPoolConfig(cloudType, qps);

        // 创建独立线程池
        ThreadPoolExecutor executor = new ThreadPoolExecutor(
                poolConfig.coreSize,
                poolConfig.maxSize,
                60L, TimeUnit.SECONDS,
                new LinkedBlockingQueue<>(poolConfig.queueCapacity),
                new ThreadFactoryBuilder()
                        .setNameFormat(cloudType.toLowerCase() + "-" + accountKey.substring(0, Math.min(8, accountKey.length())) + "-%d")
                        .build(),
                new ThreadPoolExecutor.AbortPolicy() // 快速失败,避免阻塞
        );

        // 创建QPS调度器
        QpsScheduler scheduler = new QpsScheduler(
                Math.round(qps),  // 每秒调度的任务数
                poolConfig.maxConcurrent,  // 最大并发数
                executor
        );

        log.info("账号调度器创建成功: accountKey={}, threadPool=[core={}, max={}, queue={}], qps={}, maxConcurrent={}",
                accountKey,
                poolConfig.coreSize,
                poolConfig.maxSize,
                poolConfig.queueCapacity,
                Math.round(qps),
                poolConfig.maxConcurrent);

        return new AccountSchedulerContext(accountKey, cloudType, executor, scheduler);
    }

    /**
     * 根据云类型和QPS计算线程池参数
     */
    private ThreadPoolConfig calculateThreadPoolConfig(String cloudType, float qps) {
        // 假设每个任务平均执行时间 500ms
        int avgExecutionTimeMs = 500;

        // 所需线程数 = QPS × 平均执行时间(秒)
        int requiredThreads = Math.max(1, (int) Math.ceil(qps * avgExecutionTimeMs / 1000.0));

        // 核心线程数 = 所需线程数 × 2 (留有余量)
        int coreSize = requiredThreads * 2;

        // 最大线程数 = 核心线程数 × 2
        int maxSize = coreSize * 2;

        // 队列容量 = QPS × 60 (可容纳1分钟的任务)
        int queueCapacity = Math.max(100, (int) (qps * 60));

        // 最大并发数 = 所需线程数 × 1.5 (防止瞬时抖动)
        int maxConcurrent = Math.max(2, (int) (requiredThreads * 1.5));

        log.debug("计算线程池参数 - cloudType={}, qps={}, requiredThreads={}, coreSize={}, maxSize={}, queue={}, maxConcurrent={}",
                cloudType, qps, requiredThreads, coreSize, maxSize, queueCapacity, maxConcurrent);

        return new ThreadPoolConfig(coreSize, maxSize, queueCapacity, maxConcurrent);
    }

    /**
     * 获取所有调度器的监控信息
     */
    public Map<String, AccountSchedulerStats> getAllStats() {
        Map<String, AccountSchedulerStats> stats = new HashMap<>();
        schedulers.forEach((key, ctx) -> {
            stats.put(key, new AccountSchedulerStats(
                    ctx.getAccountKey(),
                    ctx.getCloudType(),
                    ctx.getExecutor().getActiveCount(),
                    ctx.getExecutor().getQueue().size(),
                    ctx.getScheduler().getQueueSize()
            ));
        });
        return stats;
    }

    /**
     * 关闭所有调度器 (应用关闭时调用)
     */
    public void shutdownAll() {
        log.info("关闭所有账号调度器, total={}", schedulers.size());
        schedulers.forEach((key, ctx) -> {
            try {
                ctx.getScheduler().shutdown();
                ctx.getExecutor().shutdown();
            } catch (Exception e) {
                log.error("关闭调度器失败, accountKey={}", key, e);
            }
        });
    }

    /**
     * 线程池配置
     */
    @Data
    @AllArgsConstructor
    static class ThreadPoolConfig {
        int coreSize;
        int maxSize;
        int queueCapacity;
        int maxConcurrent;
    }

    /**
     * 账号调度器统计信息
     */
    @Data
    @AllArgsConstructor
    public static class AccountSchedulerStats {
        String accountKey;
        String cloudType;
        int activeThreads;
        int executorQueueSize;
        int schedulerQueueSize;
    }
}
