package cn.reghao.bnt.web.devops.app.service.bd.impl;

import cn.reghao.bnt.common.docker.model.DockerAuth;
import cn.reghao.bnt.common.msg.constant.PackType;
import cn.reghao.bnt.common.msg.event.EvtAppDeploy;
import cn.reghao.bnt.common.msg.event.EvtAppStatResult;
import cn.reghao.bnt.web.devops.aliyun.service.AliyunOss;
import cn.reghao.bnt.web.devops.app.db.query.AppBuildQuery;
import cn.reghao.bnt.web.devops.app.db.query.AppDeployQuery;
import cn.reghao.bnt.web.devops.app.model.po.AppBuilding;
import cn.reghao.bnt.web.devops.app.model.po.config.AppConfig;
import cn.reghao.bnt.web.devops.app.model.po.config.AppDeployConfig;
import cn.reghao.bnt.web.devops.app.model.po.log.BuildLog;
import cn.reghao.bnt.web.devops.app.service.AppDeployService;
import cn.reghao.bnt.web.devops.app.service.bd.DeployApp;
import cn.reghao.bnt.web.devops.app.service.bd.task.OssDeployTask;
import cn.reghao.bnt.web.devops.build.model.po.DockerRegistry;
import cn.reghao.bnt.web.devops.machine.service.MachineQuery;
import cn.reghao.bnt.web.ws.WsSender;
import cn.reghao.jutil.jdk.event.message.EventMessage;
import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.jutil.jdk.web.result.ResultStatus;
import cn.reghao.jutil.jdk.thread.ThreadPoolWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.concurrent.ExecutorService;

/**
 * @author reghao
 * @date 2023-02-28 11:40:45
 */
@Slf4j
@Service
public class DeployAppImpl implements DeployApp {
    ExecutorService deployPool = ThreadPoolWrapper.threadPool("deploy", 10);
    private final MachineQuery machineQuery;
    private final WsSender wsSender;
    private final AppDeployQuery appDeployQuery;
    private final AppDeployService appDeployService;
    private final AppBuildQuery appBuildQuery;
    private final AliyunOss aliyunOss;

    public DeployAppImpl(MachineQuery machineQuery, WsSender wsSender, AppDeployQuery appDeployQuery,
                         AppDeployService appDeployService, AppBuildQuery appBuildQuery, AliyunOss aliyunOss) {
        this.machineQuery = machineQuery;
        this.wsSender = wsSender;
        this.appDeployQuery = appDeployQuery;
        this.appDeployService = appDeployService;
        this.appBuildQuery = appBuildQuery;
        this.aliyunOss = aliyunOss;
    }

    @Override
    public void deploy(String buildLogId) {
        BuildLog buildLog = appBuildQuery.getBuildLog(buildLogId);
        AppBuilding appBuilding = new AppBuilding(buildLog);
        deploy(appBuilding);
    }

    @Override
    public void deploy(String buildLogId, String machineId) {
        BuildLog buildLog = appBuildQuery.getBuildLog(buildLogId);
        AppBuilding appBuilding = new AppBuilding(buildLog);
        String appId = appBuilding.getAppConfig().getAppId();
        if (machineId == null || machineId.isBlank()) {
            log.info("deploy app to all machines");
        } else {
            AppDeployConfig appDeployConfig = appDeployQuery.getByAppIdAndMachineId(appId, machineId);
            deploy(appBuilding, appDeployConfig);
        }
    }

    @Override
    public void deploy(AppBuilding appBuilding) {
        AppConfig appConfig = appBuilding.getAppConfig();
        appDeployQuery.getByAppId(appConfig.getAppId()).forEach(appDeployConfig -> deploy(appBuilding, appDeployConfig));
    }

    private void deploy(AppBuilding appBuilding, AppDeployConfig appDeployConfig) {
        String deployBy = appBuilding.getBuildBy();
        String packagePath = appBuilding.getPackagePath();

        String appId = appDeployConfig.getAppConfig().getAppId();
        String packType = appDeployConfig.getAppConfig().getPackerConfig().getType();

        String machineId = appDeployConfig.getMachineHost().getMachineId();
        String startScript = appDeployConfig.getStartScript();
        String startHome = appDeployConfig.getStartHome();
        String unpackScript = appDeployConfig.getUnpackScript();
        if (packType.equals(PackType.staticFiles.getName())) {
            OssDeployTask ossDeployTask = new OssDeployTask(aliyunOss, appDeployService, appBuilding, machineId);
            deployPool.submit(ossDeployTask);
            log.info("submit {} OssDeployTask", appId);
            return;
        }

        EvtAppDeploy deployParam = new EvtAppDeploy();
        deployParam.setAppId(appId);
        deployParam.setPackagePath(packagePath);
        deployParam.setPackType(packType);
        deployParam.setStartScript(startScript);
        deployParam.setStartHome(startHome);
        if (packType.equals(PackType.docker.getName())) {
            DockerRegistry registry = appDeployConfig.getAppConfig().getPackerConfig().getDockerRegistry();
            if (registry != null) {
                DockerAuth dockerAuth = new DockerAuth(registry.getRegistryUrl(), registry.getUsername(), registry.getPassword());
                deployParam.setDockerAuth(dockerAuth);
            }
        }

        if (appDeployQuery.isDeploying(appId, machineId)) {
            log.info("应用正在部署...");
            return;
        }

        if (!machineQuery.isAgentOnline(machineId)) {
            return;
        }

        appDeployService.updateBeforeDeploy(appBuilding, machineId, deployBy);
        EventMessage evtMsg = EventMessage.evt(deployParam);
        try {
            wsSender.send(machineId, evtMsg);
        } catch (IOException e) {
            e.printStackTrace();
            EvtAppStatResult statResult = new EvtAppStatResult(appId, machineId);
            statResult.setResult(Result.result(ResultStatus.FAIL, "连接异常"));
            appDeployService.updateAfterDeploy(statResult);
        }
    }
}
