package net.northking.cctp.se.script.service;

import lombok.extern.slf4j.Slf4j;
import net.northking.cctp.se.script.bean.Script;
import net.northking.cctp.se.script.bean.ScriptRuntime;
import net.northking.cctp.se.script.core.ScriptExecutor;
import net.northking.cctp.se.script.core.ScriptResolutionService;
import net.northking.cctp.se.util.JsonUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 脚本准备服务
 */
@Slf4j
@Service
public class ScriptResolutionServiceImpl implements ScriptResolutionService {
    private Map<String,ScriptExecutor> scriptExecutorMap = new ConcurrentHashMap<>();
    @Override
    public Script parse(String scriptJson) {
        log.info("Parsing the script json string");
        return JsonUtils.fromJsonString(scriptJson,Script.class);
    }

    @Override
    public void prepareScriptResources(Script script) {
        log.info("Preparing the script  resource ...");

        log.info("Script resources prepared.");
    }

    @Override
    public ScriptExecutor getScriptExecutor(String identifier) {
        return scriptExecutorMap.get(identifier);
    }

    /**
     * 移除
     *
     * @param identifier
     * @return
     */
    @Override
    public ScriptExecutor removeScriptExecutor(String identifier) {
        return scriptExecutorMap.remove(identifier);
    }

    @Override
    public ScriptExecutor createDebugScriptRuntime(Map<String, Object> debugInfo, Script script) {
        if (debugInfo==null){
            log.warn("Invalid debugInfo");
            return null;
        }
        String identifier = (String)debugInfo.get("sessionId");
        String projectId = (String)debugInfo.get("projectId");
        String envId = (String) debugInfo.get("envId");
        ScriptExecutor executor  = new ScriptRuntimeExecutor(identifier, projectId, envId, script);
        scriptExecutorMap.put(identifier,executor);
        return executor;
    }

    @Override
    public ScriptExecutor createTaskScriptRuntime(Map<String, Object> taskInfo, Script script) {
        if (taskInfo==null || script == null){
            log.warn("Invalid debugInfo or script");
            return null;
        }
        String identifier = (String)taskInfo.get("scheduleId");
        String projectId = (String)taskInfo.get("projectId");
        boolean snapshot = (boolean)taskInfo.get("snapshot");
        boolean errorSnapshot = (boolean)taskInfo.get("errorSnapshot");
        String envId = null;
        if (null != taskInfo.get("envId")) {
            envId = (String) taskInfo.get("envId");
        }
        ScriptExecutor executor  = new ScriptRuntimeExecutor(identifier,projectId, envId,script,errorSnapshot,snapshot);

        scriptExecutorMap.put(identifier,executor);
        return executor;
    }


    @Override
    public boolean isRunnable(Script script) {
        log.info("Check the script whether is runnable ...");
        if(null == script){
            return  false;
        }
        ScriptRuntime requiredRuntime = script.getRuntime();
        if (null == requiredRuntime){//说明对运行环境无要求
            return true;
        }
        if(!checkOS(requiredRuntime)){//如果操作系统不满足要求
            return false;
        }
        if (!checkOSArch(requiredRuntime)){//如果OS Arch不满足要求
            return false;
        }
        if (!checkCpuArch(requiredRuntime)){//如果CPU Arch不满足要求
            return false;
        }
        return true;
    }

    private boolean checkOS(ScriptRuntime runtime) {
        log.info("Check the OS ...");
        String[] os =  runtime.getOs();
        if (null == os || os.length ==0 || Arrays.binarySearch(os,"any")==-1){
            return true;
        }
        String sysOS = System.getProperty("os");
        boolean ret = Arrays.binarySearch(os,sysOS) > -1;
        if (!ret){
            log.warn("Required OS:{},actual OS:{}",Arrays.toString(os),sysOS);
        }
        return ret;
    }
    private boolean checkOSArch(ScriptRuntime runtime) {
        log.info("Check the OSArch ...");
        String osArch = runtime.getOsArch();
        if (StringUtils.isBlank(osArch) || "any".equalsIgnoreCase(osArch)){
                return true;
        }
        String sysOSArch = System.getProperty("osArch");
        boolean ret = osArch.equalsIgnoreCase(sysOSArch);
        if (!ret){
            log.warn("Required OS Arch:{},actual OS Arch:{}",osArch,sysOSArch);
        }
        return ret;
    }

    private boolean checkCpuArch(ScriptRuntime runtime) {
        log.info("Check the CpuArch ...");
        String cpuArch = runtime.getCpuArch();
        if (StringUtils.isBlank(cpuArch) || "any".equalsIgnoreCase(cpuArch)){
            return true;
        }
        String sysCpuArch = System.getProperty("cpuArch");
        boolean ret = cpuArch.equalsIgnoreCase(sysCpuArch);
        if (!ret){
            log.warn("Required CPU Arch:{},actual CPU Arch:{}",cpuArch,sysCpuArch);
        }
        return ret;
    }
}
