package com.ningdatech.pmapi.scheduler.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.StopWatch;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.pmapi.common.enumeration.CommonEnum;
import com.ningdatech.pmapi.projectdeclared.model.entity.Contract;
import com.ningdatech.pmapi.projectdeclared.model.entity.Operation;
import com.ningdatech.pmapi.projectdeclared.service.IContractService;
import com.ningdatech.pmapi.projectdeclared.service.IOperationService;
import com.ningdatech.pmapi.projectlib.enumeration.ProjectStatusEnum;
import com.ningdatech.pmapi.projectlib.enumeration.WarningFlowTypeEnum;
import com.ningdatech.pmapi.projectlib.enumeration.WarningOperationTypeEnum;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.sys.manage.EarlyWarningManage;
import com.wflow.bean.entity.WflowEarlyWarning;
import com.wflow.enums.WarningRuleTypeEnum;
import com.wflow.service.IEarlyWarningService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.time.*;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author ZPF
 * @date 2023/8/3 上午9:53
 * 预警填报 超时任务
 */
@Component
@Slf4j
@RequiredArgsConstructor
public class EarlyWarningInstanceNotStartTask {

    @Value("${hostname}")
    private String HOST_NAME;

    private final IEarlyWarningService earlyWarningService;

    private final IProjectService projectService;

    private final EarlyWarningManage earlyWarningManage;

    private final IContractService contractService;

    private final IOperationService operationService;

    @Scheduled(cron = "0 0/2 * * * ?")
    public void doEarlyWarningDeclared() throws UnknownHostException {
        if (!HOST_NAME.equals(InetAddress.getLocalHost().getHostName())) {
            return;
        }

        log.info("=========== 预警填报超时任务开始 ========");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 1.查询 填报的 预警规则 填报类型的 每个区域 每个规则
        List<WflowEarlyWarning> warnings = earlyWarningService.list(Wrappers.lambdaQuery(WflowEarlyWarning.class)
                .eq(WflowEarlyWarning::getRuleType, WarningRuleTypeEnum.DECLARED_WARNING.getCode()));
        for(WflowEarlyWarning warning : warnings){
            //2. 取出rule的数据
            if(!warning.getIsOpen()){
                log.info(warning.getId() + " 此规则关闭了");
                continue;
            }

            String noticeMethod = warning.getNoticeMethod();
            if(StringUtils.isBlank(noticeMethod) ||
                    (!noticeMethod.contains(String.valueOf(CommonEnum.ZWDD.getCode())) &&
                            !noticeMethod.contains(String.valueOf(CommonEnum.MOBILE.getCode())))){
                log.info("通知方式为空或者错误!");
                return;
            }

            String noticeContent = warning.getNoticeContent();
            String rule = warning.getRule();
            if(StringUtils.isNotBlank(rule)){
                JSONArray ruleArray = JSON.parseArray(rule);
                if(CollUtil.isNotEmpty(ruleArray)){
                    ruleArray.forEach(r -> {
                        JSONObject rJson = JSON.parseObject(JSON.toJSONString(r));
                        Integer time = rJson.getInteger("time");
                        Integer biz = rJson.getInteger("biz");
                        if(Objects.isNull(time) || Objects.isNull(biz)){
                            log.info("规则数据 错误 :{}",rJson);
                            return;
                        }

                        WarningFlowTypeEnum flowTypeEnum = WarningFlowTypeEnum.getByCode(biz);
                        if(Objects.isNull(flowTypeEnum)){
                            log.info("匹配不到 业务类型");
                            return;
                        }

                        //得出 对应待提交的项目状态
                        Integer projectStutas = flowTypeEnum.getProjectStutas();
                        String areaCode = warning.getAreaCode();
                        //测试先用分钟
                        //查询 所有这个区域的项目 未提交的项目
                        List<Project> needNextProjects = projectService.list(Wrappers.lambdaQuery(Project.class)
                                .eq(Project::getAreaCode, areaCode)
                                .eq(Project::getNewest, Boolean.TRUE)
                                .eq(Project::getStatus,projectStutas));
                        log.info("needNextProjects :{}",needNextProjects.size());
                        //需要发通知的项目
                        List<Project> needToWaringProjects = needNextProjects.stream()
                                .filter(p -> {
                                    //判断 当状态在 建设中的时候 是不是要初验了
                                    if(ProjectStatusEnum.UNDER_CONSTRUCTION.getCode().equals(projectStutas)){
                                        List<Long> allVersionProjectId = projectService.getAllVersionProjectId(p);
                                        //如果合同信息提交过了 才是 待初验状态
                                        if(StringUtils.isNotBlank(p.getPreliminaryInspectionMaterials())){
                                            if(0L == contractService.count(Wrappers.lambdaQuery(Contract.class)
                                                    .in(Contract::getProjectId, allVersionProjectId))){
                                                return Boolean.FALSE;
                                            }
                                        }
                                    }

                                    log.info("projectId :{}",p.getId());
                                    log.info("秒数差 :{}",Duration.between(p.getUpdateOn(),LocalDateTime.now()).getSeconds());

                                    if(Duration.between(p.getUpdateOn(),LocalDateTime.now()).toMinutes() >= time * 60 && //time * 60
                                            Duration.between(p.getUpdateOn(),LocalDateTime.now()).toMinutes() <= time * 60 + 1){ //time * 60
                                        return Boolean.TRUE;
                                    }
                                    return Boolean.FALSE;
                                })
                                .collect(Collectors.toList());

                        if(StringUtils.isBlank(noticeMethod) ||
                                (!noticeMethod.contains(String.valueOf(CommonEnum.ZWDD.getCode())) &&
                                        !noticeMethod.contains(String.valueOf(CommonEnum.MOBILE.getCode())))){
                            log.info("通知方式为空或者错误!");
                            return;
                        }

                        for(Project needToWaringProject : needToWaringProjects){
                            //去预警通知
                            String employeeCode = needToWaringProject.getSponsor();
                            earlyWarningManage.doEarlyWarning(noticeMethod,noticeContent,time,biz,
                                    needToWaringProject.getUpdateOn(),employeeCode,needToWaringProject,
                                    WarningRuleTypeEnum.DECLARED_WARNING.getCode());
                        }
                    });
                }
            }
        }

        stopWatch.stop();
        log.info("=========== 预警填报超时任务结束 耗时{}s", stopWatch.getTotalTimeSeconds());
    }

