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

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.rongwe.scentity.domian.*;
import com.rongwe.scentity.vo.ExportHiddenDangerVo;
import com.rongwei.rwadmincommon.system.domain.SysDictDo;
import com.rongwei.rwadmincommon.system.service.SysDictService;
import com.rongwei.rwcommon.base.BaseDo;
import com.rongwei.rwcommon.base.R;
import com.rongwei.rwcommon.utils.SecurityUtil;
import com.rongwei.rwcommon.utils.StringUtils;
import com.rongwei.safecommon.utils.ExportExcelByEasyExcel;
import com.rongwei.safecommon.utils.JSCommonUtils;
import com.rongwei.safecommon.utils.SaveConstans;
import com.rongwei.sfcommon.sys.dao.SaveCheckCommonDao;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.rongwei.safecommon.utils.SaveConstans.COMPANY_MAP;
import static com.rongwei.safecommon.utils.SaveConstans.DatePattern.DATE_PATTERN_YMD;
import static com.rongwei.safecommon.utils.SaveConstans.DictType.*;
import static com.rongwei.safecommon.utils.SaveConstans.FileSuffix.XLSX;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyContent.HIDDEN_DANGER_TASK_CONTENT;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyTitle.*;
import static com.rongwei.safecommon.utils.SaveConstans.NotifyType.*;
import static com.rongwei.safecommon.utils.SaveConstans.RoleCode.*;
import static com.rongwei.sfcommon.utils.MlConstants.DANGER_SOURCE_POINTCHECK;

/**
 * ScheduledTasksServiceImpl class
 *
 * @author XH
 * @date 2024/08/27
 */
@Service
public class ScheduledTasksServiceImpl implements ScheduledTasksService {
    /**
     * 隐患跟踪任务整改提醒内容
     */
    public static final String RECTIFICATION_MAIL_CONTENT = "总编号：【%s】\n 发现时间：【%tF】\n 发现人：【%s】\n 发现项：【%s】\n限整改期：【%tF】";
    /**
     * 隐患跟踪任务验证完成提醒内容
     */
    public static final String VERIFICATION_REMIND_MAIL_CONTENT = "【%s】 已整改完成，请您验证关闭";
    public static final String VERIFICATION_REMIND_TEMP = "总编号:【%s】 【%s】\n";
    /**
     * 隐患跟踪任务验证完成提醒内容
     */
    public static final String AFFIRM_REMIND_MAIL_CONTENT = "【%s】 已验证完成，请您确认关闭";

    private final Logger log = LoggerFactory.getLogger(this.getClass().getName());
    @Autowired
    private ApsHazardInvestigationTemplateServiceImpl apsHazardInvestigationTemplateService;
    @Autowired
    private SaveCheckCommonDao saveCheckCommonDao;
    @Autowired
    private SysDictService sysDictService;
    @Autowired
    private HiddenDangerTrackServiceImpl hiddenDangerTrackService;
    @Autowired
    private CheckTemplateServiceImpl checkTemplateService;
    @Autowired
    private ApsHazardInvestigationTemplateZibiaoServiceImpl apsHazardInvestigationTemplateZibiaoService;
    @Autowired
    private HazardInvestigationServiceImpl hazardInvestigationService;
    @Autowired
    private AspCompanyCertificationsServiceImpl aspCompanyCertificationsService;

    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        int currentMonth = calendar.get(Calendar.MONTH) + 1; // 月份是从0开始的，所以加1
        int currentDay = calendar.get(Calendar.DAY_OF_MONTH); // 当前日

