package com.seer.teach.teacher.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.seer.teach.common.entity.BaseEntity;
import com.seer.teach.common.enums.MakeQuestionTypeEnums;
import com.seer.teach.common.enums.teacher.ReportTypeEnum;
import com.seer.teach.common.utils.DateUtils;
import com.seer.teach.iot.api.UserDeviceServiceApi;
import com.seer.teach.teacher.common.dto.ReportQuestionDTO;
import com.seer.teach.teacher.common.req.AiReportReq;
import com.seer.teach.teacher.common.req.ReportReq;
import com.seer.teach.teacher.common.resp.AiReportResp;
import com.seer.teach.teacher.common.resp.KeyValueResp;
import com.seer.teach.teacher.common.resp.SubjectCorrectRateResp;
import com.seer.teach.teacher.common.resp.UserReportResp;
import com.seer.teach.teacher.convert.AiReportConvert;
import com.seer.teach.teacher.convert.QuestionConvert;
import com.seer.teach.teacher.convert.ReportConvert;
import com.seer.teach.teacher.module.entity.*;
import com.seer.teach.teacher.service.*;
import com.seer.teach.teacher.util.RateUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.*;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * <p>
 * 学生学习报告服务实现类
 * </p>
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ReportServiceImpl implements ReportService {

    private static final String MINUTE = "分钟";

    private static final String SECOND_RATE = "次";

    private static final String PERCENT_SIGN = "%";

    private static final String FIRST_STUDY = "你近期首次学习，期待你的持续进步!";

    private static final String NOT_STUDY = "你%s还没有学习哦! 快去学习吧~";

    private static final String VERY_GREAT = "很棒哦! %s你的作业正确率提升了%d%%，继续保持优秀表现~";

    private static final String NOT_BAD = "不错哦! %s你的作业正确率提升了%d%%，请继续加油~";

    private static final String COME_ON = "加油哦! %s你的作业正确率有提升，再接再厉~";

    private static final String CONTINUE_STUDYING = "继续努力哦! %s你的作业正确率还有提升空间~";

    private static final String DON_LOSE_HEART = "别灰心哦！%s你的作业正确率有所下降，坚持学习一定会进步的~";

    private final EvaluationTasksService evaluationTasksService;

    private final UserDeviceServiceApi userDeviceServiceApi;

    private final ReadDurationsService readDurationsService;

    private final SubjectsService subjectsService;

    private final VersionsService versionsService;

    private final LessonsService lessonsService;

    private final PlansService plansService;

    /**
     * 根据设备ID获取学生的学习报告数据。
     *
     * @param deviceId 设备ID
     * @param model    查询时间范围模型（0: 当天；1: 当月）
     * @return 用户学习报告响应对象
     */
    @Override
    public UserReportResp reportByDeviceId(Integer deviceId, ReportReq model) {
        // 获取用户ID
        Integer userId = userDeviceServiceApi.getUserIdByDeviceId(deviceId);
        // 获取所有题目相关数据
        List<ReportQuestionDTO> allQuestions = getAllQuestionData(userId, model.getModel());

        if (allQuestions.isEmpty()) {
            return new UserReportResp(Collections.emptyList(), 0, 0, Collections.emptyList());
        }

        // 构建科目映射表
        Map<Integer, String> subjectMap = getSubjectMap(allQuestions);

        // 计算总题数
        int totalQuestions = allQuestions.stream()
                .mapToInt(ReportQuestionDTO::getQuestionCount)
                .sum();

        // 计算正确题数
        int totalCorrectQuestions = allQuestions.stream()
                .mapToInt(q -> q.getCorrectRate()
                        .multiply(BigDecimal.valueOf(q.getQuestionCount()))
                        .setScale(0, RoundingMode.HALF_UP)
                        .intValue())
                .sum();

        // 统计各科目的做题数量详情
        List<KeyValueResp> subjectDetail = getSubjectDetail(allQuestions, subjectMap);
        // 各科目正确率统计
        List<KeyValueResp> subjectCorrectRate = getSubjectCorrectRate(allQuestions, subjectMap);

        // 转换并返回结果
        return ReportConvert.INSTANCE.toUserReportResp(subjectDetail, totalQuestions, totalCorrectQuestions, subjectCorrectRate);
    }

    /**
     * 获取AI生成的学生学习报告信息。
     *
     * @param params AI报告请求参数
     * @return AI报告响应对象
     */
    @Override
    public AiReportResp getReport(AiReportReq params) {
        // 获取当前登录用户ID
        Integer userId = StpUtil.getLoginIdAsInt();
        log.info("获取AI报告，用户ID：{}", userId);

        // 设置查询起始时间和结束时间
        LocalDateTime startTime = DateUtils.getStartTime(params.getType());
        LocalDateTime endTime = LocalDateTime.now();

        // 查询课程、测评任务等数据
        List<LessonsEntity> lessons = fetchLessons(userId, startTime, endTime);
        List<EvaluationTasksEntity> evaluations = fetchEvaluations(userId, startTime, endTime);

        // 总学习时长（秒）及格式化显示
        int studySeconds = getTotalStudySeconds(lessons);
        String studyTime = DateUtils.formatSecondsToHourMinute(studySeconds, params.getType());
        // 做题次数
        String practiceCount = String.format("%d%s", lessons.size(), SECOND_RATE);

        // 题目总数与正确题数计算
        int totalLessonQ = getTotalQuestions(lessons);
        int totalEvalQ = getTotalQuestions(evaluations);
        int totalQ = totalLessonQ + totalEvalQ;

        BigDecimal totalCorrect = calculateTotalCorrect(lessons).add(calculateTotalCorrect(evaluations));

        // 正确率百分比
        String homeworkCorrectRate = totalQ == 0 ? "0%" :
                totalCorrect.divide(BigDecimal.valueOf(totalQ), 2, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100))
                        .setScale(0, RoundingMode.HALF_UP) + PERCENT_SIGN;

        // 按科目分组处理数据
        Map<Integer, List<Object>> subjectGroup = groupBySubject(lessons, evaluations);
        Map<Integer, String> subjectMap = getSubjectsByIds(subjectGroup.keySet());

        // 科目正确率列表构建
        List<SubjectCorrectRateResp> subjectRates = new ArrayList<>();
        for (Map.Entry<Integer, List<Object>> entry : subjectGroup.entrySet()) {
            subjectRates.add(buildSubjectRate(entry.getKey(), entry.getValue(), subjectMap));
        }

        // 阅读时长统计
        List<ReadDurationsEntity> readings = fetchReadDurations(userId, startTime, endTime);
        int readingSeconds = readings.stream()
                .map(ReadDurationsEntity::getDurationSeconds)
                .filter(Objects::nonNull)
                .reduce(0, Integer::sum);
        String readingTime = DateUtils.formatSecondsToHourAndMinute(readingSeconds);

        // 鼓励语句
        String encourage = generateEncouragement(params.getType(), homeworkCorrectRate, userId);

        // 日均学习时间
        long days = ChronoUnit.DAYS.between(startTime.toLocalDate(), endTime.toLocalDate()) + 1;
        String dailyStudyTime = (studySeconds / 60 / days) + MINUTE;

        // 返回最终AI报告结果
        return AiReportConvert.INSTANCE.toAiReportResp(studyTime, readingTime, practiceCount, encourage,
                dailyStudyTime, homeworkCorrectRate, subjectRates);
    }

    /**
     * 鼓励语句
     *
     * @param type        时间类型
     * @param correctRate 当前正确率
     * @return 鼓励语
     */
    private String generateEncouragement(ReportTypeEnum type, String correctRate, Integer userId) {
        // 时间段
        String timePeriod = type.getDesc();
        // 当前正确率
        BigDecimal currentRate = RateUtils.percentStrToRate(correctRate);

        // 如果正确率为0%，说明没有做题，返回鼓励语
        if (currentRate.compareTo(BigDecimal.ZERO) == 0) {
            return String.format(NOT_STUDY, timePeriod);
        }
        // 获取历史正确率进行对比
        Optional<BigDecimal> historyRateOpt = getHistoricalCorrectRate(userId, type);
        // 如果没有历史学习记录，返回提示语
        if (!historyRateOpt.isPresent()) {
            return FIRST_STUDY;
        }
        // 获取提升百分比
        BigDecimal historyRate = historyRateOpt.get();
        BigDecimal improvementPercent = RateUtils.calculateImprovementPercent(currentRate, historyRate);
        int improve = improvementPercent.intValue();
        if (improve >= 20) {
            return String.format(VERY_GREAT, timePeriod, improve);
        } else if (improve >= 10) {
            return String.format(NOT_BAD, timePeriod, improve);
        } else if (improve >= 5) {
            return String.format(COME_ON, timePeriod);
        } else if (improve > -5) {
            return String.format(CONTINUE_STUDYING, timePeriod);
        } else {
            return String.format(DON_LOSE_HEART, timePeriod);
        }
    }

    /**
     * 获取历史作业正确率
     *
     * @param userId 用户Id
     * @param type   时间类型
     * @return 历史作业正确率
     */
    private Optional<BigDecimal> getHistoricalCorrectRate(Integer userId, ReportTypeEnum type) {
        // 获取当前查询时间段的开始时间
        LocalDateTime currentTimeStart = DateUtils.getStartTime(type);

        // 查询当前时间段之前的学习记录，按时间倒序排列
        List<LessonsEntity> previousLessons = lessonsService.lambdaQuery()
                .eq(LessonsEntity::getUserId, userId)
                .lt(LessonsEntity::getCreateTime, currentTimeStart)
                .orderByDesc(LessonsEntity::getCreateTime)
                .list();

        List<EvaluationTasksEntity> previousEvaluations = evaluationTasksService.lambdaQuery()
                .eq(EvaluationTasksEntity::getUserId, userId)
                .lt(EvaluationTasksEntity::getCreateTime, currentTimeStart)
                .orderByDesc(EvaluationTasksEntity::getCreateTime)
                .list();

        // 合并并按时间倒序排序，找出最近一次学习会话的时间范围
        List<LocalDateTime> allCreateTimes = Stream.concat(
                        previousLessons.stream().map(LessonsEntity::getCreateTime),
                        previousEvaluations.stream().map(EvaluationTasksEntity::getCreateTime))
                .sorted(Collections.reverseOrder()).collect(Collectors.toList());
        if (allCreateTimes.isEmpty()) {
            return Optional.empty();
        }

        // 获取最近一次学习的时间
        LocalDateTime latestLearningTime = allCreateTimes.get(0);

        // 根据报告类型确定历史时间段
        LocalDateTime periodStart, periodEnd;

        switch (type) {
            case DAILY:
                // 查找最近一次学习的那一天的所有学习记录
                LocalDate learningDate = latestLearningTime.toLocalDate();
                periodStart = learningDate.atStartOfDay();
                periodEnd = learningDate.atTime(LocalTime.MAX);
                break;
            case WEEKLY:
                // 查找最近一次学习的那周
                LocalDate learningWeekStart = latestLearningTime.toLocalDate().with(DayOfWeek.MONDAY);
                LocalDate learningWeekEnd = learningWeekStart.plusDays(6);
                periodStart = learningWeekStart.atStartOfDay();
                periodEnd = learningWeekEnd.atTime(LocalTime.MAX);
                break;
            case MONTHLY:
                // 查找最近一次学习的那个月
                YearMonth learningMonth = YearMonth.from(latestLearningTime);
                periodStart = learningMonth.atDay(1).atStartOfDay();
                periodEnd = learningMonth.atEndOfMonth().atTime(LocalTime.MAX);
                break;
            default:
                return Optional.empty();
        }

        // 获取该历史时期的完整学习数据
        List<LessonsEntity> lessons = lessonsService.lambdaQuery()
                .eq(LessonsEntity::getUserId, userId)
                .ge(LessonsEntity::getCreateTime, periodStart)
                .le(LessonsEntity::getCreateTime, periodEnd)
                .list();

        List<EvaluationTasksEntity> evaluations = evaluationTasksService.lambdaQuery()
                .eq(EvaluationTasksEntity::getUserId, userId)
                .ge(EvaluationTasksEntity::getCreateTime, periodStart)
                .le(EvaluationTasksEntity::getCreateTime, periodEnd)
                .list();

        int totalQ = getTotalQuestions(lessons) + getTotalQuestions(evaluations);
        if (totalQ == 0) {
            return Optional.empty();
        }

        BigDecimal totalCorrect = calculateTotalCorrect(lessons).add(calculateTotalCorrect(evaluations));
        return Optional.of(totalCorrect.divide(BigDecimal.valueOf(totalQ), 2, RoundingMode.HALF_UP));
    }


    /**
     * 获取指定用户的全部题目数据（包括测评和计划中的题目）。
     *
     * @param userId 用户ID
     * @param model  时间筛选模式（0: 当天；1: 当月）
     * @return 所有题目数据集合
     */
    private List<ReportQuestionDTO> getAllQuestionData(Integer userId, Integer model) {
        List<ReportQuestionDTO> evaluations = fetchEvaluationQuestions(userId, model);
        List<ReportQuestionDTO> lessons = fetchLessonQuestions(userId, model);
        List<ReportQuestionDTO> plans = fetchPlanQuestions(userId, model);
        List<ReportQuestionDTO> result = new ArrayList<>();
        result.addAll(evaluations);
        result.addAll(plans);
        result.addAll(lessons);
        return result;
    }

    /**
     * 获取测评相关的题目数据。
     *
     * @param userId 用户ID
     * @param model  时间筛选模式（0: 当天；1: 当月）
     * @return 测评题目数据集合
     */
    private List<ReportQuestionDTO> fetchEvaluationQuestions(Integer userId, Integer model) {
        LambdaQueryWrapper<EvaluationTasksEntity> wrapper = getCommonQueryWrapper(model);
        wrapper.eq(EvaluationTasksEntity::getUserId, userId).isNotNull(EvaluationTasksEntity::getCorrectRate);
        List<EvaluationTasksEntity> evaluations = evaluationTasksService.list(wrapper);

        if (evaluations.isEmpty()) return Collections.emptyList();

        List<Integer> knowIds = new ArrayList<>();
        for (EvaluationTasksEntity e : evaluations) {
            knowIds.add(e.getKnowId());
        }
        Map<Integer, Integer> subjectIds = versionsService.getSubjectIdsByKnowIds(knowIds);

        List<ReportQuestionDTO> result = new ArrayList<>();
        for (EvaluationTasksEntity e : evaluations) {
            result.add(QuestionConvert.INSTANCE.toReportQuestionDTO(
                    subjectIds.get(e.getKnowId()),
                    MakeQuestionTypeEnums.EVALUATION.getCode(),
                    e.getCorrectRate(),
                    e.getQuestionCount(),
                    e.getCreateTime(),
                    e.getUpdateTime(),
                    e.getQuestionUseTime()
            ));
        }
        return result;
    }

    /**
     * 获取用户课程相关的问题报告数据
     *
     * @param userId 用户ID，用于筛选指定用户的课程数据
     * @param model 模型类型，用于构建通用查询条件
     * @return 返回封装成ReportQuestionDTO格式的课程问题列表，如果无数据则返回空列表
     */
    private List<ReportQuestionDTO> fetchLessonQuestions(Integer userId, Integer model){
        // 构建查询条件：获取指定用户且正确率不为空的课程数据
        LambdaQueryWrapper<LessonsEntity> wrapper = getCommonQueryWrapper(model);
        wrapper.eq(LessonsEntity::getUserId, userId).isNotNull(LessonsEntity::getCorrectRate);
        List<LessonsEntity> lessons = lessonsService.list(wrapper);

        if (lessons.isEmpty()) return Collections.emptyList();

        // 提取所有课程的知识点ID
        List<Integer> knowIds = new ArrayList<>();
        for (LessonsEntity e : lessons) {
            knowIds.add(e.getKnowId());
        }

        // 根据知识点ID获取对应的科目ID映射关系
        Map<Integer, Integer> subjectIds = versionsService.getSubjectIdsByKnowIds(knowIds);

        // 将课程数据转换为问题报告DTO格式
        List<ReportQuestionDTO> result = new ArrayList<>();
        for (LessonsEntity e : lessons) {
            result.add(QuestionConvert.INSTANCE.toReportQuestionDTO(
                    subjectIds.get(e.getKnowId()),
                    MakeQuestionTypeEnums.EVALUATION.getCode(),
                    e.getCorrectRate(),
                    e.getQuestionCount(),
                    e.getCreateTime(),
                    e.getUpdateTime(),
                    e.getQuestionUseTime()
            ));
        }
        return result;
    }


    /**
     * 获取复习计划中的题目数据。
     *
     * @param userId 用户ID
     * @param model  时间筛选模式（0: 当天；1: 当月）
     * @return 复习计划题目数据集合
     */
    private List<ReportQuestionDTO> fetchPlanQuestions(Integer userId, Integer model) {
        LambdaQueryWrapper<PlansEntity> wrapper = getCommonQueryWrapper(model);
        wrapper.eq(PlansEntity::getUserId, userId).isNotNull(PlansEntity::getCorrectRate);

        List<PlansEntity> plans = plansService.list(wrapper);
        if (plans.isEmpty()) return Collections.emptyList();

        Map<Integer, Integer> subjectIds = new HashMap<>();
        for (PlansEntity p : plans) {
            subjectIds.put(p.getId(), p.getSubjectId());
        }

        List<ReportQuestionDTO> result = new ArrayList<>();
        for (PlansEntity p : plans) {
            result.add(QuestionConvert.INSTANCE.toReportQuestionDTO(
                    subjectIds.get(p.getId()),
                    MakeQuestionTypeEnums.REVIEW.getCode(),
                    p.getCorrectRate(),
                    p.getQuestionCount(),
                    p.getCreateTime(),
                    p.getUpdateTime(),
                    0
            ));
        }
        return result;
    }

    /**
     * 构造通用的时间范围查询条件包装器。
     *
     * @param model 时间筛选模式（0: 当天；1: 当月）
     * @param <T>   实体类型继承自BaseEntity
     * @return 查询条件构造器
     */
    private <T extends BaseEntity> LambdaQueryWrapper<T> getCommonQueryWrapper(Integer model) {
        LambdaQueryWrapper<T> wrapper = new LambdaQueryWrapper<>();

        ZoneId zoneId = ZoneId.of("Asia/Shanghai");
        LocalDate today = LocalDate.now(zoneId);
        LocalDateTime start = null;
        LocalDateTime end = null;

        switch (model) {
            case 0:
                start = today.atStartOfDay();
                end = today.atTime(LocalTime.MAX);
                break;
            case 1:
                LocalDate firstDay = today.withDayOfMonth(1);
                LocalDate lastDay = firstDay.withDayOfMonth(firstDay.lengthOfMonth());
                start = firstDay.atStartOfDay();
                end = lastDay.atTime(LocalTime.MAX);
                break;
            default:
                break;
        }

        if (start != null && end != null) {
            wrapper.ge(BaseEntity::getCreateTime, start);
            wrapper.le(BaseEntity::getCreateTime, end);
        }
        return wrapper;
    }

    /**
     * 根据题目数据提取科目ID，并从数据库中加载对应名称。
     *
     * @param questions 题目数据集合
     * @return 科目ID到名称的映射关系
     */
    private Map<Integer, String> getSubjectMap(List<ReportQuestionDTO> questions) {
        Set<Integer> subjectIds = new HashSet<>();
        for (ReportQuestionDTO q : questions) {
            if (q.getSubjectId() != null) subjectIds.add(q.getSubjectId());
        }

        Map<Integer, String> subjectMap = new HashMap<>();
        for (SubjectsEntity s : subjectsService.listByIds(new ArrayList<>(subjectIds))) {
            subjectMap.put(s.getId(), s.getSubject());
        }
        return subjectMap;
    }

    /**
     * 统计各个科目的做题数量详情。
     *
     * @param questions  题目数据集合
     * @param subjectMap 科目ID到名称的映射
     * @return 科目名及其对应的做题数量列表
     */
    private List<KeyValueResp> getSubjectDetail(List<ReportQuestionDTO> questions, Map<Integer, String> subjectMap) {
        Map<String, Integer> countMap = new HashMap<>();
        for (ReportQuestionDTO q : questions) {
            String name = subjectMap.getOrDefault(q.getSubjectId(), "未知科目");
            countMap.put(name, countMap.getOrDefault(name, 0) + q.getQuestionCount());
        }

        List<KeyValueResp> result = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : countMap.entrySet()) {
            result.add(new KeyValueResp(entry.getKey(), entry.getValue()));
        }
        return result;
    }

    /**
     * 计算各个科目的平均正确率。
     *
     * @param questions  题目数据集合
     * @param subjectMap 科目ID到名称的映射
     * @return 科目名及其对应的正确率列表
     */
    private List<KeyValueResp> getSubjectCorrectRate(List<ReportQuestionDTO> questions, Map<Integer, String> subjectMap) {
        Map<Integer, List<ReportQuestionDTO>> grouped = new HashMap<>();
        for (ReportQuestionDTO q : questions) {
            if (q.getSubjectId() != null) {
                if (!grouped.containsKey(q.getSubjectId()))
                    grouped.put(q.getSubjectId(), new ArrayList<ReportQuestionDTO>());
                grouped.get(q.getSubjectId()).add(q);
            }
        }

        List<KeyValueResp> result = new ArrayList<>();
        for (Map.Entry<Integer, List<ReportQuestionDTO>> entry : grouped.entrySet()) {
            int totalQ = 0;
            int totalCorrect = 0;
            for (ReportQuestionDTO q : entry.getValue()) {
                totalQ += q.getQuestionCount();
                totalCorrect += q.getCorrectRate().multiply(BigDecimal.valueOf(q.getQuestionCount())).setScale(0, RoundingMode.HALF_UP).intValue();
            }
            int rate = totalQ == 0 ? 0 : totalCorrect * 100 / totalQ;
            result.add(new KeyValueResp(subjectMap.getOrDefault(entry.getKey(), "未知科目"), rate));
        }
        return result;
    }

    /**
     * 查询用户在时间段内的课程记录。
     *
     * @param userId      用户ID
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @return 课程实体列表
     */
    private List<LessonsEntity> fetchLessons(Integer userId, LocalDateTime startTime, LocalDateTime endTime) {
        return lessonsService.lambdaQuery()
                .eq(LessonsEntity::getUserId, userId)
                .ge(LessonsEntity::getStudyStartTime, startTime)
                .le(LessonsEntity::getStudyEndTime, endTime)
                .list();
    }

    /**
     * 查询用户在时间段内的测评任务记录。
     *
     * @param userId      用户ID
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @return 测评任务实体列表
     */
    private List<EvaluationTasksEntity> fetchEvaluations(Integer userId, LocalDateTime startTime, LocalDateTime endTime) {
        return evaluationTasksService.lambdaQuery()
                .eq(EvaluationTasksEntity::getUserId, userId)
                .ge(EvaluationTasksEntity::getQuestionStartTime, startTime)
                .le(EvaluationTasksEntity::getQuestionEndTime, endTime)
                .list();
    }

    /**
     * 查询用户在时间段内的阅读时长记录。
     *
     * @param userId      用户ID
     * @param startTime   开始时间
     * @param endTime     结束时间
     * @return 阅读时长实体列表
     */
    private List<ReadDurationsEntity> fetchReadDurations(Integer userId, LocalDateTime startTime, LocalDateTime endTime) {
        return readDurationsService.lambdaQuery()
                .eq(ReadDurationsEntity::getUserId, userId)
                .ge(ReadDurationsEntity::getStartTime, startTime)
                .le(ReadDurationsEntity::getEndTime, endTime)
                .list();
    }

    /**
     * 累加所有课程的学习时长（单位：秒）。
     *
     * @param lessons 课程实体列表
     * @return 总学习时长（秒）
     */
    private int getTotalStudySeconds(List<LessonsEntity> lessons) {
        int total = 0;
        for (LessonsEntity l : lessons) {
            if (l.getStudySeconds() != null) total += l.getStudySeconds();
        }
        return total;
    }

    /**
     * 累加所有实体中的题目数量。
     *
     * @param list 包含课程或测评任务的对象列表
     * @return 总题目数量
     */
    private int getTotalQuestions(List<?> list) {
        int total = 0;
        for (Object o : list) {
            if (o instanceof LessonsEntity) total += ((LessonsEntity) o).getQuestionCount();
            else if (o instanceof EvaluationTasksEntity) total += ((EvaluationTasksEntity) o).getQuestionCount();
        }
        return total;
    }

    /**
     * 累加所有实体中的正确题目数量。
     *
     * @param list 包含课程或测评任务的对象列表
     * @return 总正确题目数量
     */
    private BigDecimal calculateTotalCorrect(List<?> list) {
        BigDecimal total = BigDecimal.ZERO;
        for (Object o : list) {
            if (o instanceof LessonsEntity) {
                LessonsEntity l = (LessonsEntity) o;
                total = total.add(l.getCorrectRate().multiply(BigDecimal.valueOf(l.getQuestionCount())));
            } else if (o instanceof EvaluationTasksEntity) {
                EvaluationTasksEntity e = (EvaluationTasksEntity) o;
                total = total.add(e.getCorrectRate().multiply(BigDecimal.valueOf(e.getQuestionCount())));
            }
        }
        return total;
    }

    /**
     * 将课程和测评按科目进行分组。
     *
     * @param lessons       课程实体列表
     * @param evaluations   测评任务实体列表
     * @return 分组后的科目ID到对象列表的映射
     */
    private Map<Integer, List<Object>> groupBySubject(List<LessonsEntity> lessons, List<EvaluationTasksEntity> evaluations) {
        Map<Integer, List<Object>> map = new HashMap<>();
        for (LessonsEntity l : lessons) {
            if (l.getSubjectId() != null) {
                if (!map.containsKey(l.getSubjectId())) map.put(l.getSubjectId(), new ArrayList<Object>());
                map.get(l.getSubjectId()).add(l);
            }
        }
        for (EvaluationTasksEntity e : evaluations) {
            if (e.getSubjectId() != null) {
                if (!map.containsKey(e.getSubjectId())) map.put(e.getSubjectId(), new ArrayList<Object>());
                map.get(e.getSubjectId()).add(e);
            }
        }
        return map;
    }

    /**
     * 根据科目ID批量获取科目名称。
     *
     * @param ids 科目ID集合
     * @return 科目ID到名称的映射
     */
    private Map<Integer, String> getSubjectsByIds(Set<Integer> ids) {
        log.info("获取科目名称，ID集合: {}", ids);
        if (ids == null || ids.isEmpty()) {
            log.info("ID集合为空，返回空map");
            return new HashMap<>();
        }
        Map<Integer, String> map = new HashMap<>();
        for (SubjectsEntity s : subjectsService.listByIds(new ArrayList<>(ids))) {
            map.put(s.getId(), s.getSubject());
        }
        return map;
    }

    /**
     * 构建单个科目的正确率响应对象。
     *
     * @param subjectId   科目ID
     * @param list        属于该科目的课程/测评对象列表
     * @param subjectMap  科目ID到名称的映射
     * @return 科目正确率响应对象
     */
    private SubjectCorrectRateResp buildSubjectRate(Integer subjectId, List<Object> list, Map<Integer, String> subjectMap) {
        int totalQ = getTotalQuestions(list);
        BigDecimal totalC = calculateTotalCorrect(list);
        BigDecimal rate = totalQ == 0 ? BigDecimal.ZERO : totalC.divide(BigDecimal.valueOf(totalQ), 2, RoundingMode.HALF_UP);

        SubjectCorrectRateResp resp = new SubjectCorrectRateResp();
        resp.setId(subjectId);
        resp.setSubject(subjectMap.getOrDefault(subjectId, ""));
        resp.setRate(rate.multiply(BigDecimal.valueOf(100)).setScale(0, RoundingMode.HALF_UP) + PERCENT_SIGN);
        return resp;
    }

}
