package com.rongwei.training.controller;

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.rongwei.rwadmincommon.system.domain.SysUserDo;
import com.rongwei.rwadmincommon.system.service.SysUserOrgService;
import com.rongwei.rwadmincommon.system.vo.SysUserVo;
import com.rongwei.rwcommon.base.BaseDo;
import com.rongwei.rwcommon.base.QueryPar;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.safecommon.utils.CXCommonUtils;
import com.rongwei.training.domain.*;
import com.rongwei.trainingcommon.sys.service.*;
import com.rongwei.trainingcommon.sys.service.impl.EmpCourseServiceImpl;
import com.rongwei.trainingcommon.sys.service.impl.TrainingSendNotifyServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

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

import static com.rongwei.safecommon.utils.SaveConstans.NotifyContent.COURSE_NOTIFY_CONTENT;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyContent.TRAIN_NOTIFY_CONTENT;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyTitle.COURSE_NOTIFY_TITLE;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyTitle.TRAIN_NOTIFY_TITLE;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyType.COURSE;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyType.TRAINING;

@RestController
@RequestMapping("plan")
@Slf4j
public class PlanController {
    @Autowired
    private PlanService planService;
    @Autowired
    private PlanPaperService planPaperService;
    @Autowired
    private SysUserOrgService userOrgService;
    @Autowired
    private EmpCourseService empCourseService;
    @Autowired
    private EmpExamService empExamService;
    @Autowired
    private CourseService courseService;
    @Autowired
    private ExamPaperService examPaperService;
    @Autowired
    private PlanCourseService planCourseService;
    @Autowired
    private TrainingSendNotifyService sendNotifyService;

    /**
     * 列表
     */
    @RequestMapping("/list")
    public R list(@RequestBody QueryPar<PlanDo> params) {
        try {
            Wrapper<PlanDo> entity = new QueryWrapper(params.getParameter());
            List<PlanDo> list = planService.list(entity);
            return R.ok(list);
        } catch (Exception e) {
            log.error(StringUtils.spliceErrorMsg(e), e.fillInStackTrace());
            return R.queryError();
        }
    }

