package com.sundot.airport.exam.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sundot.airport.common.dto.ModuleStatisticsDTO;
import com.sundot.airport.common.exception.ServiceException;
import com.sundot.airport.exam.domain.Ques;
import com.sundot.airport.exam.domain.QuesCat;
import com.sundot.airport.exam.domain.WeakModuleAnalysis;
import com.sundot.airport.exam.domain.WeakModuleRule;
import com.sundot.airport.exam.mapper.DailyAnswerRecordMapper;
import com.sundot.airport.exam.mapper.WeakModuleAnalysisMapper;
import com.sundot.airport.exam.service.IQuestionSelectionService;
import com.sundot.airport.exam.service.IWeakModuleRuleService;
import com.sundot.airport.exam.service.IWeakModuleStatisticsService;
import com.sundot.airport.exam.common.service.QuesCatService;
import com.sundot.airport.exam.common.service.QuesService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <b>功能名：</b>QuestionSelectionServiceImpl<br>
 * <b>说明：</b> 组题算法Service实现 <br>
 * <b>著作权：</b> Copyright (C) 2025 SUNDOT CORPORATION<br>
 * <b>修改履历：
 *
 * @author Simon Lin
 */
@Service
public class QuestionSelectionServiceImpl implements IQuestionSelectionService {

    private static final Logger log = LoggerFactory.getLogger(QuestionSelectionServiceImpl.class);

    @Autowired
    private QuesService quesService;

    @Autowired
    private QuesCatService quesCatService;

    @Autowired
    private DailyAnswerRecordMapper dailyAnswerRecordMapper;

    @Autowired
    private WeakModuleAnalysisMapper weakModuleAnalysisMapper;

    @Autowired
    private IWeakModuleStatisticsService weakModuleStatisticsService;

    @Autowired
    private IWeakModuleRuleService weakModuleRuleService;

    /**
     * 历史记录阈值：3次
     */
    private static final int HISTORY_THRESHOLD = 3;

    /**
     * 薄弱模块题目占比：60%
     */
    private static final double WEAK_MODULE_RATIO = 0.6;

    @Override
    public List<Ques> generateQuestions(Long userId, int questionCount) {
        if (questionCount < 1) {
            throw new ServiceException("题目数量至少为1道");
        }

        log.info("开始为用户 {} 生成 {} 道题目", userId, questionCount);

        // 使用随机出题算法
        return generateQuestionsRandomly(questionCount);
    }

    /**
     * 基于薄弱项分析的智能出题算法（备用方法）
     * <p>
     * 说明：该方法保留作为备用，当前系统使用随机出题算法。
     * 如需启用，请修改 generateQuestions() 方法调用此方法。
     * </p>
     */
    private List<Ques> generateQuestionsWithWeakModuleAnalysisBackup(Long userId, int questionCount) {
        log.info("使用薄弱项智能出题算法");

        // 1. 获取启用的规则
        WeakModuleRule rule = weakModuleRuleService.getActiveRule();
        if (rule == null) {
            throw new ServiceException("没有启用的薄弱项规则，使用随机算法");
        }

        // 2. 分析TOP3薄弱模块
        List<ModuleStatisticsDTO> top3WeakModules = weakModuleStatisticsService
                .analyzeTop3WeakModulesWithActiveRule(userId);

        if (CollUtil.isEmpty(top3WeakModules)) {
            log.info("用户 {} 没有薄弱模块数据，使用随机算法", userId);
            return generateQuestionsRandomly(questionCount);
        }

        // 3. 计算每个薄弱模块的题目数量
        Map<String, Integer> moduleQuestionCountMap = calculateModuleQuestionCount(
                top3WeakModules, rule, questionCount);

        log.info("题目分配计划：{}", moduleQuestionCountMap);

        // 4. 从薄弱模块中抽取题目
        List<Ques> selectedQuestions = new ArrayList<>();
        Set<String> selectedQuestionIds = new HashSet<>();

        for (Map.Entry<String, Integer> entry : moduleQuestionCountMap.entrySet()) {
            String moduleName = entry.getKey();
            Integer count = entry.getValue();

            if (count > 0) {
                // 根据模块名称查找qc_id
                List<Ques> moduleQuestions = selectQuestionsByModuleName(
                        moduleName, count, selectedQuestionIds);

                selectedQuestions.addAll(moduleQuestions);
                moduleQuestions.forEach(q -> selectedQuestionIds.add(q.getQuId()));

                log.info("从模块 [{}] 选取了 {} 道题目", moduleName, moduleQuestions.size());
            }
        }

        // 5. 剩余题目从非TOP3模块随机补充
        if (selectedQuestions.size() < questionCount) {
            int needMore = questionCount - selectedQuestions.size();
            log.info("从TOP3薄弱模块已选取 {} 道题，剩余 {} 道题将从其他模块随机补充",
                    selectedQuestions.size(), needMore);

            // 从所有模块（包括非TOP3）中随机选择，排除已选题目
            List<Ques> moreQuestions = selectRandomQuestions(needMore, selectedQuestionIds);
            selectedQuestions.addAll(moreQuestions);

            log.info("从其他模块补充了 {} 道题", moreQuestions.size());
        }

        if (selectedQuestions.size() < questionCount) {
            throw new ServiceException("题库题目数量不足，无法生成" + questionCount + "道题");
        }

        // 6. 打乱题目顺序
        Collections.shuffle(selectedQuestions);

        log.info("智能出题完成，共生成 {} 道题目", selectedQuestions.size());
        return selectedQuestions;
    }

