package com.rongwei.trainingcommon.sys.service.impl;

import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rongwei.rwadmincommon.system.domain.SysUserDo;
import com.rongwei.rwadmincommon.system.domain.SysUserOrgDo;
import com.rongwei.rwadmincommon.system.service.SysConfigFeignService;
import com.rongwei.rwadmincommon.system.service.SysUserOrgService;
import com.rongwei.rwadmincommon.system.service.SysUserService;
import com.rongwei.rwcommon.base.BaseDo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.rwcommon.vo.MailDo;
import com.rongwei.training.domain.*;
import com.rongwei.trainingcommon.sys.dao.PlanDao;
import com.rongwei.trainingcommon.sys.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

@Service("planService")
@Slf4j
public class PlanServiceImpl extends ServiceImpl<PlanDao, PlanDo> implements PlanService {
    @Autowired
    private SysUserOrgService userOrgService;
    @Autowired
    private PlanPaperService planPaperService;
    @Autowired
    private PlanCourseService planCourseService;
    @Autowired
    private EmpExamService empExamService;
    @Autowired
    private SysConfigFeignService sysConfigFeignService;
    @Autowired
    private SysUserService sysUserService;
    @Autowired
    private EmpCourseService empCourseService;
    @Autowired
    private SysUserOrgService sysUserOrgService;

    private static final String DEFAULT_EXAM_STATUS = "待考试";

    /**
     * 获取培训计划下所属的所有员工
     *
     * @param planDo
     * @return
     */
    @Override
    public Set<String> getPlanUserIdsFromPlan(PlanDo planDo) {
        Set<String> userIds = new HashSet<>();
        // xiahan TODO: 2020/12/17 影响获取培训计划参与的员工信息 故注释
        //if (planDo.getPublish() != null && "n".equals(planDo.getPublish().toLowerCase())) {
            // 获取部门用户
            String deptIds = planDo.getIncludingorgids();
            if (!StringUtils.isEmptyStr(deptIds)) {
                List<String> deptIdArr = Arrays.asList(deptIds.split(","));
                SysUserOrgDo sysUserOrgDo = new SysUserOrgDo();
                QueryWrapper<SysUserOrgDo> sysUserOrgQuery = (QueryWrapper<SysUserOrgDo>) new QueryWrapper(sysUserOrgDo).in("ORGID", deptIdArr);
                List<SysUserOrgDo> deptUserList = userOrgService.list(sysUserOrgQuery);
                deptUserList.forEach(deptUserRow -> {
                    userIds.add(deptUserRow.getUserid());
                });
            }
            // 获取普通用户
            String empIds = planDo.getTrainingempids();
            if (!StringUtils.isEmptyStr(empIds)) {
                List<String> empIdArr = Arrays.asList(empIds.split(","));
                empIdArr.forEach(empId -> {
                    userIds.add(empId);
                });
            }
            // 过滤不需要的用户
            String excludeEmpIds = planDo.getExcludeempids();
            if (!StringUtils.isEmptyStr(excludeEmpIds)) {
                List<String> excludeEmpIdArr = Arrays.asList(excludeEmpIds.split(","));
                excludeEmpIdArr.forEach(excludeEmpId -> {
                    userIds.remove(excludeEmpId);
                });
            }
       // }
        return userIds;
    }

    /**
     * 获取培训计划对应所属课程
     *
     * @param planId
     * @return
     */
    @Override
    public List<PlanCourseDo> getPlanCourseByPlanId(String planId) {
        PlanCourseDo planCourse = new PlanCourseDo();
        planCourse.setTrainingplanid(planId);
        planCourse.setDeleted("0");
        Wrapper wrapper = new QueryWrapper(planCourse);
        return (List<PlanCourseDo>) planCourseService.list(wrapper);
    }

    /**
     * 获取培训计划所属试卷
     *
     * @param planId
     * @return
     */
    @Override
    public List<PlanPaperDo> getPlanPaperByPlanId(String planId) {
        PlanPaperDo planPaperDo = new PlanPaperDo();
        planPaperDo.setTrainingplanid(planId);
        planPaperDo.setDeleted("0");
        Wrapper wrapper = new QueryWrapper(planPaperDo);
        return (List<PlanPaperDo>) planPaperService.list(wrapper);
    }