    /**
     * 根据plan生成
     *
     * @return
     */
    @RequestMapping("/generateUserPlanByPlanId")
    public R generateUserPlanByPlanId(@RequestBody List<String> planIds) {
        log.info("通过ids: {}发布培训计划", planIds);
        try {
            // 获取培训计划
            List<PlanDo> list = planService.list(new LambdaUpdateWrapper<PlanDo>().in(PlanDo::getId, planIds).eq(BaseDo::getDeleted, "0"));
            if (list.isEmpty()) {
                log.error("无法根据id获取对应的培训计划信息");
                return R.error("无法获取到对应的培训计划");
            }
            log.info("培训计划信息: {}", list);
            for (PlanDo row : list) {
                // 获取需要生成计划的用户ID
                Set<String> userIds = planService.getPlanUserIdsFromPlan(row);
                log.info("参与当前培训的员工Id: {}", userIds);
                if (userIds.size() > 0) {
                    // 获取培训计划
                    List<PlanCourseDo> planCourseList = planService.getPlanCourseByPlanId(row.getId());
                    List<PlanPaperDo> planPaperList = planService.getPlanPaperByPlanId(row.getId());
                    if (planCourseList.size() == 0 && planPaperList.size() == 0) {
                        return R.errorWithMsg("培训计划至少包含一个课程信息或一套试卷信息");
                    }
                    log.info("当前培训计划对应的课程信息:{}", planCourseList);
                    log.info("当前培训计划对应的试卷信息:{}", planPaperList);
                    // 获取考试计划
                    if (planPaperList.size() > 1) {
                        return R.errorWithMsg("单一培训计划只可对应一张试卷");
                    }
                    if(!planCourseList.isEmpty()){
                        CXCommonUtils.sendNotify(COURSE_NOTIFY_TITLE, String.format(COURSE_NOTIFY_CONTENT, row.getCoursename(),
                                        row.getTrainingstarttime(), row.getTrainingendtimt()), "", new ArrayList<>(userIds) ,
                                row.getId(), COURSE);
                    }
                    if(!planPaperList.isEmpty()){
                        planPaperList.forEach(data->{
                            CXCommonUtils.sendNotify(TRAIN_NOTIFY_TITLE, String.format(TRAIN_NOTIFY_CONTENT, data.getPapername(),
                                            data.getDeadline()), "", new ArrayList<>(userIds) ,
                                    row.getId(), TRAINING);
                        });

                    }
                    // 获取参与过本次培训计划的员工
                    QueryWrapper<EmpExamDo> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("PLANID", row.getId());
                    queryWrapper.eq("DELETED", 0);
                    List<EmpExamDo> examDoList = empExamService.list(queryWrapper);
                    // 给取消本次培训计划的员工 发送信息提醒
                    planService.disposeTrainingEmpExam(row, userIds, examDoList);
                    // 从本次培训计划中删除以参与过培训计划的员工
                    // userIds.removeAll(examDoList.stream().map(EmpExamDo::getEmpid).collect(Collectors.toList()));
                    log.info("需要参与本次培训计划的用户id :{}", userIds);
                    for (String userId : userIds) {
                        if (!planCourseList.isEmpty()) {
                            // 生成对应用户的培训计划
                            for (PlanCourseDo v1 : planCourseList) {
                                // 根据 计划iD,课程ID,员工id 获取员工课程关系信息
                                List<EmpCourseDo> empCourseDoList = empCourseService.list(new QueryWrapper<EmpCourseDo>()
                                        .lambda()
                                        .eq(BaseDo::getDeleted, "0")
                                        .eq(EmpCourseDo::getPlanid, row.getId())
                                        .eq(EmpCourseDo::getCourseid, v1.getCourseid())
                                        .eq(EmpCourseDo::getEmpid, userId));
                                log.info("根据 计划id:{},课程id:{},员工id:{}. 获取员工课程关系信息:{}", row.getId(), v1.getCourseid(), userId, empCourseDoList);
                                if (empCourseDoList.isEmpty()) {
                                    String uid = SecurityUtil.getUUID();
                                    EmpCourseDo empCourseDo = new EmpCourseDo();
                                    empCourseDo.setId(uid);
                                    empCourseDo.setPlanid(row.getId());
                                    empCourseDo.setPlancourseid(v1.getId());
                                    empCourseDo.setEmpid(userId); // 设置用户
                                    empCourseDo.setCourseid(v1.getCourseid()); // 设置课程id
                                    empCourseDo.setCoursename(v1.getCoursename()); // 设置课程name
                                    empCourseDo.setCoursetime(v1.getCoursetime()); // 设置课程时间
                                    empCourseDo.setDeleted("0");
                                    empCourseDo.setCreatedate(new Date());
                                    empCourseDo.setModifydate(new Date());
                                    empCourseDo.setPlanname(row.getCoursename());
                                    empCourseDo.setSerialnumber(v1.getSerialnumber());
                                    empCourseService.save(empCourseDo);
                                    log.info("新增员工和课程的对应关系：{}", empCourseDo);
                                }
                            }

                        }
                        if (!planPaperList.isEmpty()) {
                            // 生成对应用户的考试计划
                            for (PlanPaperDo v1 : planPaperList) {
                                // 根据 计划iD,课程ID,员工id 获取员工课程关系信息
                                List<EmpExamDo> empExamDoList = empExamService.list(new QueryWrapper<EmpExamDo>()
                                        .lambda()
                                        .eq(BaseDo::getDeleted, "0")
                                        .eq(EmpExamDo::getPlanid, row.getId())
                                        .eq(EmpExamDo::getPaperid, v1.getPaperid())
                                        .eq(EmpExamDo::getEmpid, userId));
                                log.info("根据 计划id:{},试卷:{},员工id:{}. 获取员工课程关系信息:{}", row.getId(), v1.getPaperid(), userId, empExamDoList);
                                if (empExamDoList.isEmpty()) {
                                    String uid = SecurityUtil.getUUID();
                                    EmpExamDo empExamDo = new EmpExamDo();
                                    empExamDo.setId(uid);
                                    empExamDo.setPlanid(row.getId());
                                    empExamDo.setPlanpaperid(v1.getId());
                                    empExamDo.setEmpid(userId); // 设置用户
                                    empExamDo.setPaperid(v1.getPaperid()); // 设置试卷ID
                                    empExamDo.setPapername(v1.getPapername());// 设置试卷NAME
                                    empExamDo.setExamdeadtime(v1.getDeadline()); // 设置截至时间
                                    empExamDo.setDeleted("0");
                                    empExamDo.setCreatedate(new Date());
                                    empExamDo.setModifydate(new Date());
                                    empExamDo.setExamstatus("待考试");
                                    empExamDo.setPlanname(row.getCoursename());
                                    empExamService.save(empExamDo);
                                    log.info("生成员工和试卷的对应关系：{}", empExamDo);
                                    ExamPaperDo paper = examPaperService.getById(v1.getPaperid());
                                    paper.setHasused("y");
                                    examPaperService.updateById(paper);
                                }
                            }

                        }
                    }
                    row.setPublish("y");
                    planService.updateById(row);
                    for (PlanCourseDo planCourse : planCourseList) {
                        CourseDo courseDo = courseService.getById(planCourse.getCourseid());
                        courseDo.setCourseused("y");
                        courseService.update();
                    }
                } else {
                    return R.errorWithMsg("查询不到该培训计划对应的员工");
                }
            }
            return R.ok();
        } catch (Exception e) {
            log.error(StringUtils.spliceErrorMsg(e), e.fillInStackTrace());
            return R.error();
        }
    }

