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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.sundot.airport.common.exception.ServiceException;
import com.sundot.airport.exam.common.service.QuesOptService;
import com.sundot.airport.exam.common.service.QuesService;
import com.sundot.airport.exam.domain.*;
import com.sundot.airport.exam.dto.QuestionDTO;
import com.sundot.airport.exam.dto.StartTaskDTO;
import com.sundot.airport.exam.dto.SubmitAnswerDTO;
import com.sundot.airport.exam.dto.SubmitResultDTO;
import com.sundot.airport.exam.enums.AnswerStatusEnum;
import com.sundot.airport.exam.enums.DailyTaskStatusEnum;
import com.sundot.airport.exam.enums.SubmitTypeEnum;
import com.sundot.airport.exam.mapper.DailyAnswerRecordMapper;
import com.sundot.airport.exam.mapper.DailyTaskDetailMapper;
import com.sundot.airport.exam.mapper.DailyTaskMapper;
import com.sundot.airport.exam.mapper.WeakModuleAnalysisMapper;
import com.sundot.airport.exam.service.IDailyAnswerService;
import com.sundot.airport.exam.service.IWeakModuleAnalysisService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
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.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <b>功能名：</b>DailyAnswerServiceImpl<br>
 * <b>说明：</b> 每日答题Service实现 <br>
 * <b>著作权：</b> Copyright (C) 2025 SUNDOT CORPORATION<br>
 * <b>修改履历：
 *
 * @author Simon Lin
 */
@Service
public class DailyAnswerServiceImpl implements IDailyAnswerService {

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

    @Autowired
    private DailyTaskMapper dailyTaskMapper;

    @Autowired
    private DailyTaskDetailMapper dailyTaskDetailMapper;

    @Autowired
    private DailyAnswerRecordMapper dailyAnswerRecordMapper;

    @Autowired
    private WeakModuleAnalysisMapper weakModuleAnalysisMapper;

    @Autowired
    private QuesService quesService;

    @Autowired
    private QuesOptService quesOptService;

    @Autowired
    private IWeakModuleAnalysisService weakModuleAnalysisService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StartTaskDTO startTask(Long userId, String taskId) {
        // 1. 查询任务（taskId是业务主键dt_id）
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.eq(DailyTask::getDtId, taskId);
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        DailyTask task = dailyTaskMapper.selectOne(taskWrapper);

        if (task == null) {
            throw new ServiceException("任务不存在");
        }

        // 2. 验证任务归属
        if (!task.getDtUserId().equals(userId)) {
            throw new ServiceException("无权访问该任务");
        }

        // 3. 验证任务状态
        if (task.getDtStatus().equals(DailyTaskStatusEnum.COMPLETED.getCode())) {
            throw new ServiceException("任务已完成");
        }
        if (task.getDtStatus().equals(DailyTaskStatusEnum.EXPIRED.getCode())) {
            throw new ServiceException("任务已逾期");
        }

        // 4. 如果是首次开始，更新任务状态和开始时间
        if (task.getDtStatus().equals(DailyTaskStatusEnum.PENDING.getCode())) {
            task.setDtStatus(DailyTaskStatusEnum.IN_PROGRESS.getCode());
            task.setDtStartTime(new Date());
            task.setUpdateTime(new Date());
            task.setUpdateUid(userId.toString());
            dailyTaskMapper.updateById(task);
        }

        // 5. 查询任务明细
        LambdaQueryWrapper<DailyTaskDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DailyTaskDetail::getDtdTaskId, taskId);
        wrapper.eq(DailyTaskDetail::getDelStatus, 0);
        wrapper.orderByAsc(DailyTaskDetail::getDtdQuestionNo);
        List<DailyTaskDetail> details = dailyTaskDetailMapper.selectList(wrapper);

        if (CollUtil.isEmpty(details)) {
            throw new ServiceException("任务题目不存在");
        }

        // 6. 查询题目详情和选项
        List<String> questionIds = details.stream()
                .map(DailyTaskDetail::getDtdQuesId)
                .collect(Collectors.toList());

        LambdaQueryWrapper<Ques> quesWrapper = new LambdaQueryWrapper<>();
        quesWrapper.in(Ques::getQuId, questionIds);
        quesWrapper.eq(Ques::getDelStatus, 0);
        List<Ques> questions = quesService.list(quesWrapper);

        // 查询选项
        List<QuesOpt> options = quesOptService.byQuIdFindList(questionIds);
        Map<String, List<QuesOpt>> optionMap = options.stream()
                .collect(Collectors.groupingBy(QuesOpt::getQuId));

        // 7. 组装返回数据
        Map<String, Ques> questionMap = questions.stream()
                .collect(Collectors.toMap(Ques::getQuId, q -> q));

