package io.wdd.func.auto.service;

import io.wdd.func.auto.beans.HarborFunctionEnum;
import io.wdd.func.auto.beans.ProjectDeployContext;
import io.wdd.server.beans.po.ServerInfoPO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import static io.wdd.func.auto.beans.ProjectDeployContext.PROJECT_NEED_TO_BY_SYNCHRONIZED;

@Service
@Slf4j
public class HarborFuncScheduler {

    @Resource
    FuncService funcService;

    public boolean runProcedure(ProjectDeployContext projectDeployContext) {

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


        // during run
        doRunProcedure(projectDeployContext);


        // after run
        afterRunProcedure(projectDeployContext);


        return true;
    }

    private void afterRunProcedure(ProjectDeployContext projectDeployContext) {


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

    private void doRunProcedure(ProjectDeployContext projectDeployContext) {

        // 执行 基础功能施工的内容
        String masterTopicName = projectDeployContext
                .getMasterNode()
                .getTopicName();

        // create harbor project
        if (!CreateHarborProject(projectDeployContext)) {
            log.error("create harbor project failed !");
        }

        // check harbor project
        // list
        if (!ListHarborProject(projectDeployContext)) {
            log.error("list harbor project failed !");
        }

        int maxSyncStatusCheckCount = 1000;
        int timePinch = 2;

        for (String project : PROJECT_NEED_TO_BY_SYNCHRONIZED) {

            // 1 - sync harbor
            log.info(
                    "start to sync project of [ {} ]",
                    project
            );
            projectDeployContext.setCurrentSynchronizingProject(project);
            if (!SyncBetweenHarbor(projectDeployContext)) {
                log.error(
                        "sync harbor project [ {} ] failed !",
                        project
                );
            }

            int waitCount = 0;
            while (waitCount < maxSyncStatusCheckCount && !checkHarborSyncStatus(projectDeployContext)) {
                waitCount++;
                try {
                    TimeUnit.SECONDS.sleep(timePinch);
                } catch (InterruptedException e) {
                    log.error(
                            "wait for project of [ {} ] sync status error !",
                            project
                    );
                }
            }

            if (waitCount == maxSyncStatusCheckCount) {
                continue;
            }

            log.info(
                    "project of [ {} ] has sync success !",
                    project
            );
        }

        log.info("Harbor Image Synchronized Succeed !");
    }


    private boolean CreateHarborProject(ProjectDeployContext projectDeployContext) {

        // use master node as harbor server
        ServerInfoPO masterNode = projectDeployContext.getMasterNode();

        ArrayList<String> createProjectArgList = new ArrayList<>();
        createProjectArgList.add(HarborFunctionEnum.CREATE_PROJECT.getOpName());
        createProjectArgList.add(masterNode.getServerIpInV4());

        // send harbor create message
        boolean createProjectOK = funcService.callHarborFuncAndJudge(
                masterNode.getTopicName(),
                HarborFunctionEnum.CREATE_PROJECT,
                createProjectArgList
        );
        if (!createProjectOK) {
            log.error(
                    "[CreateHarborProject] - project create failed ! => {}",
                    createProjectArgList
            );
            return false;
        }


        return true;
    }

    /**
     * check harbor project exists
     *
     * @param projectDeployContext
     * @return
     */
    private boolean ListHarborProject(ProjectDeployContext projectDeployContext) {

        // use master node as harbor server
        ServerInfoPO masterNode = projectDeployContext.getMasterNode();

        ArrayList<String> listProjectArgList = new ArrayList<>();
        listProjectArgList.add(HarborFunctionEnum.LIST_PROJECT.getOpName());
        listProjectArgList.add(masterNode.getServerIpInV4());

        // send harbor create message
        boolean listProjectOK = funcService.callHarborFuncAndJudge(
                masterNode.getTopicName(),
                HarborFunctionEnum.LIST_PROJECT,
                listProjectArgList
        );

        if (!listProjectOK) {
            log.error(
                    "[ListHarborProject] - List Harbor Project Failed !=> {}",
                    listProjectArgList
            );
            return false;
        }

        return true;
    }

    private boolean SyncBetweenHarbor(ProjectDeployContext projectDeployContext) {

        // use master node as harbor server
        ServerInfoPO masterNode = projectDeployContext.getMasterNode();

        ArrayList<String> syncHarborArgList = new ArrayList<>();
        // zero arg
        syncHarborArgList.add(HarborFunctionEnum.SYNC_PROJECT_BETWEEN_HARBOR.getOpName());
        // first func args
        syncHarborArgList.add(masterNode.getServerIpInV4());

        // second arg sourceHarborHost
//        String sourceHarborHost = getIPv4Address();
        syncHarborArgList.add("harbor.wdd.io");

        // third arg  sync project name
        syncHarborArgList.add(projectDeployContext.getCurrentSynchronizingProject());


        log.info(
                "{} start !  args are => {}",
                HarborFunctionEnum.SYNC_PROJECT_BETWEEN_HARBOR.getOpName(),
                syncHarborArgList
        );

        boolean syncHarborProjectOk = funcService.callHarborFuncAndJudge(
                masterNode.getTopicName(),
                HarborFunctionEnum.SYNC_PROJECT_BETWEEN_HARBOR,
                syncHarborArgList
        );

        if (!syncHarborProjectOk) {
            log.error(
                    "[SYNC_PROJECT_BETWEEN_HARBOR] - Sync Harbor Project Failed !=> {}",
                    syncHarborArgList
            );
            return false;
        }

        return true;

    }

    private String getIPv4Address() {

        String os = System
                .getProperty("os.name")
                .toLowerCase();
//        String devHarborSourceHost = "10.250.0.100";
        String devHarborSourceHost = "20.4.16.200"; // cqga
        if (os.contains("linux")) {
            try {
                InetAddress localhost = InetAddress.getLocalHost();


                if (localhost.getHostAddress() != null && !localhost
                        .getHostAddress()
                        .isEmpty() && !StringUtils.startsWith(localhost.getHostAddress(), "127")) {
                    return localhost.getHostAddress();
                } else {

                    return devHarborSourceHost;
                }

            } catch (UnknownHostException e) {
                throw new RuntimeException(e);
            }

        } else {
            log.info(
                    "getIPv4Address => dev env set ipv4 addr to => {}",
                    devHarborSourceHost
            );
            return devHarborSourceHost;
        }

    }

    private boolean checkHarborSyncStatus(ProjectDeployContext projectDeployContext) {
        ServerInfoPO masterNode = projectDeployContext.getMasterNode();

        ArrayList<String> syncHarborArgList = new ArrayList<>();
        syncHarborArgList.add(HarborFunctionEnum.SYNC_STATUS_HARBOR.getOpName());
        syncHarborArgList.add(masterNode.getServerIpInV4());


        log.info(
                "{} start !  args are => {}",
                HarborFunctionEnum.SYNC_STATUS_HARBOR.getOpName(),
                syncHarborArgList
        );

        return funcService.callHarborFuncAndJudge(
                masterNode.getTopicName(),
                HarborFunctionEnum.SYNC_STATUS_HARBOR,
                syncHarborArgList
        );
    }


    private void beforeRunProcedure(ProjectDeployContext projectDeployContext) {

        // 检查是否符合规定

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

        // 打印施工信息

        log.debug("beforeRunProcedure complete!");

    }

    private boolean MasterNodeBaseProcedure(String masterTopicName) {


        return true;
    }


    private boolean AgentNodeProcedure(List<String> agentTopicNameList) {

        return true;
    }

}
