package top.continew.admin.business.service.impl;

import cn.crane4j.core.support.OperateTemplate;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import net.dreamlu.mica.core.utils.BeanUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import top.continew.admin.business.enums.AssignmentsTypeEnum;
import top.continew.admin.business.mapper.CoursesMapper;
import top.continew.admin.business.model.entity.AssignmentSubmissionsDO;
import top.continew.admin.business.model.entity.AssignmentsDO;
import top.continew.admin.business.model.entity.CourseUserDO;
import top.continew.admin.business.model.entity.CoursesDO;
import top.continew.admin.business.model.req.CoursesReq;
import top.continew.admin.business.model.resp.AssignmentsResp;
import top.continew.admin.business.model.resp.CoursesResp;
import top.continew.admin.business.service.AssignmentSubmissionsService;
import top.continew.admin.business.service.AssignmentsService;
import top.continew.admin.business.service.CourseUserService;
import top.continew.admin.business.service.CoursesService;
import top.continew.admin.common.util.helper.LoginHelper;
import top.continew.admin.system.enums.MessageTemplateEnum;
import top.continew.admin.system.enums.MessageTypeEnum;
import top.continew.admin.system.model.req.MessageReq;
import top.continew.admin.system.service.MessageService;
import top.continew.admin.system.service.MessageUserService;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.resp.PageResp;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 课程业务实现
 *
 * @author 张波
 * @since 2024/10/22 11:58
 */
@Service
@RequiredArgsConstructor
public class CoursesServiceImpl extends ServiceImpl<CoursesMapper, CoursesDO> implements CoursesService {

    private final CourseUserService courseUserService;

    private final AssignmentsService assignmentsService;

    private final AssignmentSubmissionsService assignmentSubmissionsService;

    private final MessageService messageService;

    private final MessageUserService messageUserService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(CoursesReq req) {
        // 保存课程基础信息
        CoursesDO saveDb = new CoursesDO();
        BeanUtil.copyProperties(req, saveDb);
        save(saveDb);

        // 构建课程-学生关联信息 并保存
        List<CourseUserDO> courseUserList = req.getUsers().stream().map(user -> {
            CourseUserDO temp = new CourseUserDO();

            temp.setCourseId(saveDb.getId());
            temp.setUserId(user.getUserId());
            temp.setNickname(user.getNickname());
            //发送消息
            MessageReq messageReq = new MessageReq();
            MessageTemplateEnum socialRegister = MessageTemplateEnum.SOCIAL_COUR;
            messageReq.setTitle(socialRegister.getTitle().formatted(req.getName()));
            messageReq.setContent(socialRegister.getContent().formatted(user.getNickname(), req.getName()));
            messageReq.setType(MessageTypeEnum.SECURITY);
            messageService.add(messageReq, CollUtil.toList(user.getUserId()));
            return temp;
        }).toList();
        courseUserService.saveBatch(courseUserList);
    }

    /**
     *
     * @param db        动态数据库
     * @param role      角色（学生/老师）
     * @param pageQuery 分页查询条件
     * @return
     */
    @Override
    @DS("#db")
    public PageResp<CoursesResp> list(String db, String role, PageQuery pageQuery) {
        Page<CoursesDO> page = new Page<>(pageQuery.getPage(), pageQuery.getSize());

        // 查询当前登录用户ID
        Long loginUserId = LoginHelper.getUserId();

        // 如果登录用户是学生则关联课程
        if (role.equals("pupil")) {
            List<Long> courseIdList = courseUserService.lambdaQuery()
                .select(CourseUserDO::getCourseId)
                .eq(CourseUserDO::getUserId, loginUserId)
                .list()
                .stream()
                .map(CourseUserDO::getCourseId)
                .toList();
            if (CollUtil.isEmpty(courseIdList)) {
                return new PageResp<>(Collections.emptyList(), 0L);
            }

            // 根据关联ID查询课程信息
            page = lambdaQuery().in(CoursesDO::getId, courseIdList).orderByDesc(CoursesDO::getCreateTime).page(page);
            // 如果为老师则查询当前登录人创建的课程信息
        } else if (role.equals("teacher")) {
            page = lambdaQuery().eq(CoursesDO::getCreateUser, loginUserId)
                .orderByDesc(CoursesDO::getCreateTime)
                .page(page);
        }

        // 封装响应
        PageResp<CoursesResp> pageResp = PageResp.build(page, CoursesResp.class);
        pageResp.getList().forEach(obj -> {
            if (null == obj) {
                return;
            }

            OperateTemplate operateTemplate = SpringUtil.getBean(OperateTemplate.class);
            operateTemplate.execute(obj);
        });

        return pageResp;
    }