        List<QuestionDTO> questionDTOs = new ArrayList<>();
        for (DailyTaskDetail detail : details) {
            Ques ques = questionMap.get(detail.getDtdQuesId());
            if (ques == null) continue;

            QuestionDTO dto = new QuestionDTO();
            dto.setQuestionId(ques.getQuId());
            dto.setQuestionIndex(detail.getDtdQuestionNo());
            dto.setQuestionContent(ques.getQuContent());
            dto.setQuestionType(ques.getQuType().name());
            dto.setScore(detail.getDtdScore());

            // 设置选项（按sort排序）
            List<QuesOpt> quesOpts = optionMap.get(ques.getQuId());
            if (CollUtil.isNotEmpty(quesOpts)) {
                quesOpts.sort(Comparator.comparing(QuesOpt::getSort));
                if (quesOpts.size() > 0) dto.setOptionA(quesOpts.get(0).getQoOption());
                if (quesOpts.size() > 1) dto.setOptionB(quesOpts.get(1).getQoOption());
                if (quesOpts.size() > 2) dto.setOptionC(quesOpts.get(2).getQoOption());
                if (quesOpts.size() > 3) dto.setOptionD(quesOpts.get(3).getQoOption());
            }

            questionDTOs.add(dto);
        }

        // 8. 计算剩余时间
        Integer remainingTime = getRemainingTime(userId, taskId);

        StartTaskDTO result = new StartTaskDTO();
        result.setTaskId(taskId);
        result.setStartTime(task.getDtStartTime() != null ?
                new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(task.getDtStartTime()) : null);
        result.setRemainingTime(remainingTime);
        result.setQuestions(questionDTOs);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SubmitResultDTO submitAnswer(Long userId, SubmitAnswerDTO dto) {
        // 1. 查询任务（taskId是业务主键dt_id）
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.eq(DailyTask::getDtId, dto.getTaskId());
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        DailyTask task = dailyTaskMapper.selectOne(taskWrapper);

        if (task == null) {
            throw new ServiceException("任务不存在");
        }

        // 2. 验证任务归属
        if (!task.getDtUserId().equals(userId)) {
            throw new ServiceException("无权访问该任务");
        }

        // 3. 验证任务状态
        if (!task.getDtStatus().equals(DailyTaskStatusEnum.IN_PROGRESS.getCode())) {
            throw new ServiceException("任务状态异常，无法提交");
        }

        // 4. 查询任务明细
        LambdaQueryWrapper<DailyTaskDetail> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DailyTaskDetail::getDtdTaskId, dto.getTaskId());
        wrapper.eq(DailyTaskDetail::getDelStatus, 0);
        wrapper.orderByAsc(DailyTaskDetail::getDtdQuestionNo);
        List<DailyTaskDetail> details = dailyTaskDetailMapper.selectList(wrapper);

        // 5. 查询题目和正确答案
        List<String> questionIds = details.stream()
                .map(DailyTaskDetail::getDtdQuesId)
                .collect(Collectors.toList());

        List<Ques> questions = quesService.byTpqIdList(questionIds);
        Map<String, Ques> questionMap = questions.stream()
                .collect(Collectors.toMap(Ques::getQuId, q -> q));

        // 查询所有选项（用于判断sort起始值）
        List<QuesOpt> allOptions = quesOptService.byQuIdFindList(questionIds);

        // 查询正确答案选项
        List<QuesOpt> correctOptions = quesOptService.byQuIdFindCorrectList(questionIds);
        Map<String, String> correctAnswerMap = buildCorrectAnswerMap(correctOptions, allOptions);

        // 6. 构建用户答案Map
        Map<String, String> userAnswerMap = dto.getAnswers().stream()
                .collect(Collectors.toMap(
                        SubmitAnswerDTO.AnswerItem::getQuestionId,
                        SubmitAnswerDTO.AnswerItem::getUserAnswer,
                        (v1, v2) -> v1
                ));

        // 7. 判题并计算得分
        BigDecimal actualScore = BigDecimal.ZERO;
        int correctCount = 0;
        List<SubmitResultDTO.AnswerDetail> answerDetails = new ArrayList<>();