    @Override
    public void disposeTrainingEmpExam(PlanDo planDo, Set<String> userIds, List<EmpExamDo> examDoList) {
        /*************删除员工考试开始*******/
        if (userIds.isEmpty() || examDoList.isEmpty()) {
            return;
        }
        log.info("准备删除员工考试记录 coursename:{}", planDo.getCoursename());
        // 获取员工考试记录表
        // 筛选出还未考试并且已经不再本次培训计划中的员工 取消培训计划
        List<EmpExamDo> cancelEmpExamList = examDoList.stream()
                .filter(examdo -> DEFAULT_EXAM_STATUS.equals(examdo.getExamstatus()))
                .filter(examdo -> !userIds.contains(examdo.getEmpid()))
                .collect(Collectors.toList());
        log.info("需要取消本次员工培训计划的员工id: {}", cancelEmpExamList.stream().map(EmpExamDo::getEmpid).collect(Collectors.joining(",")));
        // 修改数据库信息
        if (!cancelEmpExamList.isEmpty()) {
            LambdaUpdateWrapper<EmpExamDo> lambdaUpdateEmpWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateEmpWrapper.in(EmpExamDo::getId, cancelEmpExamList.stream().map(EmpExamDo::getId).collect(Collectors.toList()))
                    .set(BaseDo::getDeleted, "1");
            empExamService.update(lambdaUpdateEmpWrapper);
            // 取消培训的员工ID
            List<String> empIdList = cancelEmpExamList.stream().map(EmpExamDo::getEmpid).collect(Collectors.toList());
            log.info("删除员工考试记录结束 员工Id:{}", empIdList);
            /*************删除员工考试结束*******/


            /*************删除员工课程记录表开始*******/
            log.info("准备删除员工课程记录  培训计划:{} , 培训员工：{}", planDo.getCoursename(), empIdList);
            LambdaUpdateWrapper<EmpCourseDo> lambdaUpdateWrapper = new LambdaUpdateWrapper<>();
            lambdaUpdateWrapper.eq(EmpCourseDo::getPlanid, planDo.getId())
                    .in(EmpCourseDo::getEmpid, empIdList).set(BaseDo::getDeleted, "1");
            empCourseService.update(lambdaUpdateWrapper);
            log.info("删除员工课程记录结束");
            /*************删除员工课程记录表结束*******/
            /***********发送取消培训邮件**********/
            this.sendCancelTrainingNotification(empIdList, planDo);
        }
    }


    /**
     * 邮件标题：“培训取消提醒”
     * 邮件内容：“您好，XXX培训原定于XXXX年XX月XX日开始进行，临时决定取消培训，特此通知。”
     */
    @Override
    public void sendCancelTrainingNotification(List<String> cancelEmpIds, PlanDo planDo) {
        log.info("开始发送培训取消邮件提醒给 empIds:{}", cancelEmpIds);
        if (cancelEmpIds == null || cancelEmpIds.isEmpty()) {
            return;
        }
        cancelEmpIds.forEach(empId -> {
            SysUserDo userdo = sysUserService.getById(empId);
            if (StringUtils.isNotEmpty(userdo.getEmail())) {
                MailDo mail = new MailDo();
                mail.setSubject("培训取消提醒");
                String[] reMails = {userdo.getEmail()};
                mail.setReceiveEmail(reMails);
                StringBuilder mailContent = new StringBuilder("您好，");
                mailContent.append(planDo.getCoursename());
                mailContent.append("培训原定于");
                mailContent.append(new SimpleDateFormat("yyyy年MM月dd日").format(planDo.getTrainingstarttime()));
                mailContent.append("开始进行，临时决定取消培训，特此通知。");
                mailContent.append("详见智能安全监控平台：http://192.168.0.205:8000");
                mail.setContent(mailContent.toString());
                // 邮件发送服务调用
                sysConfigFeignService.sendTextMail(mail);
            }
        });
        log.info("发送培训取消邮件提醒结束");
    }