    /**
     * 发送考试邮件提醒
     *
     * @return
     */
    @GetMapping("/sendExamNotification")
    public R sendExamNotification() {
        try {
            // 获取所有的有员工考试信息

            return R.ok();
        } catch (Exception e) {
            log.error(StringUtils.spliceErrorMsg(e), e.fillInStackTrace());
            return R.queryError();
        }
    }

    /**
     * 发送培训邮件提醒
     *
     * @return
     */
    @GetMapping("/sendTrainingNotification")
    public R sendTrainingNotification() {
        try {
            // 获取所有的有员工培训信息

            return R.ok();
        } catch (Exception e) {
            log.error(StringUtils.spliceErrorMsg(e), e.fillInStackTrace());
            return R.queryError();
        }
    }


    /**
     * 信息
     */
    @GetMapping("/info/{id}")
    public R info(@PathVariable("id") String id) {
        try {
            PlanDo plan = planService.getById(id);
            return R.ok(plan);
        } catch (Exception e) {
            log.error(StringUtils.spliceErrorMsg(e), e.fillInStackTrace());
            return R.queryError();
        }
    }

    /**
     * 保存or更新
     */
    @PostMapping("/saveOrUpdate")
    public R add(@RequestBody PlanDo plan) {
        try {
            planService.saveOrUpdate(plan);
            return R.saveOk();
        } catch (Exception e) {
            log.error(StringUtils.spliceErrorMsg(e), e.fillInStackTrace());
            return R.saveError();
        }

    }

