package com.fs.app.taskService.impl;

import com.alibaba.fastjson.JSON;
import com.fs.app.taskService.SopUserLogsInfoByIsDaysNotStudy;
import com.fs.course.mapper.FsCourseWatchLogMapper;
import com.fs.qw.domain.QwExternalContact;
import com.fs.qw.mapper.QwExternalContactMapper;
import com.fs.sop.domain.SopUserLogs;
import com.fs.sop.domain.SopUserLogsInfo;
import com.fs.sop.params.QwRatingConfig;
import com.fs.sop.service.ISopUserLogsInfoService;
import com.fs.sop.service.ISopUserLogsService;
import com.fs.system.service.ISysConfigService;
import com.fs.voice.utils.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class SopUserLogsInfoByIsDaysNotStudyImpl implements SopUserLogsInfoByIsDaysNotStudy {


    @Autowired
    private FsCourseWatchLogMapper fsCourseWatchLogMapper;

    @Autowired
    private ISysConfigService configService;

    @Autowired
    private QwExternalContactMapper qwExternalContactMapper;

    @Autowired
    private ISopUserLogsInfoService iSopUserLogsInfoService;

    @Autowired
    private ISopUserLogsService iSopUserLogsService;

    @Autowired
    private ExecutorService sopRatingExecutor;  // 自定义线程池

    // 任务队列
    private final BlockingQueue<SopUserLogs> taskQueue = new LinkedBlockingQueue<>(10000);

    private volatile boolean running = true;
    //批量更新队列
    private final List<CompletableFuture<Void>> updateFutures = Collections.synchronizedList(new ArrayList<>());

    private final Object configLock = new Object();


    private  volatile QwRatingConfig qwRatingConfig;

    // 启动时初始化消费者线程
    @PostConstruct
    public void init() {

        loadCourseConfig();

        int consumerCount = Runtime.getRuntime().availableProcessors(); // 消费者线程数，默认 CPU 核心数
        for (int i = 0; i < consumerCount; i++) {
            sopRatingExecutor.submit(this::consumeTasks); // 提交消费者任务
        }

    }

    private void loadCourseConfig() {
        try {
            String json = configService.selectConfigByKey("qwRating:config");
            QwRatingConfig config = JSON.parseObject(json, QwRatingConfig.class);
            if (!StringUtil.strIsNullOrEmpty(json) && config != null) {
                qwRatingConfig = config;
                log.info("Loaded qwRating.config successfully.");
            } else {
                log.error("Failed to load course.config from configService.");
            }
        } catch (Exception e) {
            log.error("Exception while loading qwRating.config: {}", e.getMessage(), e);
        }
    }



    @Override
    public void restoreByIsDaysNotStudy() {

        // 分页加载并放入队列
        int pageSize = 1000;
        int offset = 0;
        List<SopUserLogs> sopUserLogs;

        // 获取缓存的配置
        QwRatingConfig config;
        synchronized(configLock) {
            config = qwRatingConfig;
        }

        do {
            sopUserLogs = iSopUserLogsService.meetsTherestoreByIsDaysNotStudy(offset, pageSize,config.getNotStudyDays());
            if (!sopUserLogs.isEmpty()) {
                sopUserLogs.forEach(item -> {
                    try {
                        taskQueue.put(item); // 将任务放入队列
                    } catch (InterruptedException e) {
                        log.error("任务放入队列失败，sopId: {}", item.getSopId(), e);
                        Thread.currentThread().interrupt();
                    }
                });
                offset += pageSize;
            }
        } while (!sopUserLogs.isEmpty());


        // 等待队列处理完成
        CompletableFuture.runAsync(() -> {
            while (!taskQueue.isEmpty()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    log.error("等待队列处理时中断", e);
                    Thread.currentThread().interrupt();
                }
            }
        }).join(); // 等待任务完成

    }

    private void consumeTasks() {
        if (!running && taskQueue.isEmpty()) {
            log.info("没有评级任务需要处理");
            return; // 如果队列为空且没有正在运行的线程，则直接返回
        }

        while (running) {
            try {
                SopUserLogs item = taskQueue.poll(1, TimeUnit.SECONDS); // 等待 1 秒
                if (item != null) {
                    processRestoreByIsDaysNotStudy(item);
                }
            } catch (Exception e) {
                log.error("消费者线程异常", e);
            }
        }
    }

    private void processRestoreByIsDaysNotStudy(SopUserLogs item) {

        // 获取缓存的配置
        QwRatingConfig config;
        synchronized(configLock) {
            config = qwRatingConfig;
        }

        List<SopUserLogsInfo> infos = iSopUserLogsInfoService.selectRestoreByIsDaysNotStudy(
                item.getSopId(), item.getId());

        if (infos == null || infos.isEmpty()) {
            log.error("当前营期没有E级客户-sopId：{},营期id:{}", item.getSopId(), item.getId());
            return;
        }

        List<QwExternalContact> contacts = infos.stream()
                .map(info -> processUserLog(info, config))
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        if (!contacts.isEmpty()) {
            batchUpdateQwExternalContact(contacts);
        }
    }

    private void batchUpdateQwExternalContact(List<QwExternalContact> contacts) {
        // 9. 优化分批逻辑
        int total = contacts.size();
        for (int i = 0; i < total; i += 300) {
            List<QwExternalContact> batch = contacts.subList(i, Math.min(i + 300, total));

            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
                try {
                    qwExternalContactMapper.batchUpdateQwExternalByIsDaysNotStudy(batch);
                    iSopUserLogsInfoService.batchUpdateSopUserLogsInfoByIsDaysNotStudy(batch);
                } catch (Exception e) {
                    log.error("批量更新异常, 批次大小: {}", batch.size(), e);
                }
            }, sopRatingExecutor);

            updateFutures.add(future);
        }
    }

    @PreDestroy
    public void shutdown() {
        running = false;  // 标记消费者停止
        log.info("正在关闭线程池...");

        // **等待任务队列处理完毕**
        while (!taskQueue.isEmpty()) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                log.warn("等待任务队列处理完成时被中断", e);
            }
        }

        // **确保所有  的任务完成**
        log.info("等待所有批量更新任务完成...");
        CompletableFuture.allOf(updateFutures.toArray(new CompletableFuture[0])).join();

        // 关闭线程池
        sopRatingExecutor.shutdown();
        try {
            if (!sopRatingExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
                List<Runnable> pendingTasks = sopRatingExecutor.shutdownNow();
                log.warn("强制关闭线程池，未完成任务数: {}", pendingTasks.size());
            }
        } catch (InterruptedException e) {
            sopRatingExecutor.shutdownNow();
            Thread.currentThread().interrupt();
        }
        log.info("线程池和消费者已完全关闭");
    }

    /**
    * 只计算时长，恢复E级客户到D级
    */
    private QwExternalContact processUserLog(SopUserLogsInfo logsInfo, QwRatingConfig config) {
        try {

            Long externalId = logsInfo.getExternalId();
            if (externalId == null) {
                return null;
            }

            Integer sumDuration = fsCourseWatchLogMapper.selectFsCourseWatchLogByByIsDaysNotStudy(externalId, config.getNotStudyDays());

            if (sumDuration!=null && sumDuration>0) {
                QwExternalContact externalContact = new QwExternalContact();
                externalContact.setId(externalId);
                externalContact.setSopUserLogsInfoId(logsInfo.getId());
                externalContact.setLevel(4);  // 从E级恢复到D级
                externalContact.setLevelType(1);  // 升级
                externalContact.setIsDaysNotStudy(0);  // 标记为非连续未看课
                log.info("客户从E级恢复到D级，externalId: {}, logsInfoId: {}", externalId, logsInfo.getId());
                return externalContact;
            }

            return null;

        } catch (Exception e) {
            log.error("计算用户积分异常，用户：{}", logsInfo, e);
            return null;
        }
    }


}