    @Override
    public List<AssignmentsResp> assignmentsList(Long coursesId, AssignmentsTypeEnum type, String role) {
        // 查询课程所有作业
        List<AssignmentsDO> assignmentsList = assignmentsService.lambdaQuery()
            .select(AssignmentsDO::getId, AssignmentsDO::getName, AssignmentsDO::getExampleImages)
            .eq(AssignmentsDO::getCourseId, coursesId)
            .eq(AssignmentsDO::getType, type.getValue())
            .list();

        // 如果没有查询到作业直接返回
        if (CollUtil.isEmpty(assignmentsList)) {
            return Collections.emptyList();
        }

        // 提取作业ID列表 后续查询用
        List<Long> assignmentsIdList = assignmentsList.stream().map(AssignmentsDO::getId).toList();

        // 如果是学生 则判断学生是否提交作业，如果提交进度改为100 未提交进度0
        if (role.equals("pupil")) {
            // 获取当前登录用户ID
            Long userId = LoginHelper.getUserId();

            // 查询已提交作业的作业ID与提交记录IDMap
            Map<Long, Long> submissionIdMap = assignmentSubmissionsService.lambdaQuery()
                .select(AssignmentSubmissionsDO::getAssignmentId, AssignmentSubmissionsDO::getId)
                .in(AssignmentSubmissionsDO::getAssignmentId, assignmentsIdList)
                .eq(AssignmentSubmissionsDO::getUserId, userId)
                .list()
                .stream()
                .collect(Collectors.toMap(AssignmentSubmissionsDO::getAssignmentId, AssignmentSubmissionsDO::getId));

            // 计算作业完成度
            return assignmentsList.stream().map(assignmentsDO -> {
                AssignmentsResp temp = new AssignmentsResp();
                temp.setCourseId(coursesId);
                temp.setId(assignmentsDO.getId());
                temp.setName(assignmentsDO.getName());
                temp.setDegreeOfCompletion(submissionIdMap.containsKey(assignmentsDO.getId()) ? "已完成" : "未完成");
                temp.setAssignmentsSubmissionsId(submissionIdMap.get(assignmentsDO.getId()));
                temp.setExampleImages(assignmentsDO.getExampleImages());
                return temp;
            }).toList();
            // 如果是老师，则统计作业提交的学生数量计算进度
        } else if (role.equals("teacher")) {
            // 查询课程绑定学生数量
            Long userCount = courseUserService.lambdaQuery().eq(CourseUserDO::getCourseId, coursesId).count();

            // 查询各任务已提交作业数量
            Map<Long, Long> assignmentSubmissionCountMap = assignmentSubmissionsService.listMaps(Wrappers
                .<AssignmentSubmissionsDO>query()
                .select("assignment_id", "count(*)")
                .in("assignment_id", assignmentsList)
                .groupBy("assignment_id"))
                .stream()
                .collect(Collectors.toMap(map -> Long.valueOf(map.get("assignment_id").toString()), map -> Long
                    .valueOf(map.get("count(*)").toString())));

            // 计算完成度
            return assignmentsList.stream().map(assignmentsDO -> {
                BigDecimal div = NumberUtil.div(assignmentSubmissionCountMap.get(assignmentsDO.getId()), userCount);
                AssignmentsResp temp = new AssignmentsResp();
                temp.setCourseId(coursesId);
                temp.setId(assignmentsDO.getId());
                temp.setName(assignmentsDO.getName());
                temp.setDegreeOfCompletion(NumberUtil.decimalFormat("#.##%", div));
                temp.setExampleImages(assignmentsDO.getExampleImages());
                return temp;
            }).toList();
        }

        return Collections.emptyList();
    }
}
