package com.ningdatech.pmapi.scheduler.task;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ningdatech.pmapi.projectlib.model.entity.Project;
import com.ningdatech.pmapi.projectlib.service.IProjectService;
import com.ningdatech.pmapi.scheduler.contants.TaskContant;
import com.ningdatech.pmapi.staging.contants.StagingContant;
import com.ningdatech.pmapi.staging.model.entity.ProjectStaging;
import com.ningdatech.pmapi.staging.service.IProjectStagingService;
import com.ningdatech.pmapi.staging.utils.ProjectStatusFlowMapUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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.function.Function;

/**
 * @Classname ProjectStatusFlowTask
 * @Description
 * @Date 2023/2/20 10:12
 * @Author PoffyZhang
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class ProjectStatusFlowTask {

    private final IProjectStagingService projectStagingService;

    private final IProjectService projectService;

    private final ProjectStatusFlowMapUtil projectStatusFlowMapUtil;

    @Scheduled(cron = "0 */1 * * * ?")
    public void statusFlow() throws UnknownHostException {
        //测试暂时用自己电脑HOST
        if (TaskContant.Host.HOST_ZPF.equals(InetAddress.getLocalHost().getHostName())) {
            //1. 定时取 项目暂存表的数据 去进行状态继续流转
            List<ProjectStaging> stagingList = projectStagingService.list(Wrappers.lambdaQuery(ProjectStaging.class)
                            .eq(ProjectStaging::getDead,Boolean.FALSE)
                            .ge(ProjectStaging::getNextTime, LocalDateTime.now())
                            .le(ProjectStaging::getRetryTimes, StagingContant.Retry.MAX_RETRY_TIMES)
                            .orderByAsc(ProjectStaging::getProjectId));

            log.info("需要状态流转的项目 size:{} :{}",stagingList.size(), JSON.toJSONString(stagingList));
            if(CollUtil.isEmpty(stagingList)){
                log.info("没有需要状态流转的项目!");
                return;
            }

            //遍历
            for(ProjectStaging projectStaging : stagingList){
                try{
                    Project project = projectService.getById(projectStaging.getProjectId());
                    if(Objects.isNull(project)){
                        log.info("此项目 【{}】 不存在",projectStaging.getProjectId());
                        continue;
                    }

                    //2. 用函数map 定位到 状态流转的函数
                    Map<Integer, Function<Project, Boolean>> reStartProcessMap =
                            projectStatusFlowMapUtil.statusFlowFunctionMap;

                    if(!reStartProcessMap.containsKey(project.getStatus())){
                        log.info("此项目 【{}】 当前状态 【{}】,没有对应流转函数",projectStaging.getProjectId(),project.getStatus());
                        continue;
                    }

                    Function<Project, Boolean> functionMap = reStartProcessMap.get(project.getStatus());
                    //执行对应的函数
                    if(functionMap.apply(project)){
                        //执行成功了 删除暂存的数据
                        projectStagingService.removeById(projectStaging);
                    }
                }catch (Exception e){
                    log.error("项目流转 异常 projectId:【" + projectStaging.getProjectId() + "】 异常内容:" + e);
                }finally {
                    //增加重试的次数 和下次扫描时间
                    projectStagingService.addRetryTimes(projectStaging);
                }
            }
        }
    }
}
