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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import top.continew.admin.business.mapper.AssignmentSubmissionsMapper;
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.req.AssignmentSubmissionsReq;
import top.continew.admin.business.model.req.AssignmentsCorrectReq;
import top.continew.admin.business.model.resp.AssignmentsProgressResp;
import top.continew.admin.business.model.resp.AssignmentsSubmissionsDetailResp;
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.common.util.helper.LoginHelper;
import top.continew.starter.core.util.validate.CheckUtils;
import top.continew.starter.extension.crud.model.query.PageQuery;
import top.continew.starter.extension.crud.model.resp.PageResp;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * @author 张波
 * @since 2024/10/22 15:38
 */
@Service
@RequiredArgsConstructor
public class AssignmentSubmissionsServiceImpl extends ServiceImpl<AssignmentSubmissionsMapper, AssignmentSubmissionsDO> implements AssignmentSubmissionsService {

    private final CourseUserService courseUserService;

    private final AssignmentsService assignmentsService;

    @Override
    public void submit(AssignmentSubmissionsReq req) {
        Long loginUserId = LoginHelper.getUserId();

        boolean exists = lambdaQuery().eq(AssignmentSubmissionsDO::getAssignmentId, req.getAssignmentId())
            .eq(AssignmentSubmissionsDO::getUserId, loginUserId)
            .exists();

        CheckUtils.throwIf(exists, "作业已提交，请勿重复提交！");

        AssignmentSubmissionsDO saveDb = BeanUtil.copyProperties(req, AssignmentSubmissionsDO.class);
        saveDb.setUserId(loginUserId);
        save(saveDb);
    }

    @Override
    public void correct(AssignmentsCorrectReq req) {
        // 查询作业提交记录
        AssignmentSubmissionsDO assignmentSubmissions = getById(req.getId());

        // 检查是否已经批改
        CheckUtils.throwIf(assignmentSubmissions.getScore() != null, "作业已批改，请勿重复批改！");

        // 修改分数以及评语
        lambdaUpdate().eq(AssignmentSubmissionsDO::getId, req.getId())
            .set(AssignmentSubmissionsDO::getScore, req.getScore())
            .set(StrUtil.isNotBlank(req.getFeedback()), AssignmentSubmissionsDO::getFeedback, req.getFeedback())
            .update();
    }

    @Override
    public AssignmentsSubmissionsDetailResp detail(Long submissionsId) {
        // 查询提交记录
        AssignmentSubmissionsDO submissionsDO = getById(submissionsId);
        CheckUtils.throwIfNull(submissionsDO, "作业提交记录不存在");

        // 查询作业信息
        AssignmentsDO assignmentsDO = assignmentsService.getById(submissionsDO.getAssignmentId());

        // 拷贝相关信息 构建返回对象
        AssignmentsSubmissionsDetailResp res = BeanUtil
            .copyProperties(assignmentsDO, AssignmentsSubmissionsDetailResp.class);
        BeanUtil.copyProperties(submissionsDO, res);

        return res;
    }

    @DS("#dbName")
    @Override
    public PageResp<String> getGoodImageList(String dbName, PageQuery pageQuery) {
        // 查询分数80以上的作业
        Page<AssignmentSubmissionsDO> page = lambdaQuery().select(AssignmentSubmissionsDO::getImageUrl)
            .ge(AssignmentSubmissionsDO::getScore, 80)
            .orderByDesc(AssignmentSubmissionsDO::getCreateTime)
            .page(new Page<>(pageQuery.getPage(), pageQuery.getSize()));

        // 提取图片地址
        List<String> imageUrlList = page.getRecords().stream().map(AssignmentSubmissionsDO::getImageUrl).toList();

        // 构建分页返回
        return new PageResp<>(imageUrlList, page.getTotal());
    }

    @Override
    public PageResp<AssignmentsProgressResp> degreeOfCompletion(Long assignmentsId, PageQuery pageQuery) {
        // 检查作业是否存在
        AssignmentsDO assignmentsDO = assignmentsService.getById(assignmentsId);
        CheckUtils.throwIfNull(assignmentsDO, "作业不存在！");

        // 分页查询作业有哪些学生
        Page<CourseUserDO> page = new Page<>(pageQuery.getPage(), pageQuery.getSize());
        page = courseUserService.lambdaQuery().eq(CourseUserDO::getCourseId, assignmentsDO.getCourseId()).page(page);

        List<CourseUserDO> records = page.getRecords();
        if (CollUtil.isEmpty(records)) {
            return new PageResp<>(Collections.emptyList(), 0L);
        }

        // 提取学生ID 查询提交记录表
        List<Long> userIds = records.stream().map(CourseUserDO::getUserId).toList();
        Map<Long, AssignmentSubmissionsDO> submissionsMap = lambdaQuery()
            .eq(AssignmentSubmissionsDO::getAssignmentId, assignmentsId)
            .in(AssignmentSubmissionsDO::getUserId, userIds)
            .list()
            .stream()
            .collect(Collectors.toMap(AssignmentSubmissionsDO::getUserId, Function.identity()));

        // 查询是否有提交记录，判断学生是否提交作业，判断是否有分数，判断老师是否批改作业
        List<AssignmentsProgressResp> res = records.stream().map(courseUser -> {
            AssignmentsProgressResp temp = new AssignmentsProgressResp();
            temp.setNickname(courseUser.getNickname());

            AssignmentSubmissionsDO submissions = submissionsMap.get(courseUser.getUserId());
            if (submissions == null) {
                temp.setDegreeOfCompletion(false);
                temp.setDegreeOfCorrection(false);
            } else {
                temp.setSubmissionsId(submissions.getId());
                temp.setDegreeOfCompletion(true);
                temp.setDegreeOfCorrection(submissions.getScore() != null);
            }
            return temp;
        }).toList();

        return new PageResp<>(res, page.getTotal());
    }
}
