package io.wdd.func.auto.service;

import io.wdd.func.auto.beans.BaseFunctionEnum;
import io.wdd.func.auto.beans.ProjectDeployContext;
import io.wdd.server.beans.po.ServerInfoPO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class BaseFuncScheduler {

    @Resource
    FuncService funcService;

    public boolean runProcedure(ProjectDeployContext projectDeployContext) {

        // before run
        // check base requirement
        beforeRunProcedure(projectDeployContext);


        // during running
        doRunProcedure(projectDeployContext);

        // after run
        afterRunProcedure();


        return true;
    }

    private void afterRunProcedure() {

        // 检查是否安装完成, 对安装环境进行判定
        log.debug("afterRunProcedure complete!");
    }

    private void doRunProcedure(ProjectDeployContext projectDeployContext) {


        if (!MasterNodeProcedure(projectDeployContext)) {
            log.error("Master 初始化过程错误! 即将终止!");
        }

        if (!AgentNodeProcedure(projectDeployContext)) {
            log.error("Agent 初始化过程错误! 即将终止!");
        }


        log.info("初始化过程完成!");
    }

    private boolean MasterNodeProcedure(ProjectDeployContext projectDeployContext) {

        String masterTopicName = projectDeployContext
                .getMasterNode()
                .getTopicName();

        return serverDoRunProcedure(
                true,
                masterTopicName,
                projectDeployContext
        );

    }


    private void beforeRunProcedure(ProjectDeployContext projectDeployContext) {

        // 检查是否符合规定

        // 检查每一个Agent是否能够连通,调用命令返回结果

        // 打印施工信息

        // base function args
        // 执行 基础功能施工的内容


        // base func args
        ArrayList<String> baseFuncArgList = new ArrayList<>();
        baseFuncArgList.add(projectDeployContext
                .getMasterNode()
                .getServerIpInV4());

        projectDeployContext.setBaseFunctionArgs(baseFuncArgList);

        log.debug("beforeRunProcedure complete!");

    }

    private boolean AgentNodeProcedure(ProjectDeployContext projectDeployContext) {

        if (CollectionUtils.isEmpty(projectDeployContext.getAgentNodeList())) {
            return true;
        }

        List<String> agentTopicNameList = projectDeployContext
                .getAgentNodeList()
                .stream()
                .map(ServerInfoPO::getTopicName)
                .collect(Collectors.toList());

        for (String agentTopicName : agentTopicNameList) {
            if (!serverDoRunProcedure(
                    false,
                    agentTopicName,
                    projectDeployContext
            )) {
                log.error("{} agent run base func failed !", agentTopicName);
                return false;
            }
        }

        return true;
    }


    private boolean serverDoRunProcedure(boolean masterNode, String agentTopicName, ProjectDeployContext projectDeployContext) {

        List<BaseFunctionEnum> serverRunProcedureList;
        if (masterNode) {
            serverRunProcedureList = projectDeployContext.getMasterNodeBaseProcedure();
        } else {
            serverRunProcedureList = projectDeployContext.getAgentNodeBaseProcedure();
        }

        if (CollectionUtils.isEmpty(serverRunProcedureList)) {
            return true;
        }

        ArrayList<String> baseFuncArgList = projectDeployContext.getBaseFunctionArgs();

        for (BaseFunctionEnum durationBaseFunc : serverRunProcedureList) {

            //  add op name
            baseFuncArgList.add(
                    0,
                    durationBaseFunc.getFuncName()
            );

            if (!funcService.callBaseFuncAndJudge(
                    agentTopicName,
                    durationBaseFunc,
                    baseFuncArgList,
                    true
            )) {
                log.error(
                        "Agent {} Base Func Failed ! => {}",
                        agentTopicName,
                        durationBaseFunc
                );
                return false;
            }

            // remove
            baseFuncArgList.remove(0);
        }

        return true;
    }


}