    @Override
    public R deletedByIds(List<String> ids) {
        log.info("开始删除培训计划: {}", ids);
        if (ids.isEmpty()) {
            return R.errorWithMsg("培训计划Id为空");
        }
        List<PlanDo> planDoList = this.list(new LambdaQueryWrapper<PlanDo>().eq(BaseDo::getDeleted, "0").in(PlanDo::getId, ids));
        if (planDoList.isEmpty()) {
            log.error("无法获取到对应的培训计划");
            return R.errorWithMsg("无法获取到对应的培训计划");
        }
        log.info("获取到培训计划信息: {}", planDoList);
        // 按照培训计划名称分类方便发送邮件
        Map<String, List<PlanDo>> mapInfo = planDoList.stream().collect(Collectors.groupingBy(planInfo -> planInfo.getId() + ";" + planInfo.getCoursename()));
        mapInfo.forEach((k, v) -> {
            // 所有培训计划参与员工的ID
            Set<String> participateEmpIds = v.stream()
                    .filter(info -> StringUtils.isNotBlank(info.getTrainingempids()))
                    .flatMap(planDo -> Arrays.stream(planDo.getTrainingempids().split(",")))
                    .collect(Collectors.toSet());
            // 所有被排除培训计划的员工ID
            Set<String> excludeEmpIds = v.stream()
                    .filter(info -> StringUtils.isNotBlank(info.getExcludeempids()))
                    .flatMap(planDo -> Arrays.stream(planDo.getExcludeempids().split(",")))
                    .collect(Collectors.toSet());
            // 需要参与本次培训计划的组织机构Id
            Set<String> participateOrgIds = v.stream()
                    .filter(info -> StringUtils.isNotBlank(info.getIncludingorgids()))
                    .flatMap(planDo -> Arrays.stream(planDo.getIncludingorgids().split(",")))
                    .collect(Collectors.toSet());
            // 获取当前组织机构下的所有员工ID
            if (participateOrgIds.isEmpty()) {
                List<SysUserOrgDo> list = sysUserOrgService.list(new LambdaQueryWrapper<SysUserOrgDo>().eq(BaseDo::getDeleted, "0").in(SysUserOrgDo::getOrgid, participateOrgIds));
                Set<String> empIdInOrg = list.stream().map(SysUserOrgDo::getUserid).collect(Collectors.toSet());
                participateEmpIds.addAll(empIdInOrg);
            }
            // 将被排除的员工去除
            if (!excludeEmpIds.isEmpty()) {
                participateEmpIds.removeIf(excludeEmpIds::contains);
            }
            // 需要发送邮件的信息员工列表
            List<SysUserDo> userDoList = sysUserService.list(new LambdaQueryWrapper<SysUserDo>().eq(BaseDo::getDeleted, "0").in(SysUserDo::getId, participateEmpIds));
            if (!userDoList.isEmpty()) {
                log.info("开始发送培训取消邮件提醒");
                PlanDo planDo = planDoList.stream().filter(planInfo -> planInfo.getId().equals(k.split(";")[0])).findFirst().orElse(null);
                Set<String> emailInfos = userDoList.stream().filter(userInfo -> StringUtils.isNotBlank(userInfo.getEmail())).map(SysUserDo::getEmail).collect(Collectors.toSet());
                MailDo mail = new MailDo();
                mail.setSubject("培训取消提醒");
                mail.setReceiveEmail((String[]) emailInfos.toArray());
                StringBuilder mailContent = new StringBuilder("您好，");
                mailContent.append(planDo.getCoursename());
                mailContent.append("培训原定于");
                mailContent.append(new SimpleDateFormat("yyyy年MM月dd日").format(planDo.getTrainingstarttime()));
                mailContent.append("开始进行，临时决定取消培训，特此通知。");
                mailContent.append("详见智能安全监控平台：http://192.168.0.205:8000");
                mail.setContent(mailContent.toString());
                // 邮件发送服务调用
                sysConfigFeignService.sendTextMail(mail);
                log.info("培训取消邮件提醒接收人邮箱为: {}", emailInfos);
            }
        });
        /*********************************************************处理和培训计划相关的表****************************************************/
        log.info("开始删除培训计划相关表");
        // 1. 删除training_plan_course
        planCourseService.update(new LambdaUpdateWrapper<PlanCourseDo>().in(PlanCourseDo::getTrainingplanid, ids).set(BaseDo::getDeleted, "1"));
        // 2. 删除 training_plan_paper
        planPaperService.update(new LambdaUpdateWrapper<PlanPaperDo>().in(PlanPaperDo::getTrainingplanid, ids).set(BaseDo::getDeleted, "1"));
        // 3. 删除 training_emp_exam
        empExamService.update(new LambdaUpdateWrapper<EmpExamDo>().in(EmpExamDo::getPlanid, ids).set(BaseDo::getDeleted, "1"));
        // 4. 删除 training_emp_course
        empCourseService.update(new LambdaUpdateWrapper<EmpCourseDo>().in(EmpCourseDo::getPlanid, ids).set(BaseDo::getDeleted, "1"));
        log.info("删除结束");
        return R.deleteOk();
    }
}
