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

import cn.dev33.satoken.stp.StpUtil;
import com.seer.teach.common.enums.QuestionResultEnums;
import com.seer.teach.common.enums.teacher.ModuleEnum;
import com.seer.teach.teacher.common.llm.req.QuestionsCorrectLlmReq;
import com.seer.teach.teacher.common.llm.resp.QuestionsCorrectLlmResult;
import com.seer.teach.teacher.common.req.QuestionCorrectReq;
import com.seer.teach.teacher.common.req.QuestionsCorrectReq;
import com.seer.teach.teacher.common.resp.QuestionsCorrectDTO;
import com.seer.teach.teacher.common.utils.TeacherUtils;
import com.seer.teach.teacher.module.entity.BankQuestionsEntity;
import com.seer.teach.teacher.module.entity.EvaluationQuestionsEntity;
import com.seer.teach.teacher.module.entity.EvaluationTasksEntity;
import com.seer.teach.teacher.service.BankQuestionsService;
import com.seer.teach.teacher.service.EvaluationQuestionsService;
import com.seer.teach.teacher.service.EvaluationTasksService;
import com.seer.teach.teacher.service.LlmRequestService;
import com.seer.teach.teacher.service.registry.questionsCorrect.QuestionsCorrectHandler;
import com.seer.teach.user.api.UserInfoServiceApi;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 题目批改处理器实现类，用于处理评估任务中的题目批改逻辑。
 * <p>
 * 此类实现了 {@link QuestionsCorrectHandler} 接口，主要功能包括：
 * - 调用大模型服务进行题目批改；
 * - 更新评估题目结果与学生作答信息；
 * - 更新评估任务的状态、准确率及平均难度等统计信息；
 * - 向用户推送批改结果，并增加经验值。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EvaluationQuestionsCorrectImpl implements QuestionsCorrectHandler {

    private final EvaluationQuestionsService evaluationQuestionsService;

    private final LlmRequestService llmRequestService;

    private final EvaluationTasksService evaluationTasksService;

    private final UserInfoServiceApi userInfoServiceApi;

    private final BankQuestionsService bankQuestionsService;

    /**
     * 处理题目批改请求
     *
     * @param params 题目批改请求参数，包含任务ID和题目列表
     * @return QuestionsCorrectDTO 批改结果数据传输对象，包含批改详情和统计信息
     */
    @Override
    @Transactional(rollbackFor = Exception.class,timeout = 20)
    public QuestionsCorrectDTO handler(QuestionsCorrectReq params) {
        // 获取当前登录用户ID
        Integer userId = StpUtil.getLoginIdAsInt();
        // 根据ID获取评估任务信息
        EvaluationTasksEntity task = evaluationTasksService.getById(params.getId());
        List<EvaluationQuestionsEntity> evaluationQuestions = evaluationQuestionsService.lambdaQuery()
                .eq(EvaluationQuestionsEntity::getTaskId, task.getId())
                .list();
        // 构建题目ID与问题ID的映射关系
        Map<Integer, Integer> idQuestionIdMaps = evaluationQuestions.stream()
                .collect(Collectors.toMap(EvaluationQuestionsEntity::getQuestionId, EvaluationQuestionsEntity::getId));
        // 构建LLM题目批改请求对象
        QuestionsCorrectLlmReq llmReq = llmRequestService.buildLlmQuestionCorrectLlmReq(userId, getType(), params.getQuestions(), idQuestionIdMaps);
        // 调用LLM服务进行题目批改
        QuestionsCorrectLlmResult llmResult = llmRequestService.requestLlmForQuestionsCorrect(llmReq);
        BigDecimal correctRate =
                updateEvaluationQuestions(params.getQuestions(), llmResult, task, evaluationQuestions);
        int useTimeWithSecond = updateTask(correctRate, idQuestionIdMaps.keySet(), task);
        userInfoServiceApi.addExperience(userId, llmResult.getRightQuestionIds().size());
        // 构建并返回批改结果
        return bankQuestionsService.buildCorrectResult(
                llmResult,idQuestionIdMaps, getType(), correctRate, task.getId(), idQuestionIdMaps.keySet(), useTimeWithSecond
        );
    }


    /**
     * 根据大模型返回的结果更新每道题的批改状态和学生的作答记录。
     *
     * @param params    用户提交的答案数据列表
     * @param llmResult 大模型返回的题目批改结果
     * @param task      当前评估任务实体
     * @return 返回本次练习的正确率（保留两位小数）
     */
    private BigDecimal updateEvaluationQuestions(List<QuestionCorrectReq> params, QuestionsCorrectLlmResult llmResult, EvaluationTasksEntity task, List<EvaluationQuestionsEntity> evaluationQuestions) {
        // 构建题目ID -> EvaluationQuestionsEntity 的映射，方便快速更新
        Map<Integer, EvaluationQuestionsEntity> questionMap = evaluationQuestions.stream()
                .collect(Collectors.toMap(EvaluationQuestionsEntity::getId, Function.identity()));
        // 构建题目ID -> 学生答案（拼接成逗号字符串，如果为空返回 "未答题"）
        Map<Integer, String> studentAnswerMap = params.stream()
                .collect(Collectors.toMap(
                        QuestionCorrectReq::getId,
                        q -> {
                            // 先合并成字符串
                            String joined = String.join(",", Optional.ofNullable(q.getAnswers()).orElse(Collections.emptyList()));
                            // 判断拼接结果是否为空，如果是则返回 "未答题"
                            return joined.isEmpty() ? "未答题" : joined;
                        }
                ));
        if (!llmResult.getRightQuestionIds().isEmpty()) {
            // 更新题目结果状态（0-正确，1-错误）
            llmResult.getRightQuestionIds().forEach(id -> {
                EvaluationQuestionsEntity eq = questionMap.get(id);
                eq.setResult(QuestionResultEnums.RIGHT.getCode());
            });
        }
        if (!llmResult.getWrongQuestionIds().isEmpty()) {
            llmResult.getWrongQuestionIds().forEach(id -> {
                EvaluationQuestionsEntity eq = questionMap.get(id);
                eq.setResult(QuestionResultEnums.WRONG.getCode());
            });
        }
        // 更新学生答案
        evaluationQuestions.forEach(eq -> eq.setStudentAnswer(studentAnswerMap.get(eq.getQuestionId())));
        // 批量更新数据库
        evaluationQuestionsService.updateBatchById(evaluationQuestions);
        return TeacherUtils.calculateAccuracy(params.size(), llmResult.getRightQuestionIds().size());
    }

    /**
     * 更新评估任务的相关统计数据，如答题耗时、正确率、结束时间以及平均难度。
     *
     * @param correctRate 本次练习的正确率
     * @param task        当前评估任务实体
     * @return 返回本次练习所用的时间（单位：秒）
     */
    private int updateTask(BigDecimal correctRate, Set<Integer> questionIds, EvaluationTasksEntity task) {
        // 获取任务实体并计算使用时间
        LocalDateTime startQuestionTime = task.getCreateTime();
        int seconds = (int) Duration.between(startQuestionTime, LocalDateTime.now()).getSeconds();
        task.setQuestionUseTime(seconds);
        task.setCorrectRate(correctRate);
        task.setQuestionEndTime(LocalDateTime.now());
        task.setStatus(2);

        // 计算所有题目的平均难度
        List<BigDecimal> allDifficulty = bankQuestionsService.listByIds(questionIds).stream()
                .map(BankQuestionsEntity::getDifficulty)
                .collect(Collectors.toList());
        BigDecimal avgDifficulty;
        if (!allDifficulty.isEmpty()) {
            BigDecimal sum = allDifficulty.stream()
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            avgDifficulty = sum.divide(
                    BigDecimal.valueOf(allDifficulty.size()),
                    2,
                    RoundingMode.HALF_UP
            );
            task.setAverageDifficulty(avgDifficulty);
        }
        // 更新任务信息
        evaluationTasksService.updateById(task);
        return seconds;
    }

    /**
     * 获取该处理器对应的模块类型编码。
     *
     * @return 模块枚举中定义的评估模块编码
     */
    @Override
    public Integer getType() {
        return ModuleEnum.EVALUATION.getCode();
    }
}