    /**
     * 计算每个薄弱模块的题目数量
     * 注意：TOP3占比之和通常不是100%，剩余题目从其他模块随机选择
     */
    private Map<String, Integer> calculateModuleQuestionCount(
            List<ModuleStatisticsDTO> top3WeakModules,
            WeakModuleRule rule,
            int totalQuestionCount) {

        Map<String, Integer> result = new LinkedHashMap<>();

        // 获取TOP3占比配置
        BigDecimal[] ratios = {
                rule.getWmrTop1Ratio(),
                rule.getWmrTop2Ratio(),
                rule.getWmrTop3Ratio()
        };

        // 按照配置的占比分配题目（向下取整）
        int allocatedCount = 0;

        for (int i = 0; i < Math.min(top3WeakModules.size(), 3); i++) {
            ModuleStatisticsDTO module = top3WeakModules.get(i);
            BigDecimal ratio = ratios[i];
            String moduleName = module.getModuleName();

            // 向下取整分配题目
            int count = ratio.multiply(new BigDecimal(totalQuestionCount))
                    .setScale(0, RoundingMode.DOWN)
                    .intValue();

            if (count > 0) {
                result.put(moduleName, count);
                allocatedCount += count;
            }
        }

        log.info("TOP3模块分配：{} 道题，剩余 {} 道题将从其他模块随机选择",
                allocatedCount, totalQuestionCount - allocatedCount);

        // 注意：剩余的题目不在这里处理，由调用方从其他模块随机选择

        return result;
    }

    /**
     * 根据模块名称选择题目
     */
    private List<Ques> selectQuestionsByModuleName(String moduleName, int count, Set<String> excludeIds) {
        // 1. 根据模块名称查找对应的 qc_id
        LambdaQueryWrapper<QuesCat> catWrapper = new LambdaQueryWrapper<>();
        catWrapper.eq(QuesCat::getQcName, moduleName);
        catWrapper.eq(QuesCat::getDelStatus, 0);
        List<QuesCat> categories = quesCatService.list(catWrapper);

        if (CollUtil.isEmpty(categories)) {
            log.warn("未找到模块名称 [{}] 对应的分类", moduleName);
            return new ArrayList<>();
        }

        // 2. 从该分类中选择题目
        List<String> qcIds = categories.stream()
                .map(QuesCat::getQcId)
                .collect(Collectors.toList());

        LambdaQueryWrapper<Ques> quesWrapper = new LambdaQueryWrapper<>();
        quesWrapper.in(Ques::getQcId, qcIds);
        quesWrapper.eq(Ques::getDelStatus, 0);
        quesWrapper.notIn(!excludeIds.isEmpty(), Ques::getQuId, excludeIds);

        List<Ques> questions = quesService.list(quesWrapper);

        if (CollUtil.isEmpty(questions)) {
            log.warn("模块 [{}] 中没有可用题目", moduleName);
            return new ArrayList<>();
        }

        // 3. 随机选择指定数量的题目
        Collections.shuffle(questions);
        return questions.stream()
                .limit(count)
                .collect(Collectors.toList());
    }

    @Override
    public List<Ques> generateQuestionsRandomly(int questionCount) {
        // 查询所有有效题目
        LambdaQueryWrapper<Ques> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Ques::getDelStatus, 0);
        List<Ques> allQuestions = quesService.list(wrapper);

        if (CollUtil.isEmpty(allQuestions)) {
            throw new ServiceException("题库中没有可用题目");
        }

        if (allQuestions.size() < questionCount) {
            throw new ServiceException("题库题目数量不足，需要" + questionCount + "道题，实际只有" + allQuestions.size() + "道题");
        }

        // 随机打乱题目顺序
        Collections.shuffle(allQuestions);