    @PostMapping("/cancel")
    public R cancelTrain(@RequestBody List<String> ids){

        List<PlanCourseDo> planCourseDoList = planCourseService.list(new LambdaQueryWrapper<PlanCourseDo>()
                .in(PlanCourseDo::getTrainingplanid, ids));
        List<PlanPaperDo> planPaperDoList = planPaperService.list(new LambdaQueryWrapper<PlanPaperDo>()
                .in(PlanPaperDo::getTrainingplanid, ids));

        LambdaUpdateWrapper<PlanCourseDo> lambdaUpdateEmpWrapper = new LambdaUpdateWrapper<PlanCourseDo>();
        lambdaUpdateEmpWrapper.in(PlanCourseDo::getTrainingplanid, ids).set(BaseDo::getDeleted, 1);
        planCourseService.update(lambdaUpdateEmpWrapper);
        // 删除 training_plan_paper 表记录
        LambdaUpdateWrapper<PlanPaperDo> lambdaUpdatepaperWrapper = new LambdaUpdateWrapper<PlanPaperDo>();
        lambdaUpdatepaperWrapper.in(PlanPaperDo::getTrainingplanid, ids).set(BaseDo::getDeleted, 1);
        planPaperService.update(lambdaUpdatepaperWrapper);

        planService.update(new LambdaUpdateWrapper<PlanDo>().set(PlanDo::getPublish,"c").in(PlanDo::getId,ids));
        // 获取未参与培训的用户
        List<EmpCourseDo> toTestInfoList = empCourseService.list(new LambdaQueryWrapper<EmpCourseDo>()
                .eq(BaseDo::getDeleted, "0")
                .in(EmpCourseDo::getPlanid, ids)
                .in(EmpCourseDo::getPlancourseid,planCourseDoList.stream().map(PlanCourseDo::getId).collect(Collectors.toList()))
                .last("and COURSETIME*60 <> ifnull(COURSEUSETIME,0)")
        );
        // 获取未考试的用户信息
        List<EmpExamDo> examDoList = empExamService.list(new LambdaQueryWrapper<EmpExamDo>().eq(BaseDo::getDeleted, "0")
                .in(EmpExamDo::getPlanid, ids)
                .in(EmpExamDo::getPlanpaperid, planPaperDoList.stream().map(PlanPaperDo::getId).collect(Collectors.toList()))
                .eq(EmpExamDo::getExamstatus, "待考试")
        );

        Map<String, List<String>> courseMap = new HashMap<>();
        planService.listByIds(ids).forEach(info->{
            List<String> empIds = toTestInfoList.stream()
                    .filter(data -> data.getPlanid().equals(info.getId()))
                    .map(EmpCourseDo::getEmpid).collect(Collectors.toList());
            courseMap.put(info.getCoursename(),empIds);
        });
        Map<String, List<String>> paperMap = new HashMap<>();
        // 对试卷按照试卷名称分组
        Map<String, List<EmpExamDo>> collect = examDoList.stream().collect(Collectors.groupingBy(EmpExamDo::getPapername, Collectors.toList()));
        collect.forEach((k,v)->{
            paperMap.put(k, examDoList.stream().map(EmpExamDo::getEmpid).distinct().collect(Collectors.toList()));
        });
        // 培训课程取消提醒
        sendNotifyService.sendTrainingPlanCancelNotify(courseMap,paperMap);
        return R.ok();
    }


    /**
     * 删除
     */
    @PostMapping("/delete")
    public R delete(@RequestBody List<String> ids) {
        return planService.deletedByIds(ids);
    }

