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


import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import net.northking.cctp.element.core.DeviceDriver;
import net.northking.cctp.element.core.exception.ExecuteException;
import net.northking.cctp.se.debug.bean.DebugerConst;
import net.northking.cctp.se.debug.bean.DebuggerRequest;
import net.northking.cctp.se.debug.bean.DebuggerResponse;
import net.northking.cctp.se.device.bean.MobileDeviceConnection;
import net.northking.cctp.se.device.bean.PCDeviceConnection;
import net.northking.cctp.se.device.service.DeviceConnection;
import net.northking.cctp.se.device.service.DeviceConnectionService;
import net.northking.cctp.se.log.bean.ExecuteLog;
import net.northking.cctp.se.log.bean.StepLog;
import net.northking.cctp.se.script.bean.*;
import net.northking.cctp.se.script.core.*;
import net.northking.cctp.se.script.service.ScriptRuntimeExecutor;
import net.northking.cctp.se.util.JsonUtils;
import net.northking.cctp.se.util.SpringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.logging.LogLevel;

import javax.websocket.Session;
import java.util.*;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class DefaultDebugSession implements DebugSession {
    private final static String DEBUG_THREAD_NAME_TEMPLATE = "DebugThread-%s";
    public static final String DEVICE_INIT_FAIL_MSG = "初始化失败,原因：%s";
    private String deviceToken;
    private Session session;
    private String sessionId;
    private String sessionType;
    private String deviceId;
    private DeviceConnection deviceConnection;

    private boolean running = true;

    private Thread thread;

    private Future<?> future;

    private final Lock lock = new ReentrantLock();

    private ScriptRuntimeListener listener = new ScriptRuntimeListener() {
        @Override
        public void doLog(IScriptRuntimeContext context, String level, String msg) {
            ExecuteLog executeLog = new ExecuteLog();
            executeLog.setTime(new Date());
            executeLog.setLog(msg);
            executeLog.setLevel(level);
            Map<String, Object> logMap = new HashMap<>();
            logMap.put("cmd", DebugerConst.ReplyConst.KEY_CMD_LOG);
            logMap.put(DebugerConst.KEY_SESSIONID, sessionId);
            logMap.put(DebugerConst.ReplyConst.KEY_REPLY_DATA, executeLog);
            sendText(JsonUtils.toJson(logMap));
        }

        @Override
        public void doLog(IScriptRuntimeContext context, StepLog steplog) {
            Map<String, Object> logMap = new HashMap<>();
            logMap.put("cmd", DebugerConst.ReplyConst.KEY_CMD_LOG);
            logMap.put(DebugerConst.KEY_SESSIONID, sessionId);
            logMap.put(DebugerConst.ReplyConst.KEY_REPLY_DATA, steplog);
            sendText(JsonUtils.toJson(logMap));
        }

        @Override
        public void doReply(IScriptRuntimeContext context, StepExecuteResult result) {
            // 执行结果返回
            List<StepExecuteResult> childResult = result.getChildResult();
            if (childResult != null) {
                result.setChildResult(null); // 调试过程中子步骤的结果对于前端没有意义
            }
            HashMap<String, Object> replyMap = new HashMap<>();
            replyMap.put("cmd", DebugerConst.ReplyConst.KEY_CMD_REPLY);
            replyMap.put(DebugerConst.KEY_SESSIONID, sessionId);
            replyMap.put(DebugerConst.ReplyConst.KEY_REPLY_DATA, result);
            log.debug("step_result -> {}", JsonUtils.toJson(replyMap));
            sendText(JsonUtils.toJson(replyMap));
            if (childResult != null) {
                result.setChildResult(childResult);
            }
        }

        @Override
        public void doReply(IScriptRuntimeContext context, String cmd, String level, Object obj) {
            // 日志返回
            HashMap<String, Object> replyMap = new HashMap<>();
            replyMap.put("cmd", cmd);
            replyMap.put(DebugerConst.KEY_SESSIONID, sessionId);
            replyMap.put(DebugerConst.ReplyConst.KEY_REPLY_DATA, obj);
            sendText(JsonUtils.toJson(replyMap));
        }

        private void sendText(String msg) {
            try {
                if (session.isOpen()) {
                	DebuggerResponse.send(session, sessionId, msg);
                }
            } catch (IllegalStateException e) {
                log.error("通道发生异常", e);
                if (e.getMessage().contains("TEXT_FULL_WRITING")) {
                    throw new ExecuteException("发送信息失败：信息通道并发异常", e);
                }
            } catch (Exception e) {
                log.error("发送执行结果失败 " + e.getMessage(), e);
            }
        }
    };


    private BlockingQueue<DebuggerRequest> requestQueue = new LinkedBlockingQueue<>();

    public DefaultDebugSession(String deviceToken, String sessionType, Session session, String sessionId) {
        this.deviceToken = deviceToken;
        this.sessionType = sessionType;
        this.session = session;
        this.sessionId = sessionId;
    }

    @Override
    public String getSessionType() {
        return sessionType;
    }

    @Override
    public String getSessionId() {
        return sessionId;
    }

    @Override
    public String getDeviceToken() {
        return deviceToken;
    }

    /**
     * 获取设备id
     *
     * @return
     */
    @Override
    public String getDeviceId() {
        return this.deviceId;
    }

    @Override
    public void processRequest(DebuggerRequest request) {
        log.debug("processRequest的projectId,{}",request.getProjectId());
        requestQueue.add(request);
    }

    @Override
    public void sendResponse(DebuggerResponse response) {
        DebuggerResponse.send(session, sessionId, JsonUtils.toJson(response));
    }

    /**
     * 停止当前指令
     */
    @Override
    public void stop(DebuggerRequest request) {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("线程休眠被打断", e);
        }
        handleReplayStop(request);
    }

    @Override
    public void destroy() {

        log.info("Destroy the debug session:[sessionId->{}]", this.sessionId);
        this.running = false;
        if (null != this.future) {
            this.future.cancel(false);
        }
        // handle_exit会关闭与机器人连接，所以多加一个条件
        if (this.deviceConnection != null && this.deviceConnection.getDeviceDriver() != null) {
            try {
                SpringUtils.getBean(DeviceConnectionService.class).closeDeviceConnection(deviceId);
            } catch (Exception e) {
                log.error("连接关闭异常", e);
            }
        }
        //等待引擎与机器人关闭后才让调试线程跑完
        requestQueue.clear();
        DebuggerRequest closeRequest = DebuggerRequest.newRequest()
                .cmd(DebugerConst.CommandConst.CMD_DESTROY)
                .sessionId(sessionId);
        requestQueue.add(closeRequest);
        this.listener = null;
        ScriptResolutionService bean = SpringUtils.getBean(ScriptResolutionService.class);
        if (null != bean) {
            bean.removeScriptExecutor(this.sessionId);
        }
        log.info("Session destroyed.");
    }

    @Override
    public void setFuture(Future<?> future) {
        this.future = future;
    }

    /**
     * 断开重新连接
     *
     * @param deviceToken
     * @param session
     */
    @Override
    public void refresh(String deviceToken, Session session) {
        getLock().lock();
        try{
            this.deviceToken = deviceToken;
            this.session = session;
        }finally {
            getLock().unlock();
        }
    }

    /**
     * session的锁
     * @return
     */
    @Override
    public Lock getLock(){
        return this.lock;
    }

    @Override
    public void run() {
        this.thread = Thread.currentThread();
        thread.setName(String.format(DEBUG_THREAD_NAME_TEMPLATE, session.getId()));
        log.info("Debug request process thread started.");
        while (running) {
            log.debug("Waiting for the next request ...");
            try {
                DebuggerRequest request = requestQueue.take();
                log.debug("Take a request from queue to handle ...");
                handleRequest(request);
                Thread.sleep(500L);
            } catch (Exception e) {
                log.warn("Error when handling request", e);
            }
        }
        log.info("DebugThread exit....");
    }


    private void handleRequest(DebuggerRequest request) {
        log.debug("Begin to handle the request:{}", request);
        String cmd = request.getCmd();
        if (DebugerConst.CommandConst.CMD_DEVICE_ENTER.equalsIgnoreCase(cmd)) { //连接设备处理
            handleDeviceEnter(request);
        } else if (DebugerConst.CommandConst.CMD_DEVICE_EXIT.equalsIgnoreCase(cmd)) {//设备退出处理
            handleDeviceExit(request);
        } else if (DebugerConst.CommandConst.CMD_DEVICE_INIT.equalsIgnoreCase(cmd)) {//应用初始化处理
            handleDeviceInit(request);
        } else if (DebugerConst.CommandConst.CMD_REPLAY_START.equalsIgnoreCase(cmd)) {//回放指令处理
            handleReplayStart(request);
        } else if (DebugerConst.CommandConst.CMD_SCREEN_SHOT.equalsIgnoreCase(cmd)) {  //截图
            handleScreenShot(request);
        } else if (DebugerConst.CommandConst.CMD_DETECT_EXECUTE.equalsIgnoreCase(cmd)) { //隐式回放
            handleDetectExecute(request);
        } else if (DebugerConst.CommandConst.CMD_DESTROY.equalsIgnoreCase(cmd)) {
            log.debug("等待socket关闭...");
        } else {
            log.warn("无法识别的请求指令:{}", request);
            doOnceResponse(request, false, String.format("无法识别的请求指令:%s", JsonUtils.toJson(request)));
        }
    }

    /**
     * 隐式回放
     *
     * @param request
     */
    private void handleDetectExecute(DebuggerRequest request) {
        Map<String, Object> executeData = request.getData();
        ScriptStep step = null;
        try {
            step = JSON.parseObject(JSON.toJSONString(executeData.get("step")), ScriptStep.class);
        } catch (Exception e) {
            log.error("脚本步骤解析出错", e);
            doOnceResponse(request, false, "操作步骤解析失败");
            return;
        }
        if (null == deviceConnection && !DebugService.TYPE_INTERFACE.equalsIgnoreCase(sessionType)) {
            ScriptExecutor scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).getScriptExecutor(sessionId);
            reConnectDevice(scriptExecutor);
        }
        try {
            Script script = new Script();
            ScriptStep[] steps = new ScriptStep[1];
            steps[0] = step;
            script.setCommands(steps);
            Map<String, List<ScriptResource>> resourceMap = new HashMap<>();
            script.setResources(resourceMap);
            ScriptRuntimeExecutor executor = new ScriptRuntimeExecutor(request.getRequestId(), "", "", script);
            executor.init(script);
            DeviceDriver deviceDriver = null;
            if (this.deviceConnection != null) {
                deviceDriver = this.deviceConnection.getDeviceDriver();
            }
            executor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_DRIVER, deviceDriver);
            executor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_CONN, this.deviceConnection);
            ScriptExecuteResult ret = new ScriptExecuteResult();
            executor.runScript(script, ret);
        } catch (Exception e) {
            log.error("执行步骤失败", e);
            if (e instanceof ExecuteException) {
                doOnceResponse(request, false, e.getMessage());
            } else {
                doOnceResponse(request, false, "操作执行失败");
            }
            return;
        }
        doOnceResponse(request, true, "操作成功");
    }


    /**
     * 截图
     *
     * @param request
     */
    private void handleScreenShot(DebuggerRequest request) {
        if (DebugService.TYPE_INTERFACE.equalsIgnoreCase(sessionType)) {
            doOnceResponse(request, false, "接口调试无需截图");
            return;
        }
        if (this.deviceConnection == null && !DebugService.TYPE_INTERFACE.equalsIgnoreCase(sessionType)) {
            ScriptExecutor scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).getScriptExecutor(sessionId);
            reConnectDevice(scriptExecutor);
        }
        try {
            Map<String, Object> initData = request.getData();
            log.info("initData:{}", JSON.toJSONString(initData));
            String type = (String) initData.get("type");
            if ("image".equals(type)) {
                Object params = initData.get("params");
                String s = JsonUtils.toJson(params);
                Map map = JsonUtils.fromJsonString(s, Map.class);
                map.put("token", request.getUserToken());
                String snapshot = null;
                if (deviceConnection != null) {
                    snapshot = deviceConnection.snapshot(map);
                }
                if (StringUtils.isNotBlank(snapshot)) {
                    DebuggerResponse response = DebuggerResponse.newResponse().cmd(DebugerConst.ReplyConst.KEY_CMD_REPLY).sessionId(request.getSessionId()).requestId(request.getRequestId()).success(true).finish(true).msg("截图成功").withData(DebugerConst.ReplyConst.KEY_RESULT, snapshot);
                    sendResponse(response);
                } else {
                    doOnceResponse(request, false, "截图失败，请稍后再试");
                }
            } else {
                doOnceResponse(request, false, "此操作不需要截图");
            }
        } catch (Exception e) {
            log.warn("截图失败", e);
            doOnceResponse(request, false, "截图失败，请稍后再试");
        }
    }

    /**
     * 关闭设备逻辑处理
     *
     * @param request
     */
    private void handleDeviceExit(DebuggerRequest request) {
        log.debug("Begin to handle device exit");
        // 统一到destroy方法进行关闭
        doOnceResponse(request, true, "正在退出设备");
    }

    /**
     * 连接设备逻辑处理
     *
     * @param request
     */
    private void handleDeviceEnter(DebuggerRequest request) {
        log.debug("Begin to handle device enter");
        if (StringUtils.isBlank(this.sessionId)) {
            this.sessionId = request.getSessionId();
        }
        //创建脚本执行器
        ScriptExecutor scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).getScriptExecutor(sessionId);
        if (null == scriptExecutor) {
            Map<String, Object> debugInfo = new HashMap<>();
            debugInfo.put("sessionId",sessionId);
            debugInfo.put("request",request);
            debugInfo.put("projectId",request.getProjectId());
            debugInfo.put("envId",StringUtils.isBlank(request.getEnvId()) ? "": request.getEnvId());
            //这里没有脚本，回放的时候再将脚本数据放进去
            scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).createDebugScriptRuntime(debugInfo,null);
            log.debug("脚本执行器新建成功");
            log.debug("当前执行器的项目id为{}", scriptExecutor.getProjectId());
        }
        scriptExecutor.setContextVariable(IScriptRuntimeContext.IS_DEBUG,true); //调试
        String deviceToken = (String) request.getDataValue(DebugerConst.ReqConst.KEY_TOKEN);
        if (StringUtils.isNotBlank(deviceToken) && !DebugService.TYPE_INTERFACE.equalsIgnoreCase(sessionType)) {
            try {
                DeviceConnection connection = SpringUtils.getBean(DeviceConnectionService.class).createDeviceConnection(deviceToken);
                this.deviceId = connection.getDeviceId();
                if (this.deviceConnection != null) {
                    this.deviceConnection.close();
                }
                this.deviceConnection = connection;
                scriptExecutor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_DRIVER,connection.getDeviceDriver());
                scriptExecutor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_CONN,this.deviceConnection);
                doOnceResponse(request, true, "设备连接成功");
                log.info("设备连接成功  ----> sessionId【{}】 设备token【{}】", request.getSessionId(), deviceToken);
            } catch (Exception e) {
                doOnceResponse(request, false, String.format("设备连接失败,原因:%s", e.getLocalizedMessage()));
                log.warn("连接设备失败", e);
                log.info("设备连接失败  ----> sessionId【{}】 设备token【{}】", request.getSessionId(), deviceToken);
            }
        } else {
            doOnceResponse(request, true, String.format("设备连接失败,原因:%s", "无效的设备token,设备token不能为空"));
            log.error("设备连接失败,原因:{}", "无效的设备token,设备token不能为空");
        }

    }

    /**
     * 设备初始化逻辑处理
     *
     * @param request
     */
    private void handleDeviceInit(DebuggerRequest request) {
        log.debug("Begin to handle device init");
        if (DebugService.TYPE_INTERFACE.equalsIgnoreCase(sessionType)) {
            doOnceResponse(request, true, "初始化成功");
            log.info("初始化成功 --> ----> sessionId【{}】, sessionType【{}】", sessionId, sessionType);
            return;
        }
        if (this.deviceConnection == null && !DebugService.TYPE_INTERFACE.equalsIgnoreCase(sessionType)) {
            doOnceResponse(request, false, String.format(DEVICE_INIT_FAIL_MSG, "设备连接不存在"));
            log.error("初始化失败,原因：{}", "设备连接不存在");
            return;
        }
        try {
            Map<String, Object> initData = request.getData();
            initData.put("debug", true);
            if (DebugService.TYPE_MOBILE.equalsIgnoreCase(sessionType)) {
                ScriptExecutor scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).getScriptExecutor(request.getSessionId());
                if (null != scriptExecutor) {
                    scriptExecutor.setContextVariable(IScriptRuntimeContext.APP_VERSION,initData.get("appVersion"));
                    log.debug("已经存放app版本信息：{}", initData.get("appVersion"));
                }
            }
            if (deviceConnection != null) {
                deviceConnection.initConfig(initData);
            }
            doOnceResponse(request, true, "初始化成功");
            log.info("初始化成功 --> ----> sessionId【{}】, sessionType【{}】", sessionId, sessionType);
        } catch (Exception e) {
            log.warn("设备初始化失败", e);
            doOnceResponse(request, false, String.format(DEVICE_INIT_FAIL_MSG, e.getLocalizedMessage()));
            throw new ExecuteException("设备初始化失败", e);
        }
    }

    /**
     * 脚本回放逻辑处理
     *
     * @param request
     */
    private void handleReplayStart(DebuggerRequest request) {
        log.debug("Begin to handle replay start");
        String sessionId = request.getSessionId();
        String requestId = request.getRequestId();
        String type = (String) request.getDataValue(DebugerConst.ReqConst.KEY_REPLAY_TYPE);
        Object scriptData = request.getDataValue(DebugerConst.ReqConst.KEY_REPLAY_SCRIPT_DATA);
        Script script = null;
        if (scriptData != null) {//检查并
            try {
                if (scriptData instanceof LinkedHashMap) {
                    script = JSON.parseObject(JSON.toJSONString(scriptData)).toJavaObject(Script.class);
                } else {
                    script = SpringUtils.getBean(ScriptResolutionService.class).parse((String) scriptData);
                }
            } catch (Throwable t) {
                doOnceResponse(request, false, "回放失败，脚本数据解析异常 " + t.getMessage());
                return;
            }
        }
        if (null == script) {
            doOnceResponse(request, false, "回放失败，无效的脚本数据");
            return;
        }
        // 创建脚本执行器
        ScriptExecutor scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).getScriptExecutor(sessionId);
        log.debug("handleReplayStart的projectId,{}",request.getProjectId());
        if (null == scriptExecutor) {
            Map<String, Object> debugInfo = new HashMap<>();
            debugInfo.put("sessionId", sessionId);
            debugInfo.put("request", request);
            debugInfo.put("projectId", request.getProjectId());
            debugInfo.put("envId", StringUtils.isBlank(request.getEnvId()) ? "" : request.getEnvId());
            scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).createDebugScriptRuntime(debugInfo, script);
            log.debug("回放时脚本执行器新建成功");
            if (!DebugService.TYPE_INTERFACE.equalsIgnoreCase(sessionType)) {   // 非接口调试需要
                if (null == deviceConnection) {
                    reConnectDevice(scriptExecutor);
                }
                scriptExecutor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_DRIVER, this.deviceConnection.getDeviceDriver());
                scriptExecutor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_CONN, this.deviceConnection);
            }
        }else { //设置脚本数据
            scriptExecutor.setScript(script);
            log.debug("当前session[{}]执行器为{}", sessionId, scriptExecutor);
            log.debug("当前执行器的项目id为{}", scriptExecutor.getProjectId());
            if (scriptExecutor.getProjectId() == null){
                scriptExecutor.setProjectId(request.getProjectId());
            }
        }
        scriptExecutor.setRuntimeListener(this.listener);
        // 设置请求标识
        scriptExecutor.setRequestId(request.getRequestId());
        // 设置项目id
        scriptExecutor.setProjectId(request.getProjectId());
        ScriptExecuteResult ret = new ScriptExecuteResult();
        try {
            scriptExecutor.reset(script);
            scriptExecutor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_REQUEST, request);
            if (DebugerConst.ReplayType.TYPE_ALL.equalsIgnoreCase(type)) {
                // 回放全部
                //scriptExecutor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_REQUEST, request);
                // 需要重置参数数据
                scriptExecutor.initData(request.getData());
                scriptExecutor.runScript(script, ret);
            } else if (DebugerConst.ReplayType.TYPE_FROM.equalsIgnoreCase(type)) { // 从当前步骤回放
                scriptExecutor.initData(request.getData());
                String stepId = (String) request.getDataValue(DebugerConst.ReqConst.KEY_REPLAY_FROM_STEP_ID);
                ret = scriptExecutor.runStep(script, stepId, type);
            } else if (DebugerConst.ReplayType.TYPE_STEP.equalsIgnoreCase(type)) { // 单步回放
                String stepId = (String) request.getDataValue(DebugerConst.ReqConst.KEY_REPLAY_FROM_STEP_ID);
                ret = scriptExecutor.runStep(script, stepId, true, type);
            } else if (DebugerConst.ReplayType.TYPE_RESTART.equalsIgnoreCase(type)) {  // 重启浏览器并回放
                // 重启浏览器
                try {
                    restart(request, script);
                }catch (Exception e){
                    this.listener.doLog(scriptExecutor, LogLevel.ERROR.name(), e.getMessage());
                    throw new ExecuteException(e.getMessage());
                }
                scriptExecutor.initData(request.getData());
                scriptExecutor.runScript(script, ret);
            } else {
                // 未知指令，返回
                doOnceResponse(request, false, String.format("指令：【%s】是系统未知指令", type));
            }
            DebuggerResponse response = buildResponse(request, true, true, "回放结束");
            sendResponse(response);
        } catch (Exception e) {
            // 回放失败
            log.error("回放异常",e);
            if(thread.isInterrupted()){
                Thread.interrupted();
            }
            sendResponse(buildResponse(request, true, false, e.getMessage()));
            throw e;
        } finally {
            // 处理临时资源文件
            scriptExecutor.clearResource();
        }
    }

    private void reConnectDevice(ScriptExecutor scriptExecutor) {
        try {
            DeviceConnection connection = SpringUtils.getBean(DeviceConnectionService.class).createDeviceConnection(this.deviceToken);
            this.deviceId = connection.getDeviceId();
            if (scriptExecutor != null) {//如果不为空走切换设备驱动模式
                scriptExecutor.setContextVariable(IScriptRuntimeContext.KEY_CURRENT_DRIVER, connection.getDeviceDriver());
            }
            this.deviceConnection = connection;
            log.warn("设备驱动重新连接成功。。。。。。。。。");
        } catch (Exception e) {
            log.error("",e);
        }
    }

    private void restart(DebuggerRequest request, Script script) {
        TestTarget[] testTargets = script.getTestTargets();
        if (testTargets != null && testTargets.length > 0) {
            HashMap<String, Object> initMap = new HashMap<>();
            TestTarget testTarget = testTargets[0];
            if (testTarget.getTargetType() != null && "web".equalsIgnoreCase(testTarget.getTargetType())) {    // 后续加上枚举
                initMap.put(PCDeviceConnection.BROWSER_TYPE, testTarget.getTarget().get(PCDeviceConnection.BROWSER_TYPE));

                initMap.put(PCDeviceConnection.PROJECT_ID, testTarget.getTarget().get(PCDeviceConnection.PROJECT_ID));
                initMap.put(PCDeviceConnection.ENV_ID, testTarget.getTarget().get(PCDeviceConnection.ENV_ID));
                initMap.put(PCDeviceConnection.SYS_NAME, testTarget.getTarget().get(PCDeviceConnection.SYS_NAME));

            } else if (testTarget.getTargetType() != null && "mobile".equalsIgnoreCase(testTarget.getTargetType())) {
                Map<String, String> target = testTarget.getTarget();
                boolean isReInstall = Boolean.parseBoolean(target.get(MobileDeviceConnection.IS_REINSTALL));
                boolean isCleanData = Boolean.parseBoolean(target.get(MobileDeviceConnection.IS_CLEAN_DATA));
                boolean isAppRestart = Boolean.parseBoolean(target.get(MobileDeviceConnection.IS_APP_RESTART));
                if (isReInstall) {  //卸载安装
                    initMap.put("appId", target.get("appId"));
                    initMap.put("appVersion", target.get("appVersion"));
                    initMap.put("forceReInstall", isReInstall);
                    initMap.put("forceCleanData", isCleanData);
                    initMap.put("type", "2");
                } else {
                    if (isCleanData && !isAppRestart) { //只清除数据
                        initMap.put("type", "1");
                    } else if (isCleanData && isAppRestart) {  //清除数据+重启应用
                        initMap.put("type", "3");
                    } else {  //只重启应用
                        initMap.put("type", "0");
                    }
                }
                initMap.put(MobileDeviceConnection.PACKAGE_NAME, target.get(MobileDeviceConnection.PACKAGE_NAME));
                initMap.put(MobileDeviceConnection.APP_NAME, target.get(MobileDeviceConnection.APP_NAME));
                initMap.put(MobileDeviceConnection.IS_RECORD_DEVICE_PER, true);
            }
            this.deviceConnection.restart(initMap);
        } else {
            DebuggerResponse res = buildResponse(request, false, true, "缺少重启参数，不进行重启，直接回放");
            sendResponse(res);
        }
    }

    private void setExecutorVars(ScriptExecutor scriptExecutor, Script script) {
        Variable[] variables = script.getVariables();

        for (Variable variable : variables) {
            scriptExecutor.setVariable(variable.getName(), variable.getValue());
        }
    }

    private void handleReplayStop(DebuggerRequest request) {
        log.debug("Begin to handle replay stop");
        ScriptExecutor scriptExecutor = SpringUtils.getBean(ScriptResolutionService.class).getScriptExecutor(sessionId);
        scriptExecutor.setIgnoreError(false);
        thread.interrupt();
        if (null != deviceConnection) {
            deviceConnection.stopPlay(new HashMap<>());
        }
        doOnceResponse(request, true, "停止回放成功");
    }

    private void doResponse(DebuggerRequest request, boolean finish, boolean success, String msg) {
        DebuggerResponse response = buildResponse(request, finish, success, msg);
        sendResponse(response);
    }

    private void doOnceResponse(DebuggerRequest request, boolean success, String msg) {
        doResponse(request, true, success, msg);
    }

    private void doMoreResponse(DebuggerRequest request, boolean success, String msg) {
        doResponse(request, false, success, msg);
    }

    private void endMoreResponse(DebuggerRequest request, boolean success, String msg) {
        doResponse(request, true, success, msg);
    }

    private DebuggerResponse buildResponse(DebuggerRequest request, boolean finish, boolean success, String msg) {
        return DebuggerResponse.newResponse()
                .sessionId(request.getSessionId())
                .requestId(request.getRequestId())
                .finish(finish)
                .success(success)
                .msg(msg);
    }
}