        // 返回前N道题
        return allQuestions.stream()
                .limit(questionCount)
                .collect(Collectors.toList());
    }

    @Override
    public List<Ques> generateQuestionsWithoutHistory(int questionCount) {
        // 获取所有题目分类
        LambdaQueryWrapper<QuesCat> catWrapper = new LambdaQueryWrapper<>();
        catWrapper.eq(QuesCat::getDelStatus, 0);
        List<QuesCat> categories = quesCatService.list(catWrapper);

        if (CollUtil.isEmpty(categories)) {
            throw new ServiceException("题目分类未配置");
        }

        // 打乱分类顺序
        Collections.shuffle(categories);

        // 计算需要从多少个分类中选题
        int categoryCount = Math.min(questionCount, categories.size());
        List<QuesCat> selectedCategories = categories.subList(0, categoryCount);

        // 从每个分类中随机选1道题
        List<Ques> selectedQuestions = new ArrayList<>();
        Set<String> selectedQuestionIds = new HashSet<>();

        for (QuesCat category : selectedCategories) {
            // 查询该分类下的所有题目
            LambdaQueryWrapper<Ques> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(Ques::getQcId, category.getQcId());
            wrapper.eq(Ques::getDelStatus, 0);
            List<Ques> categoryQuestions = quesService.list(wrapper);

            if (CollUtil.isEmpty(categoryQuestions)) {
                continue;
            }

            // 过滤已选题目，随机选1道
            List<Ques> availableQuestions = categoryQuestions.stream()
                    .filter(q -> !selectedQuestionIds.contains(q.getQuId()))
                    .collect(Collectors.toList());

            if (!availableQuestions.isEmpty()) {
                Collections.shuffle(availableQuestions);
                Ques selected = availableQuestions.get(0);
                selectedQuestions.add(selected);
                selectedQuestionIds.add(selected.getQuId());
            }
        }

        // 如果题目数量不足，从剩余分类补充
        if (selectedQuestions.size() < questionCount) {
            int needMore = questionCount - selectedQuestions.size();
            List<Ques> moreQuestions = selectRandomQuestions(needMore, selectedQuestionIds);
            selectedQuestions.addAll(moreQuestions);
        }

        if (selectedQuestions.size() < questionCount) {
            throw new ServiceException("题库题目数量不足，无法生成" + questionCount + "道题");
        }

        return selectedQuestions;
    }

    @Override
    public List<Ques> generateQuestionsWithHistory(Long userId, int questionCount) {
        // 查询用户的薄弱模块分析数据（按正确率升序）
        List<WeakModuleAnalysis> weakModules = weakModuleAnalysisMapper.selectWeakModulesByUserId(userId);

        if (CollUtil.isEmpty(weakModules)) {
            // 如果没有薄弱模块数据，按无历史场景处理
            return generateQuestionsWithoutHistory(questionCount);
        }

        // 计算薄弱模块题目数量（60%）
        int weakModuleCount = (int) Math.ceil(questionCount * WEAK_MODULE_RATIO);
        int normalModuleCount = questionCount - weakModuleCount;

        List<Ques> selectedQuestions = new ArrayList<>();
        Set<String> selectedQuestionIds = new HashSet<>();

        // 1. 找出核心薄弱模块（正确率最低的）
        WeakModuleAnalysis weakestModule = weakModules.get(0);
        BigDecimal lowestRate = weakestModule.getWmaLast3Rate();

        // 找出所有正确率等于最低正确率的模块（可能有多个并列最低）
        List<WeakModuleAnalysis> coreWeakModules = new ArrayList<>();
        for (WeakModuleAnalysis module : weakModules) {
            if (module.getWmaLast3Rate().compareTo(lowestRate) == 0) {
                coreWeakModules.add(module);
            }
        }

        // 如果有多个并列最低的模块，随机选择
        Collections.shuffle(coreWeakModules);

        // 2. 从薄弱模块中选题
        List<String> weakModuleIds = coreWeakModules.stream()
                .limit(2) // 最多选2个薄弱模块
                .map(WeakModuleAnalysis::getWmaModuleId)
                .collect(Collectors.toList());

        for (String moduleId : weakModuleIds) {
            int questionsNeeded = weakModuleCount / weakModuleIds.size();
            List<Ques> moduleQuestions = selectQuestionsFromModule(moduleId, questionsNeeded, selectedQuestionIds);
            selectedQuestions.addAll(moduleQuestions);
            moduleQuestions.forEach(q -> selectedQuestionIds.add(q.getQuId()));

            weakModuleCount -= moduleQuestions.size();
        }

        // 如果薄弱模块题目不够，从次薄弱模块补充
        if (weakModuleCount > 0 && weakModules.size() > coreWeakModules.size()) {
            List<WeakModuleAnalysis> secondaryWeakModules = weakModules.subList(
                    coreWeakModules.size(),
                    Math.min(coreWeakModules.size() + 2, weakModules.size())
            );

            for (WeakModuleAnalysis module : secondaryWeakModules) {
                if (weakModuleCount <= 0) break;
                List<Ques> moduleQuestions = selectQuestionsFromModule(
                        module.getWmaModuleId(), weakModuleCount, selectedQuestionIds);
                selectedQuestions.addAll(moduleQuestions);
                moduleQuestions.forEach(q -> selectedQuestionIds.add(q.getQuId()));
                weakModuleCount -= moduleQuestions.size();
            }
        }

        // 3. 从非薄弱模块中选题（40%）
        if (normalModuleCount > 0) {
            List<String> normalModuleIds = getNormalModuleIds(weakModules);
            if (!normalModuleIds.isEmpty()) {
                Collections.shuffle(normalModuleIds);
                int questionsPerModule = Math.max(1, normalModuleCount / normalModuleIds.size());

                for (String moduleId : normalModuleIds) {
                    if (normalModuleCount <= 0) break;
                    List<Ques> moduleQuestions = selectQuestionsFromModule(
                            moduleId, Math.min(questionsPerModule, normalModuleCount), selectedQuestionIds);
                    selectedQuestions.addAll(moduleQuestions);
                    moduleQuestions.forEach(q -> selectedQuestionIds.add(q.getQuId()));
                    normalModuleCount -= moduleQuestions.size();
                }
            }
        }

        // 4. 如果题目数量还不够，随机补充
        if (selectedQuestions.size() < questionCount) {
            int needMore = questionCount - selectedQuestions.size();
            List<Ques> moreQuestions = selectRandomQuestions(needMore, selectedQuestionIds);
            selectedQuestions.addAll(moreQuestions);
        }

        if (selectedQuestions.size() < questionCount) {
            throw new ServiceException("题库题目数量不足，无法生成" + questionCount + "道题");
        }

        // 打乱题目顺序
        Collections.shuffle(selectedQuestions);

        return selectedQuestions;
    }

    @Override
    public boolean hasEnoughHistory(Long userId) {
        int count = dailyAnswerRecordMapper.countRecentRecords(userId, HISTORY_THRESHOLD);
        return count >= HISTORY_THRESHOLD;
    }

    /**
     * 从指定分类中选择指定数量的题目
     */
    private List<Ques> selectQuestionsFromModule(String categoryId, int count, Set<String> excludeIds) {
        LambdaQueryWrapper<Ques> wrapper = new LambdaQueryWrapper<>();
        // 使用 qc_id 查询题目，如果 categoryId 为 null，则查询未分类的题目
        if (categoryId == null || categoryId.isEmpty()) {
            wrapper.isNull(Ques::getQcId);
        } else {
            wrapper.eq(Ques::getQcId, categoryId);
        }
        wrapper.eq(Ques::getDelStatus, 0);
        wrapper.notIn(!excludeIds.isEmpty(), Ques::getQuId, excludeIds);

        List<Ques> categoryQuestions = quesService.list(wrapper);

        if (CollUtil.isEmpty(categoryQuestions)) {
            return new ArrayList<>();
        }

        Collections.shuffle(categoryQuestions);
        return categoryQuestions.stream()
                .limit(count)
                .collect(Collectors.toList());
    }

    /**
     * 随机选择题目（不限模块）
     */
    private List<Ques> selectRandomQuestions(int count, Set<String> excludeIds) {
        LambdaQueryWrapper<Ques> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Ques::getDelStatus, 0);
        wrapper.notIn(!excludeIds.isEmpty(), Ques::getQuId, excludeIds);

        List<Ques> allQuestions = quesService.list(wrapper);

        if (CollUtil.isEmpty(allQuestions)) {
            return new ArrayList<>();
        }

        Collections.shuffle(allQuestions);
        return allQuestions.stream()
                .limit(count)
                .collect(Collectors.toList());
    }

    /**
     * 获取非薄弱分类ID列表
     */
    private List<String> getNormalModuleIds(List<WeakModuleAnalysis> weakModules) {
        LambdaQueryWrapper<QuesCat> catWrapper = new LambdaQueryWrapper<>();
        catWrapper.eq(QuesCat::getDelStatus, 0);
        List<QuesCat> allCategories = quesCatService.list(catWrapper);

        Set<String> weakCategoryIds = weakModules.stream()
                .map(WeakModuleAnalysis::getWmaModuleId)
                .collect(Collectors.toSet());

        return allCategories.stream()
                .map(QuesCat::getQcId)
                .filter(id -> !weakCategoryIds.contains(id))
                .collect(Collectors.toList());
    }
}