    /**
     * 删除培训计划时 删除对应培训计划信息
     *
     * @param planIds 培训计划
     * @return
     */
    @PostMapping("/delete/ids")
    public R deletedTrainInfoById(@RequestBody List<String> planIds) {
        try {
            // 删除 training_plan_course 表记录
            LambdaUpdateWrapper<PlanCourseDo> lambdaUpdateEmpWrapper = new LambdaUpdateWrapper<PlanCourseDo>();
            lambdaUpdateEmpWrapper.in(PlanCourseDo::getTrainingplanid, planIds).set(BaseDo::getDeleted, 1);
            planCourseService.update(lambdaUpdateEmpWrapper);
            // 删除 training_plan_paper 表记录
            LambdaUpdateWrapper<PlanPaperDo> lambdaUpdatepaperWrapper = new LambdaUpdateWrapper<PlanPaperDo>();
            lambdaUpdatepaperWrapper.in(PlanPaperDo::getTrainingplanid, planIds).set(BaseDo::getDeleted, 1);
            planPaperService.update(lambdaUpdatepaperWrapper);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy年MM月dd日");
            Map<PlanDo, Set<String>> planAndUserIdMap = new HashMap<>();
            // 删除之前发送培训计划取消邮件
            planIds.forEach(planId -> {
                PlanDo planInfo = planService.getById(planId);
                // 未发布的培训计划不发送取消邮件
                if(planInfo.getPublish().equals("n")){
                    return;
                }
                Set<String> planUserIdsFromPlan = planService.getPlanUserIdsFromPlan(planInfo);
                if (planUserIdsFromPlan.isEmpty()) {
                    return;
                }
                planAndUserIdMap.put(planInfo, planUserIdsFromPlan);
                // modify at [ 2023-11-29 10:37:38 ] by xh: 取消邮件发送提醒
              /*  // 获取员工信息
                List<SysUserDo> list = sysUserService.list(new LambdaQueryWrapper<SysUserDo>().eq(BaseDo::getDeleted, "0").in(SysUserDo::getId, planUserIdsFromPlan));
                // 发送邮件信息
                MailDo mail = new MailDo();
                mail.setSubject("培训取消提醒");
                String[] reMails = list.stream().filter(userInfo -> StringUtils.isNotBlank(userInfo.getEmail())).map(SysUserDo::getEmail).distinct().toArray(String[]::new);
                mail.setReceiveEmail(reMails);
                StringBuilder mailContent = new StringBuilder("您好，");
                mailContent.append(planInfo.getCoursename());
                mailContent.append("培训原定于");
                mailContent.append(simpleDateFormat.format(planInfo.getTrainingstarttime()));
                mailContent.append("开始进行，临时决定取消培训，特此通知。");
                mailContent.append("详见智能安全监控平台：http://192.168.0.205:8000");
                mail.setContent(mailContent.toString());
                // 邮件发送服务调用
                sysConfigFeignService.sendTextMail(mail);*/
            });
            planService.removeByIds(planIds);
            // 培训计划取消提醒
//            sendNotifyService.sendTrainingPlanCancelNotify(planAndUserIdMap);

            return R.ok();
        } catch (Exception e) {
            log.error(StringUtils.spliceErrorMsg(e), e.fillInStackTrace());
            return R.deleteError();
        }
    }

    @PostMapping("/saveEmpNum")
    public R saveEmpNum(@RequestBody List<String> ids) {
        if (ids == null || ids.isEmpty()) {
            return R.ok();
        }
        // 获取所有的培训计划
        List<PlanDo> list = planService.list(new QueryWrapper<PlanDo>().lambda().in(PlanDo::getId, ids).eq(BaseDo::getDeleted, "0"));
        Map<PlanDo, Set<String>> planAndUserIdMap = new HashMap<>();
        list.forEach(planDo -> {
            // 参与部门
            String orgIds = planDo.getIncludingorgids();
            // 参与员工
            String empids = planDo.getTrainingempids();
            // 排除员工
            String excludeempids = planDo.getExcludeempids();
            Set<String> empIdSet = new HashSet<>();
            if (StringUtils.isNotBlank(orgIds)) {
                // 根据组织机构获取 该机构下的所有员工信息
                List<SysUserVo> deptUsersByDeptIds = userOrgService.getDeptUsersByDeptIds(Arrays.asList(orgIds.split(",")));
                // 取出员工id
                empIdSet = deptUsersByDeptIds.stream().map(SysUserDo::getId).collect(Collectors.toSet());
            }
            if (StringUtils.isNotBlank(empids)) {
                // 将参与员工的组织机构加入
                empIdSet.addAll(Arrays.asList(empids.split(",")));
            }
            if (StringUtils.isNotBlank(excludeempids)) {
                empIdSet.removeAll(Arrays.asList(excludeempids.split(",")));
            }
            planDo.setParticipateempnum(empIdSet.size());
            planService.updateById(planDo);
            planAndUserIdMap.put(planDo, empIdSet);
        });
        /**
         * 发送提醒通知
         */
//        sendNotifyService.sendTrainingPlanNotify(planAndUserIdMap);
        return R.ok();
    }

}
