package com.hotwj.platform.securityManagement.trainingProgress.service;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.hotwj.platform.config.courseResource.domain.bo.HotCourseResourceBo;
import com.hotwj.platform.config.courseResource.domain.vo.HotCourseResourceVo;
import com.hotwj.platform.config.courseResource.service.IHotCourseResourceService;
import com.hotwj.platform.securityManagement.training.domain.vo.HotTrainingVo;
import com.hotwj.platform.securityManagement.training.mapper.HotTrainingMapper;
import com.hotwj.platform.securityManagement.trainingAnswer.mapper.HotTrainingAnswerRecordMapper;
import com.hotwj.platform.securityManagement.trainingCourseConfig.domain.bo.HotTrainingCourseConfigBo;
import com.hotwj.platform.securityManagement.trainingCourseConfig.domain.vo.HotTrainingCourseConfigVo;
import com.hotwj.platform.securityManagement.trainingCourseConfig.service.IHotTrainingCourseConfigService;
import com.hotwj.platform.securityManagement.trainingCourseRecord.domain.HotTrainingCourseRecord;
import com.hotwj.platform.securityManagement.trainingCourseRecord.mapper.HotTrainingCourseRecordMapper;
import com.hotwj.platform.securityManagement.trainingParticipant.domain.HotTrainingParticipant;
import com.hotwj.platform.securityManagement.trainingParticipant.mapper.HotTrainingParticipantMapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.utils.StringUtils;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class TrainingProgressService {

    private final HotTrainingMapper trainingMapper;
    private final IHotTrainingCourseConfigService trainingCourseConfigService;
    private final IHotCourseResourceService courseResourceService;
    private final HotTrainingCourseRecordMapper trainingCourseRecordMapper;
    private final HotTrainingParticipantMapper trainingParticipantMapper;
    private final HotTrainingAnswerRecordMapper trainingAnswerRecordMapper;

    /**
     * 同步并计算培训进度
     * <p>
     * 算法说明：
     * 1. 总体进度 = (Σ所有课程进度 + 最终考试进度) / 总指标数
     * 2. 单门课程进度计算：
     * - 有随堂练习：视频观看比例 * 75% + 随堂练习完成状态(0或1) * 25%
     * - 无随堂练习：视频观看比例 * 100%
     * 3. 最终考试进度：完成考试计 100%，未完成计 0% (仅在培训配置了试卷时计入总指标)
     * <p>
     * 示例：
     * 假设培训包含 2 门课程和 1 份试卷（总指标数 = 3）：
     * - 课程1（有练习）：视频看满且练习已做 -> 100%
     * - 课程2（无练习）：视频看了一半 -> 50%
     * - 最终试卷：尚未参加 -> 0%
     * - 最终同步进度 = (100 + 50 + 0) / 3 = 50%
     *
     * @param companyId  公司ID
     * @param trainingId 培训ID
     * @param userId     用户ID
     */
    public void syncProgress(Long companyId, Long trainingId, String userId) {
        if (companyId == null || trainingId == null || StringUtils.isBlank(userId)) {
            return;
        }

        HotTrainingParticipant participant = trainingParticipantMapper.selectOne(
                Wrappers.<HotTrainingParticipant>lambdaQuery()
                        .eq(HotTrainingParticipant::getCompanyId, companyId)
                        .eq(HotTrainingParticipant::getTrainingId, trainingId)
                        .eq(HotTrainingParticipant::getUserId, userId)
                        .eq(HotTrainingParticipant::getIsDeleted, 0L)
        );
        if (participant == null) {
            return;
        }

        HotTrainingVo training = trainingMapper.selectVoById(trainingId);
        boolean hasPaper = training != null && StringUtils.isNotBlank(training.getPaperIds());

        HotTrainingCourseConfigBo courseConfigBo = new HotTrainingCourseConfigBo();
        courseConfigBo.setTrainingId(trainingId);
        courseConfigBo.setCompanyId(companyId);
        courseConfigBo.setIsDeleted(0L);
        List<HotTrainingCourseConfigVo> courseConfigs = trainingCourseConfigService.queryList(courseConfigBo);
        if (courseConfigs == null || courseConfigs.isEmpty()) {
            updateParticipantLearnProgress(companyId, trainingId, userId, BigDecimal.ZERO);
            return;
        }

        Set<Long> trainingCourseIds = courseConfigs.stream()
                .map(HotTrainingCourseConfigVo::getId)
                .filter(v -> v != null)
                .collect(Collectors.toSet());

        Map<Long, HotTrainingCourseRecord> latestRecordMap = loadLatestCourseRecords(companyId, trainingId, userId, trainingCourseIds);

        // 加载课程是否有随堂练习
        Map<Long, Boolean> courseHasQuizMap = loadCourseHasQuizMap(courseConfigs);

        int courseMetricCount = 0;
        BigDecimal totalProgressSum = BigDecimal.ZERO;
        for (HotTrainingCourseConfigVo cfg : courseConfigs) {
            if (cfg == null || cfg.getId() == null) {
                continue;
            }

            HotTrainingCourseRecord record = latestRecordMap.get(cfg.getId());
            double videoRatio = 0.0;
            if (record != null && record.getProgressRate() != null) {
                videoRatio = record.getProgressRate().doubleValue() / 100.0;
            }
            if (videoRatio < 0.0) videoRatio = 0.0;
            if (videoRatio > 1.0) videoRatio = 1.0;

            boolean hasQuiz = Boolean.TRUE.equals(courseHasQuizMap.get(cfg.getId()));
            boolean quizDone = hasQuiz && record != null && record.getCheckStatus() != null && record.getCheckStatus() == 1L;

            BigDecimal courseProgress;
            if (hasQuiz) {
                courseProgress = BigDecimal.valueOf(videoRatio)
                        .multiply(BigDecimal.valueOf(75.0))
                        .add(BigDecimal.valueOf(quizDone ? 25.0 : 0.0));
            } else {
                courseProgress = BigDecimal.valueOf(videoRatio).multiply(BigDecimal.valueOf(100.0));
            }
            totalProgressSum = totalProgressSum.add(courseProgress);
            courseMetricCount++;
        }

        boolean paperDone = hasPaper && participant.getIsCompleted().equals(1L);

        int totalMetrics = courseMetricCount + (hasPaper ? 1 : 0);
        if (totalMetrics <= 0) {
            updateParticipantLearnProgress(companyId, trainingId, userId, BigDecimal.ZERO);
            return;
        }

        if (hasPaper && paperDone) {
            totalProgressSum = totalProgressSum.add(BigDecimal.valueOf(100));
        }

        BigDecimal progress = totalProgressSum.divide(BigDecimal.valueOf(totalMetrics), 2, RoundingMode.HALF_UP);
        if (progress.compareTo(BigDecimal.ZERO) < 0) progress = BigDecimal.ZERO;
        if (progress.compareTo(BigDecimal.valueOf(100)) > 0) progress = BigDecimal.valueOf(100);
        updateParticipantLearnProgress(companyId, trainingId, userId, progress);
    }

    /**
     * 加载学员最近的课程学习记录
     */
    private Map<Long, HotTrainingCourseRecord> loadLatestCourseRecords(Long companyId,
                                                                       Long trainingId,
                                                                       String userId,
                                                                       Set<Long> trainingCourseIds) {
        if (trainingCourseIds == null || trainingCourseIds.isEmpty()) {
            return Map.of();
        }
        List<HotTrainingCourseRecord> records = trainingCourseRecordMapper.selectList(
                Wrappers.<HotTrainingCourseRecord>lambdaQuery()
                        .eq(HotTrainingCourseRecord::getCompanyId, companyId)
                        .eq(HotTrainingCourseRecord::getTrainingId, trainingId)
                        .eq(HotTrainingCourseRecord::getUserId, userId)
                        .in(HotTrainingCourseRecord::getTrainingCourseId, trainingCourseIds)
                        .eq(HotTrainingCourseRecord::getIsDeleted, 0L)
                        .orderByDesc(HotTrainingCourseRecord::getCreateTime)
        );
        if (records == null || records.isEmpty()) {
            return Map.of();
        }
        Map<Long, HotTrainingCourseRecord> map = new HashMap<>();
        for (HotTrainingCourseRecord r : records) {
            if (r.getTrainingCourseId() == null) {
                continue;
            }
            map.putIfAbsent(r.getTrainingCourseId(), r);
        }
        return map;
    }

    /**
     * 加载课程是否有随堂检测（试卷）
     */
    private Map<Long, Boolean> loadCourseHasQuizMap(List<HotTrainingCourseConfigVo> courseConfigs) {
        Map<Long, Boolean> hasQuizMap = new HashMap<>();
        Map<Long, Boolean> cache = new HashMap<>();
        if (courseConfigs == null) {
            return hasQuizMap;
        }
        for (HotTrainingCourseConfigVo cfg : courseConfigs) {
            if (cfg == null || cfg.getId() == null || cfg.getCourseId() == null) {
                continue;
            }
            Boolean hasQuiz = cache.get(cfg.getCourseId());
            if (hasQuiz == null) {
                HotCourseResourceBo bo = new HotCourseResourceBo();
                bo.setCourseId(cfg.getCourseId());
                bo.setResourceType(3L);
                List<HotCourseResourceVo> resources = courseResourceService.queryList(bo);
                hasQuiz = resources != null && !resources.isEmpty();
                cache.put(cfg.getCourseId(), hasQuiz);
            }
            hasQuizMap.put(cfg.getId(), hasQuiz);
        }
        return hasQuizMap;
    }

    private void updateParticipantLearnProgress(Long companyId, Long trainingId, String userId, BigDecimal progress) {
        trainingParticipantMapper.update(
                null,
                Wrappers.<HotTrainingParticipant>lambdaUpdate()
                        .set(HotTrainingParticipant::getLearnProgress, progress)
                        .eq(HotTrainingParticipant::getCompanyId, companyId)
                        .eq(HotTrainingParticipant::getTrainingId, trainingId)
                        .eq(HotTrainingParticipant::getUserId, userId)
                        .eq(HotTrainingParticipant::getIsDeleted, 0L)
        );
    }
}
