package com.hz.pm.api.scheduler.task;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.StopWatch;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Sets;
import com.hz.pm.api.common.model.constant.BizConst;
import com.hz.pm.api.projectlib.model.enumeration.ProjectRenewalApprovalStatusEnum;
import com.hz.pm.api.projectlib.model.enumeration.WarningFlowTypeEnum;
import com.hz.pm.api.projectlib.model.enumeration.WarningOperationTypeEnum;
import com.hz.pm.api.projectlib.model.entity.Project;
import com.hz.pm.api.projectlib.model.entity.ProjectRenewalFundDeclaration;
import com.hz.pm.api.projectlib.service.IProjectRenewalFundDeclarationService;
import com.hz.pm.api.projectlib.service.IProjectService;
import com.hz.pm.api.sys.enumeration.ProjectEarlyWarningStatusEnum;
import com.hz.pm.api.sys.model.entity.ProjectEarlyWarning;
import com.hz.pm.api.sys.model.entity.WflowEarlyWarningRecords;
import com.hz.pm.api.sys.service.IEarlyWarningRecordsService;
import com.hz.pm.api.sys.service.IProjectEarlyWarningService;
import com.wflow.enums.WarningRuleTypeEnum;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
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.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

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

    private final IProjectService projectService;

    private final IProjectEarlyWarningService projectEarlyWarningService;

    private final IEarlyWarningRecordsService earlyWarningRecordsService;

    private final IProjectRenewalFundDeclarationService renewalFundDeclarationService;

    private final TaskService taskService;

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

    @Scheduled(fixedDelay = 6000 * 120)
    public void doEarlyWarningDeclared() throws UnknownHostException {
        if (!HOST_NAME.equals(InetAddress.getLocalHost().getHostName())) {
            return;
        }

        log.info("=========== 预警项目维度任务开始 ========");
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        List<Project> projects = projectService.list(Wrappers.lambdaQuery(Project.class)
                .eq(Project::getNewest, Boolean.TRUE));

        if(CollUtil.isEmpty(projects)){
            log.info("系统没有项目 退出任务");
            stopWatch.stop();
            log.info("=========== 预警项目维度任务结束 耗时{}s", stopWatch.getTotalTimeSeconds());
            return;
        }

        Set<String> projectSet = Sets.newHashSet();
        Map<String, Project> projectMap = projects.stream().filter(p -> projectSet.add(p.getProjectCode()))
                .collect(Collectors.toMap(Project::getProjectCode, p -> p));
        List<ProjectEarlyWarning> warnings = projectEarlyWarningService.list();
        List<String> warningProjectCodes = warnings.stream().map(ProjectEarlyWarning::getProjectCode)
                .collect(Collectors.toList());

        //1.先补全 异常项目管理中 不存在的项目
        List<ProjectEarlyWarning> toAdd = projects.stream()
                .filter(p -> {
                    if(CollUtil.isEmpty(warningProjectCodes)){
                        return Boolean.TRUE;
                    }
                    if(!warningProjectCodes.contains(p.getProjectCode())){
                        return Boolean.TRUE;
                    }
                    return Boolean.FALSE;
                })
                .map(p -> {
                    ProjectEarlyWarning earlyWarning = new ProjectEarlyWarning();
                    earlyWarning.setAreaCode(p.getAreaCode());
                    earlyWarning.setBuildOrgCode(p.getBuildOrgCode());
                    earlyWarning.setProjectCode(p.getProjectCode());
                    earlyWarning.setCreateOn(LocalDateTime.now());
                    earlyWarning.setStatus(ProjectEarlyWarningStatusEnum.NORMAL.name());
                    earlyWarning.setRuleType(null);
                    return earlyWarning;
                })
                .collect(Collectors.toList());

        if(CollUtil.isNotEmpty(toAdd)){
            projectEarlyWarningService.saveBatch(toAdd);
        }

        //2.删除 已经不存在的项目
        List<ProjectEarlyWarning> toRemove = warnings.stream()
                .filter(w -> !projectMap.containsKey(w.getProjectCode()))
                .collect(Collectors.toList());
        if(CollUtil.isNotEmpty(toRemove)){
            List<Long> removeIds = toRemove.stream().map(ProjectEarlyWarning::getId)
                    .collect(Collectors.toList());
            projectEarlyWarningService.removeBatchByIds(removeIds);
        }

        //3.去查询 各个报警 是否已经正常
        List<ProjectEarlyWarning> trueWarnings = warnings.stream().filter(w -> Objects.nonNull(w.getNormal()) && !w.getNormal()).collect(Collectors.toList());
        if(CollUtil.isEmpty(trueWarnings)){
            log.info("没有异常的项目 要去查询");
            stopWatch.stop();
            log.info("=========== 预警项目维度任务结束 耗时{}s", stopWatch.getTotalTimeSeconds());
            return;
        }
        checkNormal(trueWarnings);

        stopWatch.stop();
        log.info("=========== 预警项目维度任务结束 耗时{}s", stopWatch.getTotalTimeSeconds());
    }

    //3.去查询 各个报警 是否已经正常
    private void checkNormal(List<ProjectEarlyWarning> trueWarnings) {
        //3.1 预警预警 如果正常了 要改会正常
        List<ProjectEarlyWarning> processWarning = trueWarnings.stream().filter(w -> Objects.nonNull(w.getProcessWarning())
                        && w.getProcessWarning())
                .collect(Collectors.toList());
        checkProcessWarning(processWarning);

        //3.2 填报预警 如果正常了 要改会正常
        List<ProjectEarlyWarning> declaredWarning = trueWarnings.stream().filter(w ->
                        Objects.nonNull(w.getDeclaredWarning())
                                && w.getDeclaredWarning())
                .collect(Collectors.toList());
        checkDeclaredWarning(declaredWarning);

        //3.3 实施预警 如果正常了 要改会正常
        List<ProjectEarlyWarning> operationWarning = trueWarnings.stream().filter(w ->
                        Objects.nonNull(w.getOperationWarning())
                                && w.getOperationWarning())
                .collect(Collectors.toList());
        checkOperationWarning(operationWarning);

        //3.4 续建资金预警 如果正常了 要改回正常
        List<ProjectEarlyWarning> renewalFundWarning = trueWarnings.stream().filter(w ->
                        Objects.nonNull(w.getRenewalFundWarning())
                                && w.getRenewalFundWarning())
                .collect(Collectors.toList());
        checkRenewalFundWarning(renewalFundWarning);
    }

    private void checkRenewalFundWarning(List<ProjectEarlyWarning> renewalFundWarnings) {
        if(CollUtil.isEmpty(renewalFundWarnings)){
            return;
        }

        for(ProjectEarlyWarning renewalFundWarning : renewalFundWarnings){
            String projectCode = renewalFundWarning.getProjectCode();
            Project project = projectService.getProjectByCode(projectCode);
            if(Objects.isNull(project)){
                continue;
            }

            WflowEarlyWarningRecords record = earlyWarningRecordsService.getOne(Wrappers.lambdaQuery(WflowEarlyWarningRecords.class)
                    .eq(WflowEarlyWarningRecords::getProjectCode, projectCode)
                    .eq(WflowEarlyWarningRecords::getRuleType, WarningRuleTypeEnum.OPERATION_WARNING.getCode())
                    .orderByDesc(WflowEarlyWarningRecords::getWarningTime)
                    .last(BizConst.LIMIT_1));
            if(Objects.isNull(record)){
                continue;
            }
            //借用了NODEID 其实 是续建id
            String nodeId = record.getNodeId();
            ProjectRenewalFundDeclaration renewalFund = renewalFundDeclarationService.getById(nodeId);
            if(Objects.isNull(renewalFund)){
                continue;
            }
            String approvalStatus = renewalFund.getApprovalStatus();
            ProjectRenewalApprovalStatusEnum match = ProjectRenewalApprovalStatusEnum
                    .match(approvalStatus);
            if(Objects.nonNull(match)){
                //如果是已经审批
                if(match.name().equals(ProjectRenewalApprovalStatusEnum.PASS.name())){
                    renewalFundWarning.setRenewalFundWarning(Boolean.FALSE);
                    //其它三种 都没有 说明已经正常了
                    if(!renewalFundWarning.getProcessWarning() &&
                            !renewalFundWarning.getDeclaredWarning() &&
                            !renewalFundWarning.getOperationWarning()){
                        renewalFundWarning.setNormal(Boolean.TRUE);
                        renewalFundWarning.setStatus(ProjectEarlyWarningStatusEnum.NORMAL.name());
                    }
                    projectEarlyWarningService.updateById(renewalFundWarning);
                }
            }
        }
    }

    private void checkOperationWarning(List<ProjectEarlyWarning> operationWarnings) {
        if(CollUtil.isEmpty(operationWarnings)){
            return;
        }

        for( ProjectEarlyWarning operationWarning : operationWarnings){
            String projectCode = operationWarning.getProjectCode();
            Project project = projectService.getProjectByCode(projectCode);
            if(Objects.isNull(project)){
                continue;
            }
            WflowEarlyWarningRecords record = earlyWarningRecordsService.getOne(Wrappers.lambdaQuery(WflowEarlyWarningRecords.class)
                    .eq(WflowEarlyWarningRecords::getProjectCode, projectCode)
                    .eq(WflowEarlyWarningRecords::getRuleType, WarningRuleTypeEnum.OPERATION_WARNING.getCode())
                    .orderByDesc(WflowEarlyWarningRecords::getWarningTime)
                    .last(BizConst.LIMIT_1));
            if(Objects.isNull(record)){
                continue;
            }
            Integer biz = record.getBiz();
            WarningOperationTypeEnum operationTypeEnum = WarningOperationTypeEnum.getByCode(biz);
            if(Objects.isNull(operationTypeEnum)){
                continue;
            }
            Integer projectStutas = operationTypeEnum.getProjectStutas();
            //已经不是这个状态了 说明已经被提交了
            if(!projectStutas.equals(project.getStatus())){
                operationWarning.setOperationWarning(Boolean.FALSE);
                //其它三种 都没有 说明已经正常了
                if(!operationWarning.getProcessWarning() &&
                        !operationWarning.getDeclaredWarning() &&
                        !operationWarning.getRenewalFundWarning()){
                    operationWarning.setNormal(Boolean.TRUE);
                    operationWarning.setStatus(ProjectEarlyWarningStatusEnum.NORMAL.name());
                }
                projectEarlyWarningService.updateById(operationWarning);
            }
        }
    }

    private void checkDeclaredWarning(List<ProjectEarlyWarning> declaredWarnings) {
        if(CollUtil.isEmpty(declaredWarnings)){
            return;
        }
        for( ProjectEarlyWarning declaredWarning : declaredWarnings){
            String projectCode = declaredWarning.getProjectCode();
            Project project = projectService.getProjectByCode(projectCode);
            if(Objects.isNull(project)){
                continue;
            }
            WflowEarlyWarningRecords record = earlyWarningRecordsService.getOne(Wrappers.lambdaQuery(WflowEarlyWarningRecords.class)
                    .eq(WflowEarlyWarningRecords::getProjectCode, projectCode)
                    .eq(WflowEarlyWarningRecords::getRuleType, WarningRuleTypeEnum.DECLARED_WARNING.getCode())
                    .orderByDesc(WflowEarlyWarningRecords::getWarningTime)
                    .last(BizConst.LIMIT_1));
            if(Objects.isNull(record)){
                continue;
            }
            Integer biz = record.getBiz();
            WarningFlowTypeEnum flowTypeEnum = WarningFlowTypeEnum.getByCode(biz);
            if(Objects.isNull(flowTypeEnum)){
                continue;
            }
            Integer projectStutas = flowTypeEnum.getProjectStutas();
            //已经不是这个状态了 说明已经被提交了
            if(!projectStutas.equals(project.getStatus())){
                declaredWarning.setDeclaredWarning(Boolean.FALSE);
                //其它三种 都没有 说明已经正常了
                if(!declaredWarning.getProcessWarning() &&
                        !declaredWarning.getOperationWarning() &&
                        !declaredWarning.getRenewalFundWarning()){
                    declaredWarning.setNormal(Boolean.TRUE);
                    declaredWarning.setStatus(ProjectEarlyWarningStatusEnum.NORMAL.name());
                }
                projectEarlyWarningService.updateById(declaredWarning);
            }
        }
    }

    /**
     * 流程 查看 是否已经处理过
     * @param processWarnings
     */
    private void checkProcessWarning(List<ProjectEarlyWarning> processWarnings) {
        if(CollUtil.isEmpty(processWarnings)){
            return;
        }
        for( ProjectEarlyWarning processWarning : processWarnings){
            String projectCode = processWarning.getProjectCode();
            WflowEarlyWarningRecords record = earlyWarningRecordsService.getOne(Wrappers.lambdaQuery(WflowEarlyWarningRecords.class)
                    .eq(WflowEarlyWarningRecords::getProjectCode, projectCode)
                    .orderByDesc(WflowEarlyWarningRecords::getWarningTime)
                    .last(BizConst.LIMIT_1));
            if(Objects.isNull(record)){
                continue;
            }
            String nodeId = record.getNodeId();
            if(StringUtils.isBlank(nodeId)){
                continue;
            }
            List<Task> tasks = taskService.createTaskQuery()
                    .taskDefinitionKey(nodeId)
                    .list();
            if(CollUtil.isEmpty(tasks)){
                //说明 已经审批通过了
                processWarning.setProcessWarning(Boolean.FALSE);
                //其它三种 都没有 说明已经正常了
                if(!processWarning.getDeclaredWarning() &&
                        !processWarning.getOperationWarning() &&
                        !processWarning.getRenewalFundWarning()){
                    processWarning.setNormal(Boolean.TRUE);
                    processWarning.setStatus(ProjectEarlyWarningStatusEnum.NORMAL.name());
                }
                projectEarlyWarningService.updateById(processWarning);
            }
        }

    }
}