        System.out.println("当前月份: " + currentMonth);
        System.out.println("当前日: " + currentDay);
    }

    @Override
    public void rectificationSystem() {
        List<HiddenDangerTrackDo> hiddenDangerTrackList = hiddenDangerTrackService.list(new LambdaQueryWrapper<HiddenDangerTrackDo>()
                .eq(BaseDo::getDeleted, 0)
                .eq(HiddenDangerTrackDo::getStatus, 20)
                .isNotNull(HiddenDangerTrackDo::getTrackuserid)
        );
        rectificationNotify(hiddenDangerTrackList);
    }

    @Override
    public void verifySystem() {
        List<HiddenDangerTrackDo> hiddenDangerTrackList = hiddenDangerTrackService.list(new LambdaQueryWrapper<HiddenDangerTrackDo>()
                .eq(BaseDo::getDeleted, 0)
                .eq(HiddenDangerTrackDo::getStatus, 30)
                .isNotNull(HiddenDangerTrackDo::getShopfacilitatorid)
        );
        verifyNotify(hiddenDangerTrackList);
    }

    @Override
    public void affirmSystem() {
        List<HiddenDangerTrackDo> hiddenDangerTrackDos = hiddenDangerTrackService.list(new LambdaQueryWrapper<HiddenDangerTrackDo>()
                .eq(BaseDo::getDeleted, 0)
                .eq(HiddenDangerTrackDo::getStatus, 40)
                .isNotNull(HiddenDangerTrackDo::getSafetypromoterid)
        );
        affirmNotify(hiddenDangerTrackDos);
    }

    /**
     * 点巡检隐患任务提醒
     *
     * @return
     */
    @Override
    public R hiddenDangerTask() {
        List<HiddenDangerTrackDo> hiddenDangerTrackDos = hiddenDangerTrackService.list(new LambdaQueryWrapper<HiddenDangerTrackDo>()
                .eq(BaseDo::getDeleted, "0")
                .eq(HiddenDangerTrackDo::getSource, "1")
                .eq(HiddenDangerTrackDo::getDangersource, DANGER_SOURCE_POINTCHECK)
                .last(" AND  DATEDIFF(NOW(),FINDTIME) BETWEEN 0 AND 7  "));
        if (hiddenDangerTrackDos.isEmpty()) {
            return R.ok();
        }
        LocalDate date = LocalDate.now(); // 获取当前日期
        DayOfWeek dayOfWeek = date.getDayOfWeek(); // 获取日期对应的星期几
        // 周五发送维修和生产提醒 周三发送生产提醒
        if (dayOfWeek != DayOfWeek.WEDNESDAY && dayOfWeek != DayOfWeek.FRIDAY) {
            return R.ok();
        }
        // 获取数据字典
        List<SysDictDo> dicts = sysDictService.list(new LambdaQueryWrapper<SysDictDo>().eq(BaseDo::getDeleted, "0").in(SysDictDo::getDicttype,
                TASK_SOURCE_TYPE, HIDDEN_DANGER_TYPE, HIDDEN_DANGER_STATUS));
        hiddenDangerTrackDos.forEach(info -> {
            if (StringUtils.isNotBlank(info.getDangersource())) {
                info.setDangersource(dicts.stream().filter(dict -> TASK_SOURCE_TYPE.equals(dict.getDicttype()) &&
                                info.getDangersource().equals(dict.getValue())).map(SysDictDo::getName)
                        .collect(Collectors.joining(",")));
            }

            if (StringUtils.isNotBlank(info.getHiddendangertype())) {
                info.setHiddendangertype(dicts.stream().filter(dict -> HIDDEN_DANGER_TYPE.equals(dict.getDicttype()) &&
                                info.getHiddendangertype().equals(dict.getValue())).map(SysDictDo::getName)
                        .collect(Collectors.joining(",")));
            }

            if (StringUtils.isNotBlank(info.getStatus())) {
                info.setStatus(dicts.stream().filter(dict -> HIDDEN_DANGER_STATUS.equals(dict.getDicttype()) &&
                                info.getStatus().equals(dict.getValue())).map(SysDictDo::getName)
                        .collect(Collectors.joining(",")));
            }
        });

        // 对业务数据按照厂区进行分组
        Map<String, List<HiddenDangerTrackDo>> collect = hiddenDangerTrackDos.stream().collect(Collectors.groupingBy(HiddenDangerTrackDo::getTenantid));
        collect.forEach((k, v) -> {
            // 周三和周五生成 生产提醒维修提醒
            if (DayOfWeek.WEDNESDAY == dayOfWeek) {
                // 生产提醒
                sendNotify(HIDDEN_DANGER_TASK_PRODUCTION, k, v);
            } else {
                // 生产提醒
                sendNotify(HIDDEN_DANGER_TASK_PRODUCTION, k, v);
                // 维修提醒
                sendNotify(HIDDEN_DANGER_TASK_MAINTAIN, k, v);
            }
        });
        return R.ok();
    }

    /**
     * 根据安全检查模板 定时生成安全检查计划信息
     *
     * @return
     */
    @Override
    public R createCheckPlanByTemp() {
        List<CheckTemplateDo> list = checkTemplateService.list(new LambdaQueryWrapper<CheckTemplateDo>()
                .eq(BaseDo::getDeleted, "0")
                .eq(CheckTemplateDo::getEnablestatus, "10")
                .eq(CheckTemplateDo::getJobstarttype, "10"));

        JSCommonUtils.parameterCheck(list::isEmpty, "", "安全检查模板暂无定时任务");
        //循环list
        list.forEach(checkTemplateDo -> {
            checkTemplateService.assembleCheckTask(checkTemplateDo, true);
        });


        return R.ok();
    }

    /**
     * 生成隐患排查任务
     *
     * @return
     */
    @Override
    public R creatHazardInvestigationTask() {
        // 获取所有开启的定时任务
        List<ApsHazardInvestigationTemplateDo> tempList = apsHazardInvestigationTemplateService.list(
                new LambdaQueryWrapper<ApsHazardInvestigationTemplateDo>()
                        .eq(BaseDo::getDeleted, "0")
                        .eq(ApsHazardInvestigationTemplateDo::getTaskgenerator, "1")
                        .eq(ApsHazardInvestigationTemplateDo::getTempstate, "10")
        );
        if (tempList.isEmpty()) {
            log.debug("暂无开启的定时任务模板");
            return R.ok();
        }
        // 模板ID
        List<String> tempIds = tempList.stream().map(ApsHazardInvestigationTemplateDo::getId).collect(Collectors.toList());
        // 模板检查项
        List<ApsHazardInvestigationTemplateZibiaoDo> templateZibiaoDos = apsHazardInvestigationTemplateZibiaoService.list(new LambdaQueryWrapper<ApsHazardInvestigationTemplateZibiaoDo>()
                .in(ApsHazardInvestigationTemplateZibiaoDo::getMubanid, tempIds)
                .eq(BaseDo::getDeleted, "0"));
        List<ApsHazardInvestigationTemplateZibiaoDo> subList;
        Calendar instance = Calendar.getInstance();
        for (ApsHazardInvestigationTemplateDo mainData : tempList) {
            String tempId = mainData.getId();
            // 获取本次需要生成任务的模板检查项
            subList = templateZibiaoDos.stream()
                    .filter(subData -> tempId.equals(subData.getMubanid()))
                    .collect(Collectors.toList());
            if (subList.isEmpty()) {
                continue;
            }
            Date date = preGenerationCheck(mainData, instance);
            if (date == null) {
                continue;
            }
            apsHazardInvestigationTemplateService.update(new LambdaUpdateWrapper<ApsHazardInvestigationTemplateDo>()
                    .eq(ApsHazardInvestigationTemplateDo::getId,mainData.getId())
                    .set(ApsHazardInvestigationTemplateDo::getGenerationdate,date));
            hazardInvestigationService.assembleTask(mainData,subList);
        }
        return R.ok();
    }

    @Override
    public R qualificationCertificateRemind() {
        List<AspCompanyCertificationsDo> list = aspCompanyCertificationsService.list(new LambdaQueryWrapper<AspCompanyCertificationsDo>()
                .eq(AspCompanyCertificationsDo::getDeleted,"0")
                .apply(" (DATEDIFF(NEXTREVIEWDATE,NOW()) <0  or DATEDIFF(NEXTREVIEWDATE,NOW()) in (30,15,7))"));
        aspCompanyCertificationsService.sendRemind(list);
        return R.ok();
    }

    /**
     * 更新隐患任务预警状态
     * @return
     */
    @Override
    public R updateHiddenDangerWarningStatus() {
        List<HiddenDangerTrackDo> hiddenDangerTracks = hiddenDangerTrackService.list(
                new LambdaQueryWrapper<HiddenDangerTrackDo>().eq(HiddenDangerTrackDo::getDeleted,"0")
                        .ne(HiddenDangerTrackDo::getHazardstate,"9"));
        JSCommonUtils.parameterCheck(hiddenDangerTracks::isEmpty, "暂无需要更新状态的隐患任务", "暂无需要更新状态的隐患任务");
        List<HiddenDangerTrackDo> updateList= new ArrayList<>();
        HiddenDangerTrackDo updateDo;
        for (HiddenDangerTrackDo hiddenDangerTrack : hiddenDangerTracks) {
            //限整改日期
            Date deadlineforhazardcontrol = hiddenDangerTrack.getDeadlineforhazardcontrol();
            if (deadlineforhazardcontrol == null ) {
                continue;
            }
            updateDo = new HiddenDangerTrackDo();
            updateDo.setId(hiddenDangerTrack.getId());
            Date bg = DateUtil.parseDate(DateUtil.format(new Date(), "yyyy-MM-dd"));
            Date end = DateUtil.parseDate(DateUtil.format(deadlineforhazardcontrol, "yyyy-MM-dd"));
            Long bday = DateUtil.between(bg, end, DateUnit.DAY, false);
            // 更新预警状态
            if (bday>3){
                updateDo.setWarnstatus("正常");
            }else if(bday > 1) {
                updateDo.setWarnstatus("3天");
            } else if (bday >= 0) {
                updateDo.setWarnstatus("1天");
            } else {
                updateDo.setWarnstatus("过期");
            }
            updateDo.setModifydate(new Date());
            updateList.add(updateDo);
        }
        if(!updateList.isEmpty()){
            hiddenDangerTrackService.updateBatchById(updateList);
        }
        return R.ok();
    }

    public Date preGenerationCheck(ApsHazardInvestigationTemplateDo hazardInvestigationTemplateDo,
                                   Calendar calendar) {
        int currentMonth = calendar.get(Calendar.MONTH) + 1; // 月份是从0开始的，所以加1
        int currentDay = calendar.get(Calendar.DAY_OF_MONTH); // 当前日
        int currentHour = calendar.get(Calendar.HOUR_OF_DAY); // 当前时间
        // 周期单位
        String inspectioncycleunit = hazardInvestigationTemplateDo.getInspectioncycleunit();
        // 巡检周期
        int inspectioncycle = hazardInvestigationTemplateDo.getInspectioncycle();
        // 上一次生产该任务的周期
        Date generationdate = hazardInvestigationTemplateDo.getGenerationdate();
        Date returnDate = calendar.getTime();
        int i = 0;
        if (generationdate != null) {
            // 当前时间距离上次生成时间的差值
            i = JSCommonUtils.DateDifferenceExample(generationdate, calendar.getTime(), inspectioncycleunit);
        }
        if (SaveConstans.INSPECTION_CYCLE_UNIT.HOUR.equals(inspectioncycleunit)) {
            LocalTime startTime = LocalTime.parse(hazardInvestigationTemplateDo.getStartingtimeofwork());
            LocalTime endTime = LocalTime.parse(hazardInvestigationTemplateDo.getEndtimeofwork());
            LocalTime currentTime = LocalTime.now();
            if(!currentTime.isBefore(startTime) && !currentTime.isAfter(endTime)){
                // 如果生成时间为空 或者 巡检周期大于时间差值
                if(generationdate==null || inspectioncycle == i){
                    return returnDate;
                }else{
                    return  null;
                }
            }else{
                return null;
            }
        } else if (SaveConstans.INSPECTION_CYCLE_UNIT.DAY.equals(inspectioncycleunit)) {
            if (generationdate == null) {
                return returnDate;
            } else if (i == inspectioncycle) {
                return returnDate;
            } else {
                return null;
            }
        } else if (SaveConstans.INSPECTION_CYCLE_UNIT.MONTH.equals(inspectioncycleunit)) {
            if (generationdate == null) {
                return returnDate;
            } else if (i == inspectioncycle && currentHour == 1) {
                return returnDate;
            } else {
                return null;
            }
        } else if (SaveConstans.INSPECTION_CYCLE_UNIT.YEAR.equals(inspectioncycleunit)) {
            if (generationdate == null) {
                return returnDate;
            } else if (i == inspectioncycle && currentMonth == 1 && currentDay == 1 && currentHour == 1) {
                return returnDate;
            } else {
                return null;
            }
        } else {
            log.error("未知的周期单位：{}", inspectioncycleunit);
            return null;
        }
    }

    /**
     * 发送消息提醒
     */
    public void sendNotify(String notifyType, String tenantId, List<HiddenDangerTrackDo> dangerTrackDos) {
        // 已读以往提醒信息
        saveCheckCommonDao.updateNotifyState(notifyType, tenantId);

        /****************************获取提醒人信息*******************************/
        List<String> recipientIds = new ArrayList<>();
        if (HIDDEN_DANGER_TASK_MAINTAIN.equals(notifyType)) {
            // 维修 对应工厂的设备部部长 + 设备部维修主管
            recipientIds = saveCheckCommonDao.getUserIdByRoleCodeAndOrgIdAndTenantId(Arrays.asList(HOED, EDMS), null, tenantId);
        } else {
            // 生产 根据 隐患地点 取对应部门车间的 车间主任、车间维修主管 角色中人员
            List<String> orgId = dangerTrackDos.stream().map(HiddenDangerTrackDo::getDangerworkpark).distinct().collect(Collectors.toList());
            if (!orgId.isEmpty()) {
                recipientIds.addAll(saveCheckCommonDao.getUserIdByRoleCodeAndOrgIdAndTenantId(Arrays.asList(WMS, LCZG), orgId, tenantId));
            }
            // 整改状态为“待整改”记录中的 指派跟踪人
            recipientIds.addAll(dangerTrackDos.stream().filter(info -> "待整改".equals(info.getStatus()))
                    .map(HiddenDangerTrackDo::getTrackuserid)
                    .filter(StringUtils::isNotBlank)
                    .distinct()
                    .collect(Collectors.toList()));
        }
        if (recipientIds.isEmpty()) {
            return;
        }
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat(DATE_PATTERN_YMD);
        // 附件生成
        List<ExportHiddenDangerVo> exportData = dangerTrackDos.stream().map((data) -> {
            ExportHiddenDangerVo exportHiddenDangerVo = new ExportHiddenDangerVo();
            exportHiddenDangerVo.setTenantId(COMPANY_MAP.get(data.getTenantid()));
            exportHiddenDangerVo.setStatus(data.getStatus());
            exportHiddenDangerVo.setCode(data.getCode());
            exportHiddenDangerVo.setHiddendangertype(data.getHiddendangertype());
            exportHiddenDangerVo.setHiddendangercontent(data.getHiddendangercontent());
            exportHiddenDangerVo.setTrackusername(data.getTrackusername());
            exportHiddenDangerVo.setFindUser(data.getFindusername());
            exportHiddenDangerVo.setFindDate(data.getFindtime() == null ? "" : simpleDateFormat.format(data.getFindtime()));
            exportHiddenDangerVo.setRectificationdate(data.getRectificationdate() == null ? "" : simpleDateFormat.format(data.getRectificationdate()));
            exportHiddenDangerVo.setCompletionschedule(data.getCompletionschedule());
            exportHiddenDangerVo.setFinishdate(data.getFinishdate() == null ? "" : simpleDateFormat.format(data.getFinishdate()));
            exportHiddenDangerVo.setDangersource(data.getDangersource());
            return exportHiddenDangerVo;
        }).collect(Collectors.toList());

        // 消息提醒ID
        String notifyId = SecurityUtil.getUUID();

        String fileNameAndId = ExportExcelByEasyExcel.generateExcel("file", WEEK_HIDDEN_DANGER_TASK + simpleDateFormat.format(new Date()) + XLSX,
                notifyId, exportData, ExportHiddenDangerVo.class);
        if (StringUtils.isBlank(fileNameAndId)) {
            return;
        }
        JSCommonUtils.sendNotify(notifyId, tenantId, WEEK_HIDDEN_DANGER_TASK,
                String.format(HIDDEN_DANGER_TASK_CONTENT, dangerTrackDos.size()), fileNameAndId, recipientIds, null,
                notifyType, false);
    }


    /**
     * 隐患任务整改提醒
     *
     * @param hiddenDangerTrackList
     * @return
     * @date 2023/12/20 9:54
     * @author shangmi
     */

    public void rectificationNotify(List<HiddenDangerTrackDo> hiddenDangerTrackList) {
        hiddenDangerTrackList.forEach(hiddenDangerTrack -> {
            List<String> userIds = Arrays.asList(hiddenDangerTrack.getTrackuserid().split(","));
            JSCommonUtils.sendNotify(RECTIFICATION_MAIL_TITLE,
                    String.format(RECTIFICATION_MAIL_CONTENT, hiddenDangerTrack.getCode(), hiddenDangerTrack.getFindtime(),
                            hiddenDangerTrack.getFindusername(), hiddenDangerTrack.getHiddendangercontent(),
                            hiddenDangerTrack.getRectificationdate()), null, userIds, hiddenDangerTrack.getId(), DANGERTASKS);
        });

    }


    /**
     * 隐患任务验证提醒
     *
     * @param hiddenDangerTrackList
     * @return
     * @date 2023/12/20 9:54
     * @author shangmi
     */

    public void verifyNotify(List<HiddenDangerTrackDo> hiddenDangerTrackList) {
        hiddenDangerTrackList.forEach(hiddenDangerTrack -> {
            List<String> userIds = Arrays.asList(hiddenDangerTrack.getShopfacilitatorid().split(","));
            String format = String.format(VERIFICATION_REMIND_TEMP, hiddenDangerTrack.getCode(), hiddenDangerTrack.getHiddendangercontent());
            JSCommonUtils.sendNotify(VERIFICATION_MAIL_TITLE,
                    String.format(VERIFICATION_REMIND_MAIL_CONTENT, format), null, userIds, hiddenDangerTrack.getId(), DANGERTASKS);
        });

    }

    /**
     * 隐患任务确认提醒
     *
     * @param hiddenDangerTrackList
     * @return
     * @date 2023/12/20 9:54
     * @author shangmi
     */

    public void affirmNotify(List<HiddenDangerTrackDo> hiddenDangerTrackList) {
        hiddenDangerTrackList.forEach(hiddenDangerTrack -> {
            List<String> userIds = Arrays.asList(hiddenDangerTrack.getSafetypromoterid().split(","));
            String format = String.format(VERIFICATION_REMIND_TEMP, hiddenDangerTrack.getCode(), hiddenDangerTrack.getHiddendangercontent());
            JSCommonUtils.sendNotify(AFFIRM_MAIL_TITLE,
                    String.format(AFFIRM_REMIND_MAIL_CONTENT, format), null, userIds, hiddenDangerTrack.getId(), DANGERTASKS);
        });

    }
}