        for (DailyTaskDetail detail : details) {
            String questionId = detail.getDtdQuesId();
            String userAnswer = userAnswerMap.getOrDefault(questionId, "");
            String correctAnswer = correctAnswerMap.getOrDefault(questionId, "");

            // 判断是否正确
            boolean isCorrect = checkAnswer(userAnswer, correctAnswer);
            BigDecimal scoreEarned = isCorrect ? detail.getDtdScore() : BigDecimal.ZERO;

            if (isCorrect) {
                correctCount++;
                actualScore = actualScore.add(scoreEarned);
            }

            // 更新任务明细
            detail.setDtdAnswerStatus(AnswerStatusEnum.ANSWERED.name());  // 设置答题状态为已答题
            detail.setDtdIsCorrect(isCorrect);
            detail.setDtdUserAnswer(userAnswer);
            detail.setDtdCorrectAnswer(correctAnswer);
            detail.setDtdActualScore(scoreEarned);
            detail.setDtdAnswerTime(new Date());
            detail.setUpdateTime(new Date());
            detail.setUpdateUid(userId.toString());
            dailyTaskDetailMapper.updateById(detail);

            // 组装答题详情
            Ques ques = questionMap.get(questionId);
            SubmitResultDTO.AnswerDetail answerDetail = new SubmitResultDTO.AnswerDetail();
            answerDetail.setQuestionId(questionId);
            answerDetail.setQuestionIndex(detail.getDtdQuestionNo());
            answerDetail.setQuestionContent(ques != null ? ques.getQuContent() : "");
            answerDetail.setUserAnswer(userAnswer);
            answerDetail.setCorrectAnswer(correctAnswer);
            answerDetail.setIsCorrect(isCorrect);
            answerDetail.setScore(detail.getDtdScore());
            answerDetail.setActualScore(scoreEarned);
            answerDetails.add(answerDetail);
        }

        // 8. 计算答题时间
        Integer timeUsed = 0;
        if (task.getDtStartTime() != null) {
            long elapsedSeconds = Duration.between(
                    task.getDtStartTime().toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime(),
                    LocalDateTime.now()
            ).getSeconds();
            timeUsed = (int) elapsedSeconds;
        }

        // 9. 保存答题记录（汇总信息）
        saveDailyAnswerRecordSummary(userId, task, actualScore, correctCount, details.size() - correctCount, timeUsed);

        // 10. 更新任务状态
        task.setDtStatus(DailyTaskStatusEnum.COMPLETED.getCode());
        task.setDtSubmitTime(new Date());
        task.setDtTotalScore(actualScore);
        task.setUpdateTime(new Date());
        task.setUpdateUid(userId.toString());
        dailyTaskMapper.updateById(task);

        // 11. 更新薄弱模块分析
        try {
            weakModuleAnalysisService.updateUserWeakModuleAnalysis(userId);
        } catch (Exception e) {
            log.error("更新薄弱模块分析失败 - userId: {}", userId, e);
        }

        // 12. 组装返回结果
        BigDecimal correctRate = BigDecimal.valueOf(correctCount)
                .divide(BigDecimal.valueOf(details.size()), 4, RoundingMode.HALF_UP)
                .multiply(BigDecimal.valueOf(100));

        SubmitResultDTO result = new SubmitResultDTO();
        result.setTaskId(dto.getTaskId());
        result.setTotalScore(task.getDtTotalScore());
        result.setActualScore(actualScore);
        result.setCorrectCount(correctCount);
        result.setTotalCount(details.size());
        result.setCorrectRate(correctRate);
        result.setDetails(answerDetails);