    @Scheduled(cron = "10 0/2 * * * ?")
    public void doEarlyWarningOperation() throws UnknownHostException {
        if (!HOST_NAME.equals(InetAddress.getLocalHost().getHostName())) {
            return;
        }

        log.info("=========== 预警实施超时任务开始 ========");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 1.查询 填报的 预警规则 填报类型的 每个区域 每个规则
        List<WflowEarlyWarning> warnings = earlyWarningService.list(Wrappers.lambdaQuery(WflowEarlyWarning.class)
                .eq(WflowEarlyWarning::getRuleType, WarningRuleTypeEnum.OPERATION_WARNING.getCode()));
        for(WflowEarlyWarning warning : warnings){
            //2. 取出rule的数据
            if(!warning.getIsOpen()){
                log.info(warning.getId() + " 此规则关闭了");
                continue;
            }

            String noticeMethod = warning.getNoticeMethod();
            if(StringUtils.isBlank(noticeMethod) ||
                    (!noticeMethod.contains(String.valueOf(CommonEnum.ZWDD.getCode())) &&
                            !noticeMethod.contains(String.valueOf(CommonEnum.MOBILE.getCode())))){
                log.info("通知方式为空或者错误!");
                return;
            }

            String noticeContent = warning.getNoticeContent();
            String rule = warning.getRule();
            if(StringUtils.isNotBlank(rule)){
                JSONArray ruleArray = JSON.parseArray(rule);
                if(CollUtil.isNotEmpty(ruleArray)){
                    ruleArray.forEach(r -> {
                        JSONObject rJson = JSON.parseObject(JSON.toJSONString(r));
                        Integer time = rJson.getInteger("time");
                        Integer biz = rJson.getInteger("biz");
                        if(Objects.isNull(time) || Objects.isNull(biz)){
                            log.info("规则数据 错误 :{}",rJson);
                            return;
                        }

                        WarningOperationTypeEnum operationTypeEnum = WarningOperationTypeEnum.getByCode(biz);
                        if(Objects.isNull(operationTypeEnum)){
                            log.info("匹配不到 业务类型");
                            return;
                        }

                        //得出 对应待提交的项目状态
                        Integer projectStutas = operationTypeEnum.getProjectStutas();
                        String areaCode = warning.getAreaCode();
                        //测试先用分钟
                        //查询 所有这个区域的项目 未提交的项目
                        List<Project> needNextProjects = projectService.list(Wrappers.lambdaQuery(Project.class)
                                .eq(Project::getAreaCode, areaCode)
                                .eq(Project::getNewest, Boolean.TRUE)
                                .eq(Project::getStatus,projectStutas));
                        log.info("needNextProjects :{}",needNextProjects.size());
                        List<String> projectCodes = needNextProjects.stream().map(Project::getProjectCode).collect(Collectors.toList());

                        List<Operation> operations = operationService.list(Wrappers.lambdaQuery(Operation.class)
                                .in(Operation::getProjectCode, projectCodes));

                        Map<String,Operation> operationMap = operations.stream().collect(Collectors.toMap(Operation::getProjectCode,o -> o));
                        //需要发通知的项目
                        List<Project> needToWaringProjects = needNextProjects.stream()
                                .filter(p -> {
                                    //判断 当状态在 建设中的时候 是不是要初验了
                                    if(ProjectStatusEnum.UNDER_CONSTRUCTION.getCode().equals(projectStutas)){
                                        List<Long> allVersionProjectId = projectService.getAllVersionProjectId(p);
                                        //如果合同信息提交过了 才是 待初验状态
                                        if(StringUtils.isNotBlank(p.getPreliminaryInspectionMaterials())){
                                            if(0L == contractService.count(Wrappers.lambdaQuery(Contract.class)
                                                    .in(Contract::getProjectId, allVersionProjectId))){
                                                return Boolean.FALSE;
                                            }
                                        }
                                    }

                                    //判断 实施信息中 初验和终验的时间
                                    if(!operationMap.containsKey(p.getProjectCode())){
                                        return Boolean.FALSE;
                                    }
                                    Operation operation = operationMap.get(p.getProjectCode());
                                    if(WarningOperationTypeEnum.CHUYAN.getCode().equals(biz)){
                                        //初验
                                        if(Duration.between(operation.getInitialInspectionDate(),LocalDateTime.now()).toMinutes() >= time * 60 && //time * 60
                                                Duration.between(operation.getInitialInspectionDate(),LocalDateTime.now()).toMinutes() <= time * 60 + 1){ //time * 60
                                            return Boolean.TRUE;
                                        }
                                    }else if(WarningOperationTypeEnum.ZHONGYAN.getCode().equals(biz)){
                                        //终验
                                        if(Duration.between(operation.getFinalInspectionDate(),LocalDateTime.now()).toMinutes() >= time * 60 && //time * 60
                                                Duration.between(operation.getFinalInspectionDate(),LocalDateTime.now()).toMinutes() <= time * 60 + 1){ //time * 60
                                            return Boolean.TRUE;
                                        }
                                    }

                                    return Boolean.FALSE;
                                })
                                .collect(Collectors.toList());

                        if(StringUtils.isBlank(noticeMethod) ||
                                (!noticeMethod.contains(String.valueOf(CommonEnum.ZWDD.getCode())) &&
                                        !noticeMethod.contains(String.valueOf(CommonEnum.MOBILE.getCode())))){
                            log.info("通知方式为空或者错误!");
                            return;
                        }

                        for(Project needToWaringProject : needToWaringProjects){
                            //去预警通知
                            String employeeCode = needToWaringProject.getSponsor();
                            earlyWarningManage.doEarlyWarning(noticeMethod,noticeContent,time,biz,
                                    needToWaringProject.getUpdateOn(),employeeCode,needToWaringProject,
                                    WarningRuleTypeEnum.OPERATION_WARNING.getCode());
                        }
                    });
                }
            }
        }

        stopWatch.stop();
        log.info("=========== 预警实施超时任务结束 耗时{}s", stopWatch.getTotalTimeSeconds());
    }
}