        return result;
    }

    @Override
    public Integer getRemainingTime(Long userId, String taskId) {
        // 查询任务（taskId是业务主键dt_id）
        LambdaQueryWrapper<DailyTask> taskWrapper = new LambdaQueryWrapper<>();
        taskWrapper.eq(DailyTask::getDtId, taskId);
        taskWrapper.eq(DailyTask::getDelStatus, 0);
        DailyTask task = dailyTaskMapper.selectOne(taskWrapper);

        if (task == null || task.getDtStartTime() == null) {
            return null;
        }

        // 验证任务归属
        if (!task.getDtUserId().equals(userId)) {
            return null;
        }

        // 如果已完成或逾期，返回0
        if (task.getDtStatus().equals(DailyTaskStatusEnum.COMPLETED.getCode()) ||
                task.getDtStatus().equals(DailyTaskStatusEnum.EXPIRED.getCode())) {
            return 0;
        }

        // 计算已用时间
        LocalDateTime startTime = task.getDtStartTime().toInstant()
                .atZone(ZoneId.systemDefault()).toLocalDateTime();
        LocalDateTime now = LocalDateTime.now();
        long elapsedSeconds = Duration.between(startTime, now).getSeconds();

        // 计算剩余时间
        long remainingSeconds = task.getDtTimeLimit() - elapsedSeconds;

        return remainingSeconds > 0 ? (int) remainingSeconds : 0;
    }

    /**
     * 构建正确答案Map
     * <p>
     * 单选/判断：取选项序号（1,2,3,4 对应ABCD）
     * 多选：按序号排序后拼接（如 "1,2,3"）
     * 注意：需要判断每道题的sort是从0还是从1开始
     * - 查询该题目的所有选项，找到最小sort值
     * - 如果最小sort=0，则需要+1转换为1-based
     * - 如果最小sort=1，则直接使用
     * </p>
     *
     * @param correctOptions 正确答案选项列表
     * @param allOptions     所有选项列表（用于判断sort起始值）
     * @return 题目ID -> 正确答案字符串的Map
     */
    private Map<String, String> buildCorrectAnswerMap(List<QuesOpt> correctOptions, List<QuesOpt> allOptions) {
        // 先按题目分组所有选项，用于判断每道题的sort起始值
        Map<String, List<QuesOpt>> allOptionsMap = allOptions.stream()
                .collect(Collectors.groupingBy(QuesOpt::getQuId));

        // 计算每道题的sort起始值（0-based或1-based）
        Map<String, Boolean> questionIsZeroBasedMap = new HashMap<>();
        for (Map.Entry<String, List<QuesOpt>> entry : allOptionsMap.entrySet()) {
            List<QuesOpt> opts = entry.getValue();
            if (!opts.isEmpty()) {
                // 找到该题目的最小sort值
                int minSort = opts.stream()
                        .mapToInt(QuesOpt::getSort)
                        .min()
                        .orElse(0);
                questionIsZeroBasedMap.put(entry.getKey(), minSort == 0);
            }
        }

        // 按题目分组正确答案选项
        Map<String, List<QuesOpt>> groupedCorrectOptions = correctOptions.stream()
                .collect(Collectors.groupingBy(QuesOpt::getQuId));

        // 构建正确答案Map
        Map<String, String> correctAnswerMap = new HashMap<>();
        for (Map.Entry<String, List<QuesOpt>> entry : groupedCorrectOptions.entrySet()) {
            String questionId = entry.getKey();
            List<QuesOpt> opts = entry.getValue();
            if (opts.isEmpty()) {
                continue;
            }

            opts.sort(Comparator.comparing(QuesOpt::getSort));

            // 根据该题目的sort起始值决定是否需要+1转换
            boolean isZeroBased = questionIsZeroBasedMap.getOrDefault(questionId, false);
            String answer = opts.stream()
                    .map(opt -> String.valueOf(isZeroBased ? opt.getSort() + 1 : opt.getSort()))
                    .collect(Collectors.joining(","));

            correctAnswerMap.put(questionId, answer);
        }

        return correctAnswerMap;
    }

    /**
     * 检查答案是否正确
     */
    private boolean checkAnswer(String userAnswer, String correctAnswer) {
        if (userAnswer == null || correctAnswer == null) {
            return false;
        }

        // 去除空格
        userAnswer = userAnswer.trim();
        correctAnswer = correctAnswer.trim();

        // 如果是多选，需要排序后比较
        if (userAnswer.contains(",") || correctAnswer.contains(",")) {
            String[] userParts = userAnswer.split(",");
            String[] correctParts = correctAnswer.split(",");

            Arrays.sort(userParts);
            Arrays.sort(correctParts);

            return Arrays.equals(userParts, correctParts);
        }

        return userAnswer.equals(correctAnswer);
    }

    /**
     * 保存答题记录（汇总信息）
     */
    private void saveDailyAnswerRecordSummary(Long userId, DailyTask task, BigDecimal actualScore,
                                              int correctCount, int wrongCount, Integer timeUsed) {
        DailyAnswerRecord record = new DailyAnswerRecord();
        record.setDarId(IdUtil.getSnowflakeNextIdStr());
        record.setDarUserId(userId);
        record.setDarTaskId(task.getDtId());
        record.setDarSetNo(1); // 当前只支持单套题
        record.setDarStartTime(task.getDtStartTime());
        record.setDarSubmitTime(new Date());
        record.setDarTimeUsed(timeUsed);
        record.setDarTotalScore(task.getDtTotalScore());
        record.setDarActualScore(actualScore);
        record.setDarCorrectCount(correctCount);
        record.setDarWrongCount(wrongCount);
        record.setDarTimeoutCount(0); // 当前逻辑没有超时未答题

        // 计算正确率
        int totalQuestions = correctCount + wrongCount;
        BigDecimal correctRate = totalQuestions > 0 ?
                BigDecimal.valueOf(correctCount)
                        .divide(BigDecimal.valueOf(totalQuestions), 4, RoundingMode.HALF_UP)
                        .multiply(BigDecimal.valueOf(100)) : BigDecimal.ZERO;
        record.setDarCorrectRate(correctRate);

        record.setDarSubmitType(SubmitTypeEnum.MANUAL.name());
        record.setDelStatus(0);
        record.setCreateTime(new Date());
        record.setCreateUid(userId.toString());

        dailyAnswerRecordMapper.insert(record);
    }

}
