/*
 * Copyright (c) 京北方信息技术股份有限公司 Corporation 2022 . All rights reserved.
 *
 */
package net.northking.cctp.scriptcase.api.atuScript.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import com.hzbank.testteam.autotest.dependencies.authDependency.utils.RequestUtil;
import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.exception.InvalidException;
import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.vo.ApiScriptOptionVO;
import com.hzbank.testteam.autotest.dependencies.monsterDependency.dto.UserDTO;
import net.northking.cctp.common.cache.EntityNameCache;
import net.northking.cctp.common.cache.EntityNameCatalog;
import net.northking.cctp.common.db.*;
import net.northking.cctp.common.db.annotation.DatabaseReadOnly;
import net.northking.cctp.common.db.excel.AbstractExcelService;
import net.northking.cctp.common.db.excel.ExcelHeader;
import net.northking.cctp.common.dto.AdvancedQueryOptions;
import net.northking.cctp.common.dto.AssociatedFilesDto;
import net.northking.cctp.common.dto.CpLogAddDto;
import net.northking.cctp.common.dto.UserOptions;
import net.northking.cctp.common.enums.FileBusinessTypeEnum;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.common.feign.MonsterCommonFeignClient;
import net.northking.cctp.common.feign.MonsterLogServer;
import net.northking.cctp.common.http.QueryByPage;
import net.northking.cctp.common.http.ResultWrapper;
import net.northking.cctp.common.s3.FileDownloadException;
import net.northking.cctp.common.s3.FileUploadException;
import net.northking.cctp.common.s3.NKFile;
import net.northking.cctp.common.s3.SimpleStorageService;
import net.northking.cctp.common.security.authentication.NKSecurityContext;
import net.northking.cctp.common.util.DateUtil;
import net.northking.cctp.common.util.UUIDUtil;
import net.northking.cctp.scriptcase.api.caseDataSet.service.AtuCaseDataSetApiService;
import net.northking.cctp.scriptcase.api.component.service.AtuBusinessNoApiService;
import net.northking.cctp.scriptcase.api.component.service.MdBusComponentInfoApiService;
import net.northking.cctp.scriptcase.api.scenescript.service.coordinate.SceneCoordinatorService;
import net.northking.cctp.scriptcase.bus.LogRabbitMQPublisher;
import net.northking.cctp.scriptcase.bus.PlanRabbitMQPublisher;
import net.northking.cctp.scriptcase.constants.RedisConstant;
import net.northking.cctp.scriptcase.constants.ScriptConstant;
import net.northking.cctp.scriptcase.db.entity.*;
import net.northking.cctp.scriptcase.db.service.*;
import net.northking.cctp.scriptcase.dto.atuScript.UserQueryDto;
import net.northking.cctp.scriptcase.dto.atuScript.atuScriptInfo.*;
import net.northking.cctp.scriptcase.dto.atuScript.atuScriptVersion.AtuScriptVersionQueryDto;
import net.northking.cctp.scriptcase.dto.atuScript.atuScriptVersion.AtuScriptVersionResultDto;
import net.northking.cctp.scriptcase.dto.atuscriptrecord.AtuScriptInputSetAddTmpDto;
import net.northking.cctp.scriptcase.dto.atuscriptrecord.ScriptInputTableDto;
import net.northking.cctp.scriptcase.dto.caseDataSet.AtuCaseScriptResultDto;
import net.northking.cctp.scriptcase.dto.caseDataSet.SetTreeDto;
import net.northking.cctp.scriptcase.dto.caseset.AppList;
import net.northking.cctp.scriptcase.dto.inputSet.AtuInputSetResultDto;
import net.northking.cctp.scriptcase.enums.ErrorMessage;
import net.northking.cctp.scriptcase.enums.ScriptCaseAppError;
import net.northking.cctp.scriptcase.feign.*;
import net.northking.cctp.scriptcase.tools.Assert;
import net.northking.cctp.scriptcase.tools.DataMgrUtils;
import net.northking.cctp.scriptcase.tools.DownloadFileUtils;
import net.northking.cctp.scriptcase.tools.MinioPathUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.*;
import java.util.stream.Collectors;

import static net.northking.cctp.scriptcase.constants.ScriptConstant.*;

/**
 * 脚本信息表服务实现类
 *
 * @author maven-cctp-plugin
 * @since 1.0
 */

@Service
@ConditionalOnMissingBean(name = "AtuScriptInfoApiServiceImpl")
public class AtuScriptInfoApiServiceImpl extends AbstractExcelService<AtuScriptInfo> implements AtuScriptInfoApiService
{
  /**
   * 日志
   */
  private final static Logger logger = LoggerFactory.getLogger(AtuScriptInfoApiServiceImpl.class);

  @Autowired
  private AtuScriptVersionService atuScriptVersionService;
  @Autowired
  private AtuScriptInfoService atuScriptInfoService;
  @Autowired
  private AtuScriptGroupService atuScriptGroupService;
  @Autowired
  private AppService appService;
  @Autowired
  private SimpleStorageService simpleStorageService;
  @Autowired
  private EntityNameCache entityNameCache;
  @Autowired
  private MinioPathUtils pathUtil;
  @Autowired
  private PlatformFeignClient platformFeignClient;
  @Autowired
  private LogRabbitMQPublisher logPublisher;
  @Autowired
  private AtuSceneNodeInfoService atuSceneNodeInfoService;
  @Autowired
  private AtuSceneInfoService atuSceneInfoService;

  @Autowired
  private SceneCoordinatorService sceneCoordinatorService;

  @Autowired
  private AtuScriptInputSetVersionService atuScriptInputSetVersionService;

  @Autowired
  private AtuScriptInputSetService atuScriptInputSetService;

  @Autowired
  private AtuInputSetService atuInputSetService;

  @Autowired
  private ProjectFeignClient projectFeignClient;

  @Autowired
  private ExecutePlanFeignClient executePlanFeignClient;

  @Autowired
  private AtuCaseDataSetApiService atuCaseDataSetService;

  @Autowired
  private AtuCaseDataSetService caseDataSetService;

  @Autowired
  private RedisTemplate redisTemplate;

  @Autowired
  private RedisLockRegistry redisLockRegistry;

  @Autowired
  private AtuBusinessNoApiService atuBusinessNoApiService;

  @Autowired
  private PlanRabbitMQPublisher planRabbitMQPublisher;

  @Autowired
  private AtuScriptTagService atuScriptTagService;

  @Autowired
  private MdBusComponentInfoApiService busComponentInfoApiService;

  @Autowired
  private DownloadFileUtils downloadFileUtils;

  @Autowired
  private DataMgrUtils dataMgrUtils;

  @Autowired
  MonsterCommonFeignClient monsterCommonFeignClient;
  @Autowired
  AttachmentFeignClient attachmentFeignClient;

  @Value("${nk.config.flush_redis:false}")
  private boolean flush_redis;
  @Override
  public BasicService<AtuScriptInfo> getService()
  {
    return this.atuScriptInfoService;
  }

  @Override
  public ExcelHeader[] excelHeaders()
  {
    ExcelHeader id = new ExcelHeader("脚本ID", "id", String.class);
    ExcelHeader groupId = new ExcelHeader("脚本目录ID", "groupId", String.class);
    ExcelHeader scriptName = new ExcelHeader("脚本名称", "scriptName", String.class);
    ExcelHeader scriptType = new ExcelHeader("脚本类型", "scriptType", String.class);
    ExcelHeader latestVersionId = new ExcelHeader("最新版本ID", "latestVersionId", Integer.class);
    ExcelHeader scriptUrl = new ExcelHeader("脚本地址", "scriptUrl", String.class);
    ExcelHeader dataUrl = new ExcelHeader("脚本快照数据地址", "dataUrl", String.class);
    ExcelHeader isDeleted = new ExcelHeader("是否删除", "isDeleted", String.class);
    ExcelHeader projectId = new ExcelHeader("系统ID", "projectId", String.class);
    ExcelHeader tenantId = new ExcelHeader("租户号", "tenantId", String.class);
    ExcelHeader createdBy = new ExcelHeader("创建人", "createdBy", String.class);
    ExcelHeader createdTime = new ExcelHeader("创建时间", "createdTime", Date.class);
    ExcelHeader updatedBy = new ExcelHeader("更新人", "updatedBy", String.class);
    ExcelHeader updatedTime = new ExcelHeader("更新时间", "updatedTime", Date.class);
    return new ExcelHeader[]{};
  }

  /**
   * Excel导入，入库之前的处理
   * @param records 从Excel读取到的记录
   * @return 待入库的记录
   */
  @Override
  protected List<AtuScriptInfo> beforeInsertBatch(List<AtuScriptInfo> records)
  {
    for (AtuScriptInfo record : records)
    {
      record.setId(UUIDUtil.create32UUID());
    }
    return records;
  }

  /**
   * 写入Excel之前的处理<br>
   * 数据的特殊处理在此处加工处理
   *
   * @param record 来自数据库记录
   * @return 待写入Excel的记录
   */
  @Override
  protected AtuScriptInfo beforeWriteExcel(AtuScriptInfo record)
  {
    return record;
  }


  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public AtuScriptInfo saveScript(AtuScriptInfoAddDto addDto) {
    //保存已有脚本
    if (StringUtils.hasText(addDto.getId())) {
      String scriptJsonStr = addDto.getScriptJsonStr();//脚本的json文件
      Assert.hasText(scriptJsonStr, ScriptConstant.SCRIPT_IS_NULL);
      AtuScriptInfo script = atuScriptInfoService.findByPrimaryKey(addDto.getId());
      if (null == script || ScriptConstant.STR_ONE.equals(script.getIsDeleted())) {
        throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_IS_DEL);
      }
      //从脚本字符串转换成脚本对象
      JSONObject scriptObject = null;
      try {
        scriptObject = JSON.parseObject(scriptJsonStr, JSONObject.class);
      } catch (Exception e) {
        logger.error("",e);
        throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_FILE_JSON_ERR);
      }
      String scriptType = script.getScriptType();
      FileBusinessTypeEnum businessCode = null;
      if (scriptType.equals(SCRIPT_TYPE_ANDROID) || scriptType.equals(SCRIPT_TYPE_IOS)) {
        businessCode = FileBusinessTypeEnum.MOBILE_RECORD_SCREENSHOT;
      } else if (scriptType.equals(SCRIPT_TYPE_BS) || scriptType.equals(SCRIPT_TYPE_CS)) {
        businessCode = FileBusinessTypeEnum.PC_RECORD_SCREENSHOT;
      }
      long start = System.currentTimeMillis();
      Map<String, String> oldPathAndNewPathMap = new HashMap<>();
      String oldScriptUrl = script.getScriptUrl();
      if (StringUtils.hasText(oldScriptUrl)) {
        logger.info("开始下载旧文件，获取图片信息：{}",start);
        JSONObject oldJsonObject = downloadScriptFile(oldScriptUrl);
        getIamgeUrlByJsonArray(addDto.getId(), oldJsonObject.get("commands"), oldPathAndNewPathMap, false, businessCode);
        long end1 = System.currentTimeMillis();
        logger.info("下载旧文件，获取图片信息结束：{},耗时：{}",end1,end1 - start);
        logger.info("旧文件图片信息：{}",JSON.toJSONString(oldPathAndNewPathMap.keySet()));
      }
      // 截图文件，全删全增
      long end2 = System.currentTimeMillis();
      logger.info("开始获取当前脚本图片信息并拷贝：{}",end2);
      getIamgeUrlByJsonArray(addDto.getId(), scriptObject.get("commands"), oldPathAndNewPathMap, true, businessCode);
      long end3 = System.currentTimeMillis();
      logger.info("获取当前脚本图片信息并拷贝结束：{},耗时：{}",end3, end3 - end2);
      logger.info("全部文件图片信息：{}",JSON.toJSONString(oldPathAndNewPathMap.keySet()));
      List<String> fileIds = oldPathAndNewPathMap.keySet().stream().map(path -> "/"+MinioPathUtils.idToPath(path)[1]).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(fileIds)) {
        AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
        associatedFilesDto.setObjId("-1");
        associatedFilesDto.setFileIds(fileIds);
        ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
        if (wrapper == null || !wrapper.isSuccess()) {
          throw new InvalidException("文件关联异常");
        }
      }

      //保存脚本文件
      script.setUpdatedTime(new Date());
      script.setUpdatedBy(NKSecurityContext.getUserId());
      //生成新的脚本文件并上传覆盖原来的脚本文件
      String path = generateScriptFileAndUpload(scriptObject, addDto.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      //删除服务器上原文件
      if (StringUtils.hasText(script.getScriptUrl())) {
        deleteFile(script.getScriptUrl());
      }
      script.setScriptUrl(path);
      atuScriptInfoService.updateByPrimaryKey(script);  //更新脚本信息
      return atuScriptInfoService.findByPrimaryKey(addDto.getId());
      //====================================
    }else { //新建脚本
      String scriptName = addDto.getScriptName();
      //检查同名脚本是否存在
      Integer num = atuScriptInfoService.countScriptByScriptName(addDto.getScriptName(), addDto.getProjectId());
      if (null != num && num > 0) {
        throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_PRO_HAS_EXIST,addDto.getScriptName());
      }
      //检查脚本目录是否存在
      if (StringUtils.hasText(addDto.getGroupId())) {
        checkScriptGroup(addDto.getGroupId());
      }
      //生成脚本
      String uuid = UUIDUtil.create32UUID();
      addDto.setId(uuid);
      AtuScriptInfo script = createAtuScript(addDto);
      //补充结点相关脚本信息
      JSONObject scriptTemplate = null;
      String scriptStr = addDto.getScriptJsonStr();
      if (StringUtils.isEmpty(scriptStr)) {
        //虚拟脚本文件数据
        scriptTemplate = new JSONObject();
        scriptTemplate.put(ScriptConstant.ENGINE_VERSION,ScriptConstant.ENGINE_DEFAULT_VERSION);
        scriptTemplate.put(ScriptConstant.VARIABLES, new JSONObject());
        scriptTemplate.put(ScriptConstant.RUNTIME, new JSONObject());

        List<CommandDetailDto> comands = new ArrayList<>();
        for(int i = 0; i<3; i++) {
          CommandDetailDto commandDetailDto = new CommandDetailDto();
          commandDetailDto.setId(ScriptConstant.DETAIL_ID + i);
          commandDetailDto.setTitle(ScriptConstant.DETAIL_TITLE + i);
          commandDetailDto.setImgUri(ScriptConstant.DETAIL_IMG);
          commandDetailDto.setComponentLib(ScriptConstant.DETAIL_LIB);
          commandDetailDto.setCommand(ScriptConstant.DETAIL_COMMAND);
          List<TargetDto> targetDtos = new ArrayList<>();
          TargetDto targetDto = new TargetDto();
          targetDto.setUsing(ScriptConstant.TARGET_USING);
          targetDto.setValue(ScriptConstant.TARGET_VALUE);
          targetDto.setStrategy(ScriptConstant.STR_TWO);
          targetDtos.add(targetDto);
          commandDetailDto.setTargets(targetDtos);
          comands.add(commandDetailDto);
        }
        scriptTemplate.put(ScriptConstant.COMMANDS, comands);

        JSONObject globalSettings = new JSONObject();
        globalSettings.put(ScriptConstant.TIMEOUT, 30);
        scriptTemplate.put(ScriptConstant.GLOBAL_SET, globalSettings);

        JSONObject scriptInfo = new JSONObject();
        scriptInfo.put(ScriptConstant.NAME,script.getScriptName());
        scriptInfo.put(ScriptConstant.CREATED_BY,entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, script.getCreatedBy()));
        scriptTemplate.put(ScriptConstant.SCRIPT_INFO, scriptInfo);

        JSONObject resources = new JSONObject();
        resources.put(ScriptConstant.SCRIPT_DEP, new ArrayList<>());
        resources.put(ScriptConstant.COM_DEP, new ArrayList<>());
        scriptTemplate.put(ScriptConstant.RESOURCE, new JSONObject());

        JSONObject testTarget = new JSONObject();
        testTarget.put(ScriptConstant.TARGET_TYPE, ScriptConstant.TYPE_MOB);
        JSONObject target = new JSONObject();
        target.put(ScriptConstant.APP_PACKAGE, addDto.getPackageName());
        testTarget.put(ScriptConstant.TARGET,target);
        scriptTemplate.put(ScriptConstant.TEST_TARGET, testTarget);
      } else {
        scriptTemplate = JSON.parseObject(scriptStr, JSONObject.class);
      }
      scriptTemplate.put(ScriptConstant.UUID, uuid);
      // 关联截图文件
      String scriptType = script.getScriptType();
      FileBusinessTypeEnum businessCode = null;
      if (scriptType.equals(SCRIPT_TYPE_ANDROID) || scriptType.equals(SCRIPT_TYPE_IOS)) {
        businessCode = FileBusinessTypeEnum.MOBILE_RECORD_SCREENSHOT;
      } else if (scriptType.equals(SCRIPT_TYPE_BS) || scriptType.equals(SCRIPT_TYPE_CS)) {
        businessCode = FileBusinessTypeEnum.PC_RECORD_SCREENSHOT;
      }
      Map<String, String> oldPathAndNewPathMap = new HashMap<>();
      getIamgeUrlByJsonArray(addDto.getId(), scriptTemplate.get("commands"), oldPathAndNewPathMap, false, businessCode);
      List<String> fileIds = oldPathAndNewPathMap.keySet().stream().map(path -> "/"+MinioPathUtils.idToPath(path)[1]).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(fileIds)) {
        AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
        associatedFilesDto.setObjId(uuid);
        associatedFilesDto.setFileIds(fileIds);
        ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
        if (wrapper == null || !wrapper.isSuccess()) {
          throw new InvalidException("文件关联异常");
        }
      }
      //存储脚本文件
      String path = generateScriptFileAndUpload(scriptTemplate, addDto.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      script.setScriptUrl(path);
      script.setPrincipalId(NKSecurityContext.getUserId());
      //补充脚本基本状态
      createdCodeAndInsertData(script);

      //保存输入项草稿数据
      if (null!=addDto.getAtuScriptInputSetAddTmpDtos()&&addDto.getAtuScriptInputSetAddTmpDtos().size()!=0) {
        saveScriptInputSetData(script, addDto.getAtuScriptInputSetAddTmpDtos());
      }else {
        //创建默认数据保存到输入项草稿表中
        List<AtuScriptInputSet> resultList = createdFileByInputSet(script.getId(), script.getProjectId(), scriptStr);
        if (resultList.size() > 0) {
          this.atuScriptInputSetService.insertByBatch(resultList);
        }
      }
      return script;
    }
  }

  public void getImageUrlByJSONObject(String objId, Object obj, Map<String, String> paths, boolean isCopy, FileBusinessTypeEnum businessCode) {
      for (Map.Entry<String, Object> entry : ((JSONObject) obj).entrySet()) {
        Object value = entry.getValue();
        if (value instanceof JSONObject) {
          getImageUrlByJSONObject(objId, value, paths, isCopy, businessCode);
        } else if (value instanceof JSONArray) {
          getIamgeUrlByJsonArray(objId, value, paths, isCopy, businessCode);
        } else {
          String oldPath = value.toString();
          if (oldPath.endsWith(".png") || oldPath.endsWith(".jpg")) {
            if (!paths.containsKey(oldPath)) {
              paths.put(oldPath, null);
            }
            if (isCopy) {
              if (paths.containsKey(oldPath) && paths.get(oldPath) != null) {
                entry.setValue(paths.get(oldPath));
              } else {
                String newPath = copyFile(oldPath, objId, businessCode);
                entry.setValue(newPath);
                paths.put(oldPath, newPath);
              }
            }
          }
        }
      }
  }

  @Override
  public void getIamgeUrlByJsonArray(String objId, Object obj, Map<String, String> paths, boolean isCopy, FileBusinessTypeEnum businessCode) {
    for (Object item : ((JSONArray) obj)) {
      if (item instanceof JSONObject) {
        getImageUrlByJSONObject(objId, item, paths, isCopy, businessCode);
      } else if (item instanceof JSONArray) {
        getIamgeUrlByJsonArray(objId, item, paths, isCopy, businessCode);
      }
    }
  }

  public String copyFile(String path, String objId, FileBusinessTypeEnum businessCode){
    String[] fileNames = MinioPathUtils.idToPath(path);
    String newPath = null;
    File dest = null;
    try {
      String tenant = fileNames[0];
      File file = simpleStorageService.downloadAsFile(tenant, "/" + fileNames[1]);
      String name = file.getName();
      name = name.substring(0, name.lastIndexOf("."));
      name += fileNames[1].substring(fileNames[1].lastIndexOf("."));
      dest = new File(file.getParent() + File.separator + name);
      file.renameTo(dest);
      NKFile upload = simpleStorageService.upload(tenant, dest, objId, businessCode);
      newPath = MinioPathUtils.pathToId(tenant, upload.getId());
    } catch (FileDownloadException | FileUploadException e) {
      logger.error("脚本截图copy异常", e);
      throw new InvalidException("脚本截图copy异常");
    } finally {
      if (dest != null) {
        dest.delete();
      }
    }
    return newPath;
  }
  private void saveScriptInputSetData(AtuScriptInfo script, List<AtuScriptInputSetAddTmpDto> atuScriptInputSetAddTmpDtos) {
    List<String> envIds = projectFeignClient.selectEnvIds(script.getProjectId());
    if (envIds.size()!=0){
      AtuScriptInputSet atuScriptInputSetAdd = null;
      List<String> fileIds = new ArrayList<>();
      for (AtuScriptInputSetAddTmpDto tmpDto:atuScriptInputSetAddTmpDtos){
        if (envIds.contains(tmpDto.getEnvId())){
          //数据插入
          atuScriptInputSetAdd = new AtuScriptInputSet();
          String uuid = UUIDUtil.create32UUID();
          atuScriptInputSetAdd.setId(uuid);
          atuScriptInputSetAdd.setEnvId(tmpDto.getEnvId());
          atuScriptInputSetAdd.setScriptId(script.getId());
          atuScriptInputSetAdd.setCreatedBy(NKSecurityContext.getUserId());
          atuScriptInputSetAdd.setCreatedTime(new Date());
          atuScriptInputSetAdd.setDataUrl(tmpDto.getPath());
          fileIds.add("/" + MinioPathUtils.idToPath(tmpDto.getPath())[1]);
          atuScriptInputSetService.insert(atuScriptInputSetAdd);
          //记录输入项内对应的输入项关联
          AtuInputSetResultDto resultDto = downloadFileUtils.downloadFile(tmpDto.getPath());
          dataMgrUtils.queryInputAndDataLink(resultDto.getTableContent(),tmpDto.getEnvId(),uuid,ScriptConstant.DATA_SET_LINK_BY_SCRIPT);
        }
      }
      if (!CollectionUtils.isEmpty(fileIds)) {
        AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
        associatedFilesDto.setObjId(script.getId());
        associatedFilesDto.setFileIds(fileIds);
        ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
        if (wrapper == null || !wrapper.isSuccess()) {
          throw new InvalidException("文件关联异常");
        }
      }
    }
  }

  @Override
  public AtuScriptInfo publishScript(AtuScriptInfoAddDto addDto) {
    logger.debug("开始处理脚本发布，id{}",addDto.getId());
    //保存已有脚本
    if (StringUtils.hasText(addDto.getId())) {
      String scriptJsonStr = addDto.getScriptJsonStr();//脚本的json文件
      Assert.hasText(scriptJsonStr, ScriptConstant.SCRIPT_IS_NULL);
      AtuScriptInfo script = atuScriptInfoService.findByPrimaryKey(addDto.getId());
      if (null == script || ScriptConstant.STR_ONE.equals(script.getIsDeleted())) {
        throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_IS_DEL);
      }
      //从脚本字符串转换成脚本对象
      JSONObject scriptObject = null;
      try {
        scriptObject = JSON.parseObject(scriptJsonStr, JSONObject.class);
      } catch (Exception e) {
        logger.error("",e);
        throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_FILE_JSON_ERR);
      }
      //保存脚本文件
      script.setUpdatedTime(new Date());
      script.setUpdatedBy(NKSecurityContext.getUserId());
      String scriptType = script.getScriptType();
      FileBusinessTypeEnum businessCode = null;
      if (scriptType.equals(SCRIPT_TYPE_ANDROID) || scriptType.equals(SCRIPT_TYPE_IOS)) {
        businessCode = FileBusinessTypeEnum.MOBILE_RECORD_SCREENSHOT;
      } else if (scriptType.equals(SCRIPT_TYPE_BS) || scriptType.equals(SCRIPT_TYPE_CS)) {
        businessCode = FileBusinessTypeEnum.PC_RECORD_SCREENSHOT;
      }
      long start = System.currentTimeMillis();
      Map<String, String> oldPathAndNewPathMap = new HashMap<>();
      String oldScriptUrl = script.getScriptUrl();
      if (StringUtils.hasText(oldScriptUrl)) {
        logger.info("开始下载旧文件，获取图片信息：{}",start);
        JSONObject oldJsonObject = downloadScriptFile(oldScriptUrl);
        getIamgeUrlByJsonArray(addDto.getId(), oldJsonObject.get("commands"), oldPathAndNewPathMap, false, businessCode);
        long end1 = System.currentTimeMillis();
        logger.info("下载旧文件，获取图片信息结束：{},耗时：{}",end1,end1 - start);
        logger.info("旧文件图片信息：{}",JSON.toJSONString(oldPathAndNewPathMap.keySet()));
      }
      // 截图文件，全删全增
      long end2 = System.currentTimeMillis();
      logger.info("开始获取当前脚本图片信息并拷贝：{}",end2);
      getIamgeUrlByJsonArray(addDto.getId(), scriptObject.get("commands"), oldPathAndNewPathMap, true, businessCode);
      long end3 = System.currentTimeMillis();
      logger.info("获取当前脚本图片信息并拷贝结束：{},耗时：{}",end3, end3 - end2);
      logger.info("全部文件图片信息：{}",JSON.toJSONString(oldPathAndNewPathMap.keySet()));
      List<String> fileIds = oldPathAndNewPathMap.keySet().stream().map(path -> "/"+MinioPathUtils.idToPath(path)[1]).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(fileIds)) {
        AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
        associatedFilesDto.setObjId("-1");
        associatedFilesDto.setFileIds(fileIds);
        ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
        if (wrapper == null || !wrapper.isSuccess()) {
          throw new InvalidException("文件关联异常");
        }
      }
      //生成新的脚本文件并上传覆盖原来的脚本文件
      String path = generateScriptFileAndUpload(scriptObject, addDto.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      //删除服务器上原文件
      if (StringUtils.hasText(script.getScriptUrl())) {
        deleteFile(script.getScriptUrl());
      }
      script.setScriptUrl(path);
      //生成脚本版本
      AtuScriptVersion atuScriptVersion = generateScriptVersion(script);
      script.setLatestVersionId(atuScriptVersion.getVersionId());
      // 生成新图片
      JSONObject clone = scriptObject.clone();
      getIamgeUrlByJsonArray(addDto.getId(), clone.get("commands"), new HashMap<>(), true, businessCode);
      //生成新的脚本版本文件
      String vsersionScriptPath = generateScriptFileAndUpload(clone, addDto.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      atuScriptVersion.setUrl(vsersionScriptPath);
      AtuScriptInfo newScriptInfo = updateSaveScriptData(script, atuScriptVersion);

      //通知计划输入项发送变动
      planRabbitMQPublisher.updatePlanStatusMQ(addDto.getId());
      return newScriptInfo;
    }else { //新建脚本
      //检查同名脚本是否存在
      Integer num = atuScriptInfoService.countScriptByScriptName(addDto.getScriptName(), addDto.getProjectId());
      if (null != num && num > 0) {
        throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_PRO_HAS_EXIST,addDto.getScriptName());
      }
      //检查脚本目录是否存在
      checkScriptGroup(addDto.getGroupId());
      //生成脚本
      String uuid = UUIDUtil.create32UUID();
      addDto.setId(uuid);
      AtuScriptInfo script = createAtuScript(addDto);
      //补充结点相关脚本信息
      JSONObject scriptTemplate = null;
      String scriptStr = addDto.getScriptJsonStr();
      if (StringUtils.isEmpty(scriptStr)) {
        //虚拟脚本文件数据
        scriptTemplate = new JSONObject();
        scriptTemplate.put(ScriptConstant.ENGINE_VERSION,ScriptConstant.ENGINE_DEFAULT_VERSION);
        scriptTemplate.put(ScriptConstant.VARIABLES, new JSONObject());
        scriptTemplate.put(ScriptConstant.RUNTIME, new JSONObject());

        List<CommandDetailDto> comands = new ArrayList<>();
        for(int i = 0; i<3; i++) {
          CommandDetailDto commandDetailDto = new CommandDetailDto();
          commandDetailDto.setId(ScriptConstant.DETAIL_ID + i);
          commandDetailDto.setTitle(ScriptConstant.DETAIL_TITLE + i);
          commandDetailDto.setImgUri(ScriptConstant.DETAIL_IMG);
          commandDetailDto.setComponentLib(ScriptConstant.DETAIL_LIB);
          commandDetailDto.setCommand(ScriptConstant.DETAIL_COMMAND);
          List<TargetDto> targetDtos = new ArrayList<>();
          TargetDto targetDto = new TargetDto();
          targetDto.setUsing(ScriptConstant.TARGET_USING);
          targetDto.setValue(ScriptConstant.TARGET_VALUE);
          targetDto.setStrategy(ScriptConstant.STR_TWO);
          targetDtos.add(targetDto);
          commandDetailDto.setTargets(targetDtos);
          comands.add(commandDetailDto);
        }
        scriptTemplate.put(ScriptConstant.COMMANDS, comands);

        JSONObject globalSettings = new JSONObject();
        globalSettings.put(ScriptConstant.TIMEOUT, 30);
        scriptTemplate.put(ScriptConstant.GLOBAL_SET, globalSettings);

        JSONObject scriptInfo = new JSONObject();
        scriptInfo.put(ScriptConstant.NAME,script.getScriptName());
        scriptInfo.put(ScriptConstant.CREATED_BY,entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, script.getCreatedBy()));
        scriptTemplate.put(ScriptConstant.SCRIPT_INFO, scriptInfo);

        JSONObject resources = new JSONObject();
        resources.put(ScriptConstant.SCRIPT_DEP, new ArrayList<>());
        resources.put(ScriptConstant.COM_DEP, new ArrayList<>());
        scriptTemplate.put(ScriptConstant.RESOURCE, new JSONObject());

        JSONObject testTarget = new JSONObject();
        testTarget.put(ScriptConstant.TARGET_TYPE, ScriptConstant.TYPE_MOB);
        JSONObject target = new JSONObject();
        target.put(ScriptConstant.APP_PACKAGE, addDto.getPackageName());
        testTarget.put(ScriptConstant.TARGET,target);
        scriptTemplate.put(ScriptConstant.TEST_TARGET, testTarget);
      } else {
        scriptTemplate = JSON.parseObject(scriptStr, JSONObject.class);
      }
      scriptTemplate.put(ScriptConstant.UUID, uuid);
      // 关联截图文件
      String scriptType = script.getScriptType();
      FileBusinessTypeEnum businessCode = null;
      if (scriptType.equals(SCRIPT_TYPE_ANDROID) || scriptType.equals(SCRIPT_TYPE_IOS)) {
        businessCode = FileBusinessTypeEnum.MOBILE_RECORD_SCREENSHOT;
      } else if (scriptType.equals(SCRIPT_TYPE_BS) || scriptType.equals(SCRIPT_TYPE_CS)) {
        businessCode = FileBusinessTypeEnum.PC_RECORD_SCREENSHOT;
      }
      Map<String, String> oldPathAndNewPathMap = new HashMap<>();
      getIamgeUrlByJsonArray(addDto.getId(), scriptTemplate.get("commands"), oldPathAndNewPathMap, false, businessCode);
      List<String> fileIds = oldPathAndNewPathMap.keySet().stream().map(path -> "/"+MinioPathUtils.idToPath(path)[1]).collect(Collectors.toList());
      if (!CollectionUtils.isEmpty(fileIds)) {
        AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
        associatedFilesDto.setObjId(uuid);
        associatedFilesDto.setFileIds(fileIds);
        ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
        if (wrapper == null || !wrapper.isSuccess()) {
          throw new InvalidException("文件关联异常");
        }
      }
      //存储脚本文件
      String path = generateScriptFileAndUpload(scriptTemplate, addDto.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      script.setScriptUrl(path);
      //生成脚本版本
      AtuScriptVersion atuScriptVersion = generateScriptVersion(script);
      String versionPath = generateScriptFileAndUpload(scriptTemplate, addDto.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      atuScriptVersion.setUrl(versionPath);
      script.setLatestVersionId(atuScriptVersion.getVersionId());
      createSaveScriptData(addDto, script, atuScriptVersion, scriptTemplate);
      return script;
    }
  }

  @Transactional(rollbackFor = Exception.class)
  private void createSaveScriptData(AtuScriptInfoAddDto addDto, AtuScriptInfo scriptInfo,
                                    AtuScriptVersion atuScriptVersion, JSONObject scriptTemplate){
    logger.debug("新建脚本数据保存");
    atuScriptVersionService.insert(atuScriptVersion);
    //补充脚本基本状态
    scriptInfo.setPrincipalId(NKSecurityContext.getUserId());
    createdCodeAndInsertData(scriptInfo);
    //新增脚本保存并发布输入项数据
    addSaveAndDeployInputData(addDto, atuScriptVersion, scriptTemplate);
    //生成用例集目录相关数据
    SetTreeDto setTreeDto=new SetTreeDto();
    setTreeDto.setVersion(atuScriptVersion.getVersionName());
    setTreeDto.setId(atuScriptVersion.getScriptId());
    setTreeDto.setVersion(atuScriptVersion.getVersionName());
    setTreeDto.setScriptType(scriptInfo.getScriptType());
    logger.info("发布脚本{"+scriptInfo.getScriptName()+"}----------version{"+atuScriptVersion.getVersionName()+"}");
    atuCaseDataSetService.saveScriptSetTree(setTreeDto);
  }

  @Transactional(rollbackFor = Exception.class)
  private AtuScriptInfo updateSaveScriptData(AtuScriptInfo scriptInfo, AtuScriptVersion atuScriptVersion){
    logger.debug("编辑脚本数据保存");
    atuScriptVersionService.insert(atuScriptVersion);
    //更新脚本信息
    atuScriptInfoService.updateByPrimaryKey(scriptInfo);
    AtuScriptInfo newScriptInfo = atuScriptInfoService.findByPrimaryKey(scriptInfo.getId());
    //编辑脚本保存并发布输入项数据
    updateSaveAndDeployInputData(atuScriptVersion);
    //生成用例集目录相关数据
    SetTreeDto setTreeDto=new SetTreeDto();
    logger.info("发布脚本{"+newScriptInfo.getScriptName()+"}----------version{"+atuScriptVersion.getVersionName()+"}");
    setTreeDto.setVersion(atuScriptVersion.getVersionName());
    setTreeDto.setId(atuScriptVersion.getScriptId());
    setTreeDto.setScriptType(newScriptInfo.getScriptType());
    atuCaseDataSetService.saveScriptSetTree(setTreeDto);
    return newScriptInfo;
  }

  @Override
  public Pagination<AtuScriptInfoDetailDto> pagingQuery(QueryByPage<AtuScriptInfoQueryDto> query) {
    DefaultPagination<AtuScriptInfoDetailDto> pagination = new DefaultPagination();
    AtuScriptInfoQueryDto scriptQuery = query.getQuery();
    //处理查询参数
    if (null != scriptQuery) {
      AtuScriptInfoQueryDto autoScriptQueryDto = handleQueryParam(scriptQuery);
      //无符合条件创建人
      if (null == autoScriptQueryDto) {
        return pagination;
      }
      autoScriptQueryDto.setIsDeleted(ScriptConstant.STR_ZERO);
      autoScriptQueryDto.setTenantId(NKSecurityContext.getTenantId());
      query.setQuery(autoScriptQueryDto);
    }
    //处理分页参数
    handlePageParam(query);
    pagination.setPageSize(query.getPageSize());
    pagination.setPageNo(query.getPageNo());

    Page<AtuScriptInfoDetailDto> page = PageMethod.startPage(query.getPageNo(), query.getPageSize());  //开始分页
    List<AtuScriptInfoDetailDto> result = atuScriptInfoService.queryScriptList(query);
    //处理返回数据
    for (AtuScriptInfoDetailDto detailDto : result) {
      //创建修改人名称
      detailDto.setCreator(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, detailDto.getCreatedBy()));
      detailDto.setModifier(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, detailDto.getUpdatedBy()));
      detailDto.setPrincipal(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER,detailDto.getPrincipalId()));
    }
    pagination.setRecords(result);
    pagination.setRecordCount(page.getTotal());
    return pagination;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer deleteScript(String id) {
    AtuScriptInfo script = atuScriptInfoService.findByPrimaryKey(id);
    //校验脚本是否被计划引用
    Boolean status = executePlanFeignClient.checkScript(CollUtil.newArrayList(id));
    if (status){//true:存在关联，删除失败  false:不存在关联
      throw new PlatformRuntimeException(ScriptCaseAppError.PLAN_HAS_SCRIPT);
    }
    //校验脚本是否存在用例集
    AtuCaseDataSet dataSet = new AtuCaseDataSet();
    dataSet.setLeaf(true);
    dataSet.setScriptId(id);
    List<AtuCaseDataSet> query = caseDataSetService.query(dataSet);
    if (query != null && query.size()>0){
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_HAS_DATA_SET);
    }
    //校验脚本是否被场景脚本引用
    AtuSceneNodeInfo nodeInfo = new AtuSceneNodeInfo();
    nodeInfo.setNodeScriptId(id);
    nodeInfo.setIsDeleted(0);
    List<AtuSceneNodeInfo> resultList = this.atuSceneNodeInfoService.query(nodeInfo);
    if (resultList.size() > 0) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_IN_SCENE);
    }
    AtuScriptInfo scriptInfo = new AtuScriptInfo();
    BeanUtils.copyProperties(script, scriptInfo);
    scriptInfo.setIsDeleted(ScriptConstant.STR_ONE);
    scriptInfo.setUpdatedTime(new Date());
    scriptInfo.setUpdatedBy(NKSecurityContext.getUserId());
    int num = atuScriptInfoService.updateByPrimaryKey(scriptInfo);
    String scriptUrl = script.getScriptUrl();
    JSONObject oldJsonObject = downloadScriptFile(scriptUrl);
    Map<String, String> oldPathAndNewPathMap = new HashMap<>();
    getIamgeUrlByJsonArray(null, oldJsonObject.get("commands"), oldPathAndNewPathMap, false, null);
    // 删除脚本文件
    attachmentFeignClient.deleteFileByObjId(id, null);
    List<String> deletedFilePath = oldPathAndNewPathMap.keySet().stream().map(path -> "/" + MinioPathUtils.idToPath(path)[1]).collect(Collectors.toList());
    if (!CollectionUtils.isEmpty(deletedFilePath)) {
      AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
      associatedFilesDto.setObjId("-1");
      associatedFilesDto.setFileIds(deletedFilePath);
      ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
      if (wrapper == null || !wrapper.isSuccess()) {
        throw new InvalidException("文件关联异常");
      }
    }
    //删除脚本草稿输入项
    AtuScriptInputSet atuScriptInputSet = new AtuScriptInputSet();
    atuScriptInputSet.setScriptId(script.getId());
    atuScriptInputSetService.deleteByExample(atuScriptInputSet);
    // 删除输入项
    AtuInputSet atuInputSet = new AtuInputSet();
    atuInputSet.setScriptId(script.getId());
    atuInputSetService.deleteByExample(atuInputSet);
    // 删除版本输入项表
    AtuScriptInputSetVersion inputSetVersion = new AtuScriptInputSetVersion();
    inputSetVersion.setScriptId(script.getId());
    atuScriptInputSetVersionService.deleteByExample(inputSetVersion);
    // 删除版本表
    AtuScriptVersion atuScriptVersion = new AtuScriptVersion();
    atuScriptVersion.setScriptId(script.getId());
    atuScriptVersionService.deleteByExample(atuScriptVersion);
    //删除脚本增加平台日志
    CpLogAddDto cpLogAddDto = new CpLogAddDto();
    String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), script.getProjectId());
    String content = String.format(ScriptConstant.DEL_SCRIPT_INFO,projectName,script.getScriptName());
    cpLogAddDto.setContent(content);
    cpLogAddDto.setModule(ScriptConstant.SCRIPT_MODULE);
    cpLogAddDto.setType(ScriptConstant.LOG_DEL_STATUS);
    MonsterLogServer.sendLogToMonster(cpLogAddDto);
    logPublisher.deployLogContent(cpLogAddDto);
    return num;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer deleteScriptList(AtuScriptInfoDeleteDto dto) {
    List<String> scriptIds = dto.getScriptIds();
    if (CollectionUtils.isEmpty(scriptIds)) {
      throw new PlatformRuntimeException(ScriptCaseAppError.DEL_SCRIPT_ID_NULL);
    }
    //feign:查询这批脚本是否被引用
    Boolean status = executePlanFeignClient.checkScript(scriptIds);
    if (status){//true:存在关联，删除失败  false:不存在关联
      throw new PlatformRuntimeException(ScriptCaseAppError.PLAN_HAS_SCRIPT_LIST);
    }
    //校验脚本是否存在用例集
    List<AtuCaseDataSet> setList = caseDataSetService.querySetByList(scriptIds);
    if (setList != null && setList.size()>0){
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_LIST_HAS_DATA_SET);
    }
    //校验脚本是否被场景脚本引用
    List<AtuSceneNodeInfo> nodeInfoList = atuSceneNodeInfoService.queryNodeByScriptId(scriptIds);
    if (nodeInfoList != null && nodeInfoList.size()>0) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_LIST_IN_SCENE);
    }
    //获取脚本信息
    List<AtuScriptInfo> scriptInfoList = atuScriptInfoService.queryScriptByIds(scriptIds);
    List<String> scriptNames = new ArrayList<>();
    List<String> deletedFilePath = new ArrayList<>();
    for (AtuScriptInfo atuScriptInfo : scriptInfoList) {
      if (null == atuScriptInfo) continue;
      scriptNames.add(atuScriptInfo.getScriptName());
      String scriptUrl = atuScriptInfo.getScriptUrl();
      JSONObject oldJsonObject = downloadScriptFile(scriptUrl);
      Map<String, String> oldPathAndNewPathMap = new HashMap<>();
      getIamgeUrlByJsonArray(null, oldJsonObject.get("commands"), oldPathAndNewPathMap, false, null);
      deletedFilePath.addAll(oldPathAndNewPathMap.keySet().stream().map(path -> "/" + MinioPathUtils.idToPath(path)[1]).collect(Collectors.toList()));
      attachmentFeignClient.deleteFileByObjId(atuScriptInfo.getId(), null);
      //删除脚本草稿输入项
      AtuScriptInputSet atuScriptInputSet = new AtuScriptInputSet();
      atuScriptInputSet.setScriptId(atuScriptInfo.getId());
      atuScriptInputSetService.deleteByExample(atuScriptInputSet);
      // 删除输入项
      AtuInputSet atuInputSet = new AtuInputSet();
      atuInputSet.setScriptId(atuScriptInfo.getId());
      atuInputSetService.deleteByExample(atuInputSet);
      // 删除版本输入项表
      AtuScriptInputSetVersion inputSetVersion = new AtuScriptInputSetVersion();
      inputSetVersion.setScriptId(atuScriptInfo.getId());
      atuScriptInputSetVersionService.deleteByExample(inputSetVersion);
      // 删除版本表
      AtuScriptVersion atuScriptVersion = new AtuScriptVersion();
      atuScriptVersion.setScriptId(atuScriptInfo.getId());
      atuScriptVersionService.deleteByExample(atuScriptVersion);
    }
    if (!CollectionUtils.isEmpty(deletedFilePath)) {
      AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
      associatedFilesDto.setObjId("-1");
      associatedFilesDto.setFileIds(deletedFilePath);
      ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
      if (wrapper == null || !wrapper.isSuccess()) {
        throw new InvalidException("文件关联异常");
      }
    }
    String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), scriptInfoList.get(0).getProjectId());
    //逻辑删除脚本
    AtuScriptInfo scriptInfo = new AtuScriptInfo();
    scriptInfo.setIsDeleted(ScriptConstant.STR_ONE);
    scriptInfo.setUpdatedTime(new Date());
    scriptInfo.setUpdatedBy(NKSecurityContext.getUserId());
    int num = atuScriptInfoService.deleteScriptList(scriptInfo,scriptIds);
    //删除脚本增加平台日志
    CpLogAddDto cpLogAddDto = new CpLogAddDto();
    String content = String.format(ScriptConstant.DEL_SCRIPT_LIST,projectName,num);
    cpLogAddDto.setContent(content);
    cpLogAddDto.setModule(ScriptConstant.SCRIPT_MODULE);
    cpLogAddDto.setType(ScriptConstant.LOG_DEL_STATUS);
    cpLogAddDto.setContentDetails(scriptNames);
    MonsterLogServer.sendLogToMonster(cpLogAddDto);
    logPublisher.deployLogContent(cpLogAddDto);
    return num;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer renameScript(AtuScriptInfoUpdateDto dto) {
    String scriptName = dto.getScriptName();
    AtuScriptInfo scriptInfo = atuScriptInfoService.findByPrimaryKey(dto.getId());
    if (null == scriptInfo) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_VERSION_NOT_EXIST);
    }
    //名称未改变不更新
    if (scriptName.equals(scriptInfo.getScriptName())) {
      return 0;
    }
    //检查同名脚本是否存在
    Integer num = atuScriptInfoService.countScriptByScriptName(scriptName, scriptInfo.getProjectId());
    if (null != num && num > 0) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_PRO_HAS_EXIST,scriptName);
    }
    //更新脚本数据
    scriptInfo.setScriptName(dto.getScriptName());
    scriptInfo.setUpdatedBy(NKSecurityContext.getUserId());
    scriptInfo.setUpdatedTime(new Date());
    return atuScriptInfoService.updateByPrimaryKey(scriptInfo);
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer moveScript(AtuScriptInfoMoveDto dto) {
    if(dto.getId()!=null && dto.getScriptIds()==null){
      List<String> scriptIds = new ArrayList<>();
      scriptIds.add(dto.getId());
      dto.setScriptIds(scriptIds);
    }
    List<String> ids = dto.getScriptIds();
    if (ids==null || ids.size()<1) {
      throw new PlatformRuntimeException(ScriptCaseAppError.MOVE_SCRIPT_ID_NULL);
    }
    List<AtuScriptInfo> scripts = atuScriptInfoService.findByPrimaryKeys(new ArrayList<Object>(ids));
    if (null == scripts || scripts.size()<1) {
      throw new PlatformRuntimeException(ScriptCaseAppError.MOVE_SCRIPT_NOT_EXIST);
    }
    //检查脚本目录是否存在
    checkScriptGroup(dto.getGroupId());
    for (String scriptId : dto.getScriptIds()) {
      //补充脚本信息
      AtuScriptInfo moveScript = new AtuScriptInfo();
      moveScript.setId(scriptId);
      moveScript.setGroupId(dto.getGroupId());
      moveScript.setUpdatedBy(NKSecurityContext.getUserId());
      moveScript.setUpdatedTime(new Date());
      atuScriptInfoService.updateByPrimaryKey(moveScript);
    }
    return 1;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer copyScript(AtuScriptInfoMoveDto dto) {
    if (CollectionUtils.isEmpty(dto.getScriptIds())) {
      if (StringUtils.hasText(dto.getId())) {
        List<String> ids = new ArrayList<>();
        ids.add(dto.getId());
        dto.setScriptIds(ids);
      }
    }
    //查询出需要复制的脚本
    if (CollectionUtils.isEmpty(dto.getScriptIds())) {
      throw new PlatformRuntimeException(ScriptCaseAppError.COPY_SCRIPT_ID_NULL);
    }
    List<AtuScriptInfo> scriptList = atuScriptInfoService.queryScriptByIds(dto.getScriptIds());
    if (CollectionUtils.isEmpty(scriptList)) {
      throw new PlatformRuntimeException(ScriptCaseAppError.COPY_SCRIPT_NOT_EXIST);
    }
    //查询当前系统关联的环境集合
    List<String> envIds = projectFeignClient.selectEnvIds(scriptList.get(0).getProjectId());
    Integer copyNum = 0;
    List<AtuScriptInputSet> inputSetList = new ArrayList<>();
    for (AtuScriptInfo scriptInfo : scriptList) {
      AtuScriptInfo copyScript = getCopyScript(scriptInfo, dto);
      if (copyScript.getScriptName().length() > 30) {
        throw new PlatformRuntimeException(ScriptCaseAppError.COPY_SCRIPT_NAME_TOO_LONG, copyScript.getScriptName());
      }
      Map<String,String> filePath = copyScriptFile(copyScript);
      copyScript.setScriptUrl(filePath.get(ScriptConstant.SCRIPT_URL));
      copyScript.setDataUrl(filePath.get(ScriptConstant.DATA_URL));
      //保存克隆脚本
      createdCodeAndInsertData(copyScript);
      //克隆脚本标签
      cloneScriptLabel(scriptInfo,copyScript.getId());
      //克隆输入项数据
      List<AtuScriptInputSet> scriptInputList = copyScriptInput(scriptInfo, envIds, copyScript.getId());
      if (scriptInputList.size() > 0){
        atuScriptInputSetService.insertByBatch(scriptInputList);
      }
      copyNum++;
    }
    return copyNum;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer rollBackVersion(AtuScriptVersionQueryDto queryDto) {
    AtuScriptVersion query = new AtuScriptVersion();
    BeanUtils.copyProperties(queryDto,query);
    List<AtuScriptVersion> versions = atuScriptVersionService.query(query);
    if (CollectionUtils.isEmpty(versions)) {
      throw new PlatformRuntimeException(ScriptCaseAppError.RELOAD_VERSION_NOT_EXIST);
    }
    //脚本+版本id即可确定唯一内容
    AtuScriptVersion atuScriptVersion = versions.get(0);
    //更新脚本内容
    AtuScriptInfo script = atuScriptInfoService.findByPrimaryKey(queryDto.getScriptId());
    AtuScriptInfo newScript = new AtuScriptInfo();
    BeanUtils.copyProperties(script,newScript);
    newScript.setScriptName(atuScriptVersion.getScriptName());
    newScript.setScriptUrl(atuScriptVersion.getUrl());
    newScript.setDataUrl(atuScriptVersion.getDataUrl());
    newScript.setUpdatedBy(NKSecurityContext.getUserId());
    newScript.setUpdatedTime(new Date());
    //生成脚本版本实体，更新脚本数据
    AtuScriptVersion newVersion = generateScriptVersion(newScript);
    String scriptType = script.getScriptType();
    FileBusinessTypeEnum businessCode = null;
    if (scriptType.equals(SCRIPT_TYPE_ANDROID) || scriptType.equals(SCRIPT_TYPE_IOS)) {
      businessCode = FileBusinessTypeEnum.MOBILE_RECORD_SCREENSHOT;
    } else if (scriptType.equals(SCRIPT_TYPE_BS) || scriptType.equals(SCRIPT_TYPE_CS)) {
      businessCode = FileBusinessTypeEnum.PC_RECORD_SCREENSHOT;
    }
    String oldScriptUrl = atuScriptVersion.getUrl();
    JSONObject oldJsonObject = downloadScriptFile(oldScriptUrl);
    Map<String, String> oldPathAndNewPathMap = new HashMap<>();
    getIamgeUrlByJsonArray(newScript.getId(), oldJsonObject.get("commands"), oldPathAndNewPathMap, true, businessCode);
    String newScriptUrl = generateScriptFileAndUpload(oldJsonObject, newScript.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
    newScript.setScriptUrl(newScriptUrl);
    newScript.setLatestVersionId(newVersion.getVersionId());
    atuScriptInfoService.updateByPrimaryKey(newScript);
    //插入新生成版本数据
    newVersion.setCreatedBy(newScript.getUpdatedBy());
    newVersion.setCreatedTime(newScript.getUpdatedTime());
    //输入项数据回滚
    atuInputSetDataRollBack(queryDto,atuScriptVersion,newVersion.getVersionId(), oldJsonObject);
    return atuScriptVersionService.insert(newVersion);
  }

  private void atuInputSetDataRollBack(AtuScriptVersionQueryDto queryDto,AtuScriptVersion atuScriptVersion,Integer versionId, JSONObject scriptJson) {
    //删除正式表中当前脚本关联的数据
    AtuInputSet atuInputSetDel=new AtuInputSet();
    atuInputSetDel.setScriptId(queryDto.getScriptId());
    atuInputSetService.deleteByExample(atuInputSetDel);
    //删除草稿表数据
    AtuScriptInputSet atuScriptInputSet=new AtuScriptInputSet();
    atuScriptInputSet.setScriptId(queryDto.getScriptId());
    atuScriptInputSetService.deleteByExample(atuScriptInputSet);
    //查询系统关联环境id集合
    List<String> envIds = projectFeignClient.selectEnvIds(atuScriptVersion.getProjectId());
    if (envIds.size()!=0) {
      //查询草稿表版本表
      AtuScriptInputSetVersion atuScriptInputSetVersion = new AtuScriptInputSetVersion();
      atuScriptInputSetVersion.setScriptId(queryDto.getScriptId());
      atuScriptInputSetVersion.setScriptVersionId(queryDto.getVersionId());
      List<AtuScriptInputSetVersion> query1 = atuScriptInputSetVersionService.query(atuScriptInputSetVersion);

      AtuInputSet atuInputSetAdd=null;
      AtuScriptInputSetVersion atuScriptInputSetVersionAdd=null;
      JSONObject jsonObject=null;
      if (query1.size()!=0){
        for (AtuScriptInputSetVersion atu:query1) {
          if (envIds.contains(atu.getEnvId())){
            //插入版本表中的数据到正式表
            String dataUrl = atu.getDataUrl();
            atuInputSetAdd=new AtuInputSet();
            BeanUtils.copyProperties(atu,atuInputSetAdd);
            String inputSetDataUrl = copyJSONFile(dataUrl, atuScriptVersion.getScriptId(), FileBusinessTypeEnum.INPUT_DATA_SET);
            atuInputSetAdd.setDataUrl(inputSetDataUrl);
            atuInputSetAdd.setCreatedTime(new Date());
            atuInputSetAdd.setCreatedBy(NKSecurityContext.getUserId());
            atuInputSetAdd.setId(UUIDUtil.create32UUID());
            atuInputSetService.insert(atuInputSetAdd);
            //插入版本表中的数据到草稿表版本表
            atuScriptInputSetVersionAdd=new AtuScriptInputSetVersion();
            BeanUtils.copyProperties(atu,atuScriptInputSetVersionAdd);
            atuScriptInputSetVersionAdd.setId(UUIDUtil.create32UUID());
            atuScriptInputSetVersionAdd.setScriptVersionId(versionId);
            atuScriptInputSetVersionAdd.setCreatedBy(NKSecurityContext.getUserId());
            atuScriptInputSetVersionAdd.setCreatedTime(new Date());
            String inputSetVersionUrl = copyJSONFile(dataUrl, atuScriptVersion.getScriptId(), FileBusinessTypeEnum.COMMON_SCRIPT_VERSION_INPUT_DATA_SET);
            atuScriptInputSetVersionAdd.setDataUrl(inputSetVersionUrl);
            atuScriptInputSetVersionService.insert(atuScriptInputSetVersionAdd);
            //插入版本表中的数据到草稿表
            AtuScriptInputSet atuScriptInputSet1 = new AtuScriptInputSet();
            BeanUtils.copyProperties(atu,atuScriptInputSet1);
            atuScriptInputSet1.setId(UUIDUtil.create32UUID());
            String scriptInputSetDataUrl = copyJSONFile(dataUrl, atuScriptVersion.getScriptId(), FileBusinessTypeEnum.COMMON_SCRIPT_INPUT_DATA_SET);
            atuScriptInputSet1.setDataUrl(scriptInputSetDataUrl);
            atuScriptInputSet1.setCreatedBy(NKSecurityContext.getUserId());
            atuScriptInputSet1.setCreatedTime(new Date());
            atuScriptInputSet1.setUpdatedBy(NKSecurityContext.getUserId());
            atuScriptInputSet1.setUpdatedTime(new Date());
            atuScriptInputSetService.insert(atuScriptInputSet1);
          }
        }
        List<String> list = query1.stream().map(AtuScriptInputSetVersion::getEnvId).collect(Collectors.toList());
        List<String> addEnvIds=new ArrayList<>();
        for (String envId:envIds){
          if (!list.contains(envId)){
            addEnvIds.add(envId);
          }
        }
        if (addEnvIds.size()!=0){
          for (String envId:addEnvIds) {
            //插入版本表中的数据到正式表
            atuInputSetAdd=new AtuInputSet();
            atuInputSetAdd.setEnvId(envId);
            atuInputSetAdd.setScriptId(queryDto.getScriptId());
            atuInputSetAdd.setCreatedTime(new Date());
            atuInputSetAdd.setCreatedBy(NKSecurityContext.getUserId());
            atuInputSetAdd.setId(UUIDUtil.create32UUID());
            //
            jsonObject=new JSONObject();
            jsonObject.put(ScriptConstant.SCRIPT_INPUT_ENV_ID,envId);
            String upload = generateScriptFileAndUpload(jsonObject, queryDto.getScriptId(), FileBusinessTypeEnum.INPUT_DATA_SET);
            atuInputSetAdd.setDataUrl(upload);
            atuInputSetService.insert(atuInputSetAdd);
          }
        }
      } else {
        for (String envId:envIds) {
          //插入版本表中的数据到正式表
          atuInputSetAdd=new AtuInputSet();
          atuInputSetAdd.setEnvId(envId);
          atuInputSetAdd.setScriptId(queryDto.getScriptId());
          atuInputSetAdd.setCreatedTime(new Date());
          atuInputSetAdd.setCreatedBy(NKSecurityContext.getUserId());
          atuInputSetAdd.setId(UUIDUtil.create32UUID());
          //
          jsonObject = atuScriptInputSetService.createDefaultInputSet(JSONUtil.toJsonStr(scriptJson));
          String upload = generateScriptFileAndUpload(jsonObject, queryDto.getScriptId(), FileBusinessTypeEnum.INPUT_DATA_SET);
          atuInputSetAdd.setDataUrl(upload);
          atuInputSetService.insert(atuInputSetAdd);
        }
      }
    }
  }

  @Override
  @DatabaseReadOnly
  public AtuScriptInfoDetailDto getVersionContent(AtuScriptVersionQueryDto queryDto) {
    AtuScriptVersion query = new AtuScriptVersion();
    BeanUtils.copyProperties(queryDto,query);
    List<AtuScriptVersion> versions = atuScriptVersionService.query(query);
    if (CollectionUtils.isEmpty(versions)) {
      throw new PlatformRuntimeException(ScriptCaseAppError.VERSION_NOT_EXIST);
    }
    logger.debug("versions :{}", versions);
    //脚本+版本id即可确定唯一内容
    AtuScriptVersion atuScriptVersion = versions.get(0);
    logger.debug("atuScriptVersion :{}", versions);

    //更新脚本内容
    AtuScriptInfo script = atuScriptInfoService.findByPrimaryKey(queryDto.getScriptId());
    script.setScriptUrl(atuScriptVersion.getUrl());
    script.setDataUrl(atuScriptVersion.getDataUrl());
    script.setScriptName(atuScriptVersion.getScriptName());
    //封装脚本详情
    AtuScriptInfoDetailDto res = new AtuScriptInfoDetailDto();
    BeanUtils.copyProperties(script,res);
    //封装脚本步骤信息
    if (StringUtils.hasText(script.getScriptUrl())) {
      JSONObject scriptData = downloadScriptFile(script.getScriptUrl());
      if (null != scriptData) {
        //获取脚本信息字符串
        res.setScriptJsonStr(scriptData.toJSONString());
      }
    }
    return res;
  }

  private void updateBusinessComInfo(JSONObject scriptData){
    JSONObject resources = scriptData.getJSONObject(ScriptConstant.RESOURCE);
    if (resources == null){
      logger.debug("脚本未使用资源");
      return;
    }
    String scriptDependencies = resources.getString(ScriptConstant.SCRIPT_DEP);
    if (scriptDependencies == null){
      logger.debug("脚本未使用脚本依赖");
      return;
    }
    List<ScriptDependencyDto> scriptDependencyList = JSON.parseArray(scriptDependencies, ScriptDependencyDto.class);
    if (CollUtil.isEmpty(scriptDependencyList)){
      return;
    }
    List<String> resIdList = scriptDependencyList.stream().map(ScriptDependencyDto::getResId).collect(Collectors.toList());
    Map<String, String> comNameMap = busComponentInfoApiService.queryComNameByIdList(resIdList);
    if (CollUtil.isEmpty(comNameMap)){
      logger.debug("业务组件查询为空");
      return;
    }
    JSONArray commands = scriptData.getJSONArray(ScriptConstant.COMMANDS);
    List<JSONObject> commandList = new ArrayList<>();
    for (Object command : commands) {
      JSONObject commandJson = JSON.parseObject(JSON.toJSONString(command));
      JSONObject args = commandJson.getJSONObject(ScriptConstant.ARGS);
      if (args == null){
        commandList.add(commandJson);
        continue;
      }
      String resId = args.getString(ScriptConstant.RES_ID);
      if (resId == null){
        commandList.add(commandJson);
        continue;
      }
      if (comNameMap.containsKey(resId)){
        JSONObject extAttrs = commandJson.getJSONObject(ScriptConstant.EXT_ATTRS);
        extAttrs.put(ScriptConstant.COMMAND_NAME, comNameMap.get(resId));
        commandJson.put(ScriptConstant.EXT_ATTRS, extAttrs);
      }
      commandList.add(commandJson);
    }
    scriptData.put(ScriptConstant.COMMANDS, commandList);
  }

  @Override
  @DatabaseReadOnly
  public AtuScriptInfoDetailDto getScriptInfo(String scriptId, Boolean queryLastVersion) {
    AtuScriptInfo scriptInfo = atuScriptInfoService.findByPrimaryKey(scriptId);
    if (null == scriptInfo || ScriptConstant.STR_ONE.equals(scriptInfo.getIsDeleted())) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_VERSION_NOT_EXIST);
    }
    AtuScriptVersion record = new AtuScriptVersion();
    record.setScriptId(scriptId);
    record.setVersionId(scriptInfo.getLatestVersionId());
    List<AtuScriptVersion> query = atuScriptVersionService.query(record);
    AtuScriptVersion atuScriptVersion = null;
    if (!CollectionUtils.isEmpty(query)) {
      atuScriptVersion = query.get(0);
    }
    AtuScriptInfoDetailDto detailDto = new AtuScriptInfoDetailDto();
    BeanUtils.copyProperties(scriptInfo,detailDto);
    String scriptUrl = scriptInfo.getScriptUrl();
    String dataUrl = scriptInfo.getDataUrl();
    if (atuScriptVersion != null) {
      //增加版本信息返回
      detailDto.setVersionName(atuScriptVersion.getVersionName());
      if (queryLastVersion) {
        scriptUrl = atuScriptVersion.getUrl();
        dataUrl = atuScriptVersion.getDataUrl();
        detailDto.setScriptUrl(scriptUrl);
        detailDto.setDataUrl(dataUrl);
      }
    }
    //获取脚本步骤信息
    if (StringUtils.hasText(scriptUrl)) {
      JSONObject scriptData = downloadScriptFile(scriptUrl);
      if (null != scriptData) {
        // 业务组件信息更新
        updateBusinessComInfo(scriptData);
        //获取脚本信息字符串
        detailDto.setScriptJsonStr(scriptData.toJSONString());
        //获取脚本参数封装输入输出项参数信息
        Map scriptMap = scriptData.toJavaObject(Map.class);
        Object variables = scriptMap.get(ScriptConstant.VARIABLES);
        if (null != variables && variables instanceof List) {
          List<Object> variableDtoList = (List<Object>) variables;
          List<Object> inputs = new ArrayList<>();
          List<Object> outputs = new ArrayList<>();
          for (Object scriptVariableDto : variableDtoList) {
            ScriptVariableDto temp = JSONObject.toJavaObject((JSON) scriptVariableDto,ScriptVariableDto.class);
            if (null != temp) {
              if (null != temp.getInput() && temp.getInput()) {
                inputs.add(scriptVariableDto);
              }
              if (null != temp.getOutput() && temp.getOutput()) {
                outputs.add(scriptVariableDto);
              }
            }
          }
          detailDto.setInputList(inputs);
          detailDto.setOutputList(outputs);
        }
      }
    }
    //获取脚本输入项数据
    if (StringUtils.hasText(dataUrl)) {
      JSONObject jsonObject = downloadScriptFile(dataUrl);
      if (jsonObject != null){
        ScriptInputTableDto inputTableDto = jsonObject.toJavaObject(ScriptInputTableDto.class);
        if (null != inputTableDto) {
          detailDto.setInputs(inputTableDto);
        }
      }
    }
    return detailDto;
  }

  @Override
  public String getScriptDetailInfo(Map<String, String> params) {
    String scriptId = params.get(ScriptConstant.SCRIPT_ID);
    String type = params.get(ScriptConstant.TYPE);
    if (ObjectUtil.equal(ScriptConstant.STR_SIX, type)){
      // 场景用例
      AtuSceneInfo atuSceneInfo = atuSceneInfoService.findByPrimaryKey(scriptId);
      if (ObjectUtil.isNull(atuSceneInfo)){
        return "";
      }
      JSONObject jsonObject = downloadScriptFile(atuSceneInfo.getScriptUrl());
      return JSONUtil.toJsonStr(jsonObject);
    }else {
      // 查询脚本信息
      AtuScriptInfo scriptInfo = atuScriptInfoService.findByPrimaryKey(scriptId);
      if (ObjectUtil.isNull(scriptInfo)) {
        return "";
      }
      JSONObject jsonObject = downloadScriptFile(scriptInfo.getScriptUrl());
      return JSONUtil.toJsonStr(jsonObject);
    }
  }

  @Override
  public String getScriptName(String scriptId) {
    AtuScriptInfo scriptInfo = atuScriptInfoService.findByPrimaryKey(scriptId);
    if (null == scriptInfo) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_IS_DEL);
    }
    return scriptInfo.getScriptName();
  }

  @Override
  public Map<String, AtuPlanScriptDetailDto> queryScriptDetailMap(Set<String> scriptIdSet) {
    Map<String, AtuPlanScriptDetailDto> scriptMap = new HashMap<>(scriptIdSet.size());
    List<AtuScriptInfoDetailDto> scriptList = atuScriptInfoService.queryScriptDetailList(scriptIdSet);
    if (CollUtil.isEmpty(scriptList)){
      return scriptMap;
    }
    for (AtuScriptInfoDetailDto atuScriptInfoDetailDto : scriptList) {
      AtuPlanScriptDetailDto detailDto = new AtuPlanScriptDetailDto();
      BeanUtils.copyProperties(atuScriptInfoDetailDto, detailDto);
      detailDto.setScriptId(atuScriptInfoDetailDto.getId());
      detailDto.setVersionId(atuScriptInfoDetailDto.getLatestVersionId());
      detailDto.setScriptPath(atuScriptInfoDetailDto.getScriptUrl());
      detailDto.setPlatformType(atuScriptInfoDetailDto.getPlatform());
      scriptMap.put(atuScriptInfoDetailDto.getId(), detailDto);
    }
    return scriptMap;
  }

  private void addSaveAndDeployInputData(AtuScriptInfoAddDto addDto,AtuScriptVersion atuScriptVersion, JSONObject scriptJson) {
    //查询系统关联的环境id集合
    List<String> envIds = projectFeignClient.selectEnvIds(addDto.getProjectId());
    if (envIds.size() != 0) {
      List<AtuScriptInputSet> scriptInputSetList = new ArrayList<>();
      List<AtuScriptInputSetVersion> scriptInputSetVersionList = new ArrayList<>();
      List<AtuInputSet> inputSetList = new ArrayList<>();
      String scriptId = atuScriptVersion.getScriptId();
      Integer versionId = atuScriptVersion.getVersionId();
      //输入项判空
      if (addDto.getAtuScriptInputSetAddTmpDtos() != null &&
              addDto.getAtuScriptInputSetAddTmpDtos().size()>0) {
        List<String> fileIds = new ArrayList<>();
        for (AtuScriptInputSetAddTmpDto addTmpDto : addDto.getAtuScriptInputSetAddTmpDtos()) {
          // 添加输入项瞬间增加或删除了某个环境
          if (envIds.contains(addTmpDto.getEnvId())) {
            String path = addTmpDto.getPath();
            fileIds.add("/" + MinioPathUtils.idToPath(path)[1]);
            String envId = addTmpDto.getEnvId();
            //更新到输入项草稿表
            createScriptInputSet(scriptInputSetList, scriptId, envId, path);
            //更新草稿表版本表
            createScriptInputSetVersion(scriptInputSetVersionList, scriptId, envId, path, versionId);
            //同步草稿表数据到正式表
            createInputSet(inputSetList, scriptId, envId, path);
          }
        }
        if (!CollectionUtils.isEmpty(fileIds)) {
          AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
          associatedFilesDto.setObjId(scriptId);
          associatedFilesDto.setFileIds(fileIds);
          ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
          if (wrapper == null || !wrapper.isSuccess()) {
            throw new InvalidException("文件关联异常");
          }
        }
      }else {
        // 生成默认轮次
        JSONObject jsonObject = atuScriptInputSetService.createDefaultInputSet(JSONUtil.toJsonStr(scriptJson));

        for (String envId : envIds) {
          // 上传默认输入项数据
          String scriptInputSetId = UUIDUtil.create32UUID();
          String path = generateScriptFileAndUpload(jsonObject, scriptId, FileBusinessTypeEnum.COMMON_SCRIPT_INPUT_DATA_SET);
          //更新到输入项草稿表
          createScriptInputSet(scriptInputSetList, scriptId, envId, path);
          //更新草稿表版本表
          createScriptInputSetVersion(scriptInputSetVersionList, scriptId, envId, path, versionId);
          //同步草稿表数据到正式表
          createInputSet(inputSetList, scriptId, envId, path);
        }
      }

      if (CollUtil.isNotEmpty(scriptInputSetList)){
        for (AtuScriptInputSet dto : scriptInputSetList) {
          AtuInputSetResultDto resultDto = downloadFileUtils.downloadFile(dto.getDataUrl());
          dataMgrUtils.queryInputAndDataLink(resultDto.getTableContent(),dto.getEnvId(),dto.getId(),ScriptConstant.DATA_SET_LINK_BY_SCRIPT);
        }
        atuScriptInputSetService.insertByBatch(scriptInputSetList);
      }

      if (CollUtil.isNotEmpty(scriptInputSetVersionList)){
        atuScriptInputSetVersionService.insertByBatch(scriptInputSetVersionList);
      }

      if (CollUtil.isNotEmpty(inputSetList)){
        for (AtuInputSet dto : inputSetList) {
          AtuInputSetResultDto resultDto = downloadFileUtils.downloadFile(dto.getDataUrl());
          dataMgrUtils.queryInputAndDataLink(resultDto.getTableContent(),dto.getEnvId(),dto.getId(),ScriptConstant.DATA_SET_LINK_BY_CASE);
        }
        atuInputSetService.insertByBatch(inputSetList);
      }
    }
  }

  private void createScriptInputSet(List<AtuScriptInputSet> scriptInputSetList, String scriptId,
                                    String envId, String path){
    AtuScriptInputSet scriptInputSet = new AtuScriptInputSet();
    String uuid = UUIDUtil.create32UUID();
    scriptInputSet.setId(uuid);
    scriptInputSet.setScriptId(scriptId);
    scriptInputSet.setEnvId(envId);
    scriptInputSet.setDataUrl(path);
    scriptInputSet.setCreatedBy(NKSecurityContext.getUserId());
    scriptInputSet.setCreatedTime(new Date());
    scriptInputSetList.add(scriptInputSet);

    AtuInputSetResultDto resultDto = downloadFileUtils.downloadFile(path);
    dataMgrUtils.queryInputAndDataLink(resultDto.getTableContent(),envId,uuid,ScriptConstant.DATA_SET_LINK_BY_SCRIPT);
  }

  private void createScriptInputSetVersion(List<AtuScriptInputSetVersion> scriptInputSetVersionList, String scriptId,
                                           String envId, String path, Integer versionId){
    AtuScriptInputSetVersion atuScriptInputSetVersion = new AtuScriptInputSetVersion();
    atuScriptInputSetVersion.setId(UUIDUtil.create32UUID());
    atuScriptInputSetVersion.setCreatedBy(NKSecurityContext.getUserId());
    atuScriptInputSetVersion.setCreatedTime(new Date());
    String newUrl = copyJSONFile(path, scriptId, FileBusinessTypeEnum.COMMON_SCRIPT_VERSION_INPUT_DATA_SET);
    atuScriptInputSetVersion.setDataUrl(newUrl);
    atuScriptInputSetVersion.setEnvId(envId);
    atuScriptInputSetVersion.setScriptVersionId(versionId);
    atuScriptInputSetVersion.setScriptId(scriptId);
    scriptInputSetVersionList.add(atuScriptInputSetVersion);
  }

  private void createInputSet(List<AtuInputSet> inputSetList, String scriptId,
                              String envId, String path){
    //复制一份输入项文件到正式表

    AtuInputSet atuInputSet = new AtuInputSet();
    atuInputSet.setId(UUIDUtil.create32UUID());
    atuInputSet.setCreatedBy(NKSecurityContext.getUserId());
    atuInputSet.setCreatedTime(new Date());
    atuInputSet.setUpdatedBy(NKSecurityContext.getUserId());
    atuInputSet.setUpdatedTime(new Date());
    String newUrl = copyJSONFile(path, scriptId, FileBusinessTypeEnum.INPUT_DATA_SET);
    atuInputSet.setDataUrl(newUrl);
    atuInputSet.setEnvId(envId);
    atuInputSet.setScriptId(scriptId);
    inputSetList.add(atuInputSet);
  }


  private void updateSaveAndDeployInputData(AtuScriptVersion atuScriptVersion) {
    long start = System.currentTimeMillis();
    //查系统相关环境关联表
    List<String> envIds = projectFeignClient.selectEnvIds(atuScriptVersion.getProjectId());
    if (envIds.size()!=0) {
      //查询草稿表
      AtuScriptInputSet atuScriptInputSet = new AtuScriptInputSet();
      atuScriptInputSet.setScriptId(atuScriptVersion.getScriptId());
      SqlOrderBy sqlOrderBy=new SqlOrderBy();
      sqlOrderBy.asc(ScriptConstant.SCRIPT_INPUT_ENV_ID);
      List<AtuScriptInputSet> query = atuScriptInputSetService.query(atuScriptInputSet,sqlOrderBy);

      if (query.size() > 0) {
        //删除正式表数据，将删除操作下移，因为可能存在一种情况，就是修改脚本，不改输入项用例
        AtuInputSet atuInputSetDel=new AtuInputSet();
        atuInputSetDel.setScriptId(atuScriptVersion.getScriptId());
        attachmentFeignClient.deleteFileByObjId(atuScriptVersion.getScriptId(), FileBusinessTypeEnum.INPUT_DATA_SET.getCode());
        atuInputSetService.deleteByExample(atuInputSetDel);
        //批量更新list
        ArrayList<AtuScriptInputSetVersion> scriptInputSetVersionUpdateList = new ArrayList<>();
        ArrayList<AtuInputSet> inputSetUpdateList = new ArrayList<>();
        for (AtuScriptInputSet scriptInputSet : query) {
          if (envIds.contains(scriptInputSet.getEnvId())) {
            //更新草稿表版本表
            AtuScriptInputSetVersion atuScriptInputSetVersion = new AtuScriptInputSetVersion();
            String uuid = UUIDUtil.create32UUID();
            atuScriptInputSetVersion.setId(uuid);
            atuScriptInputSetVersion.setCreatedBy(NKSecurityContext.getUserId());
            atuScriptInputSetVersion.setCreatedTime(new Date());
            // 复制文件
            String newDataUrl = copyJSONFile(scriptInputSet.getDataUrl(), atuScriptVersion.getScriptId(), FileBusinessTypeEnum.COMMON_SCRIPT_VERSION_INPUT_DATA_SET);
            atuScriptInputSetVersion.setDataUrl(newDataUrl);
            atuScriptInputSetVersion.setEnvId(scriptInputSet.getEnvId());
            atuScriptInputSetVersion.setScriptVersionId(atuScriptVersion.getVersionId());
            atuScriptInputSetVersion.setScriptId(atuScriptVersion.getScriptId());
            scriptInputSetVersionUpdateList.add(atuScriptInputSetVersion);

            //同步草稿表数据到正式表
            AtuInputSet atuInputSet = new AtuInputSet();
            BeanUtils.copyProperties(scriptInputSet, atuInputSet);
            //复制输入项文件到正式表
            String newUrl = copyJSONFile(atuScriptInputSetVersion.getDataUrl(), atuScriptVersion.getScriptId(), FileBusinessTypeEnum.INPUT_DATA_SET);
            atuInputSet.setDataUrl(newUrl);
            atuInputSet.setUpdatedBy(NKSecurityContext.getUserId());
            atuInputSet.setUpdatedTime(new Date());
            inputSetUpdateList.add(atuInputSet);
            AtuInputSetResultDto resultDto = downloadFileUtils.downloadFile(atuScriptInputSetVersion.getDataUrl());
            dataMgrUtils.queryInputAndDataLink(resultDto.getTableContent(),scriptInputSet.getEnvId(),atuInputSet.getId(),ScriptConstant.DATA_SET_LINK_BY_CASE);
          }
        }
        if (!CollectionUtils.isEmpty(scriptInputSetVersionUpdateList)) {
          atuScriptInputSetVersionService.insertByBatch(scriptInputSetVersionUpdateList);
        }
        atuInputSetService.insertByBatch(inputSetUpdateList);
      }
    } else {
      throw new InvalidException("输入项数据为空，请先保存输入项！");
    }
    logger.debug("updateSaveAndDeployInputData 耗时：{}", System.currentTimeMillis() - start);
  }

  @Override
  public Map<String, Object> checkPlanData(AtuScriptInfoFeignDto dto) {
    Map<String,Object> map = new HashMap<>();
    //1、校验用例集中的用例是否大于0
    //场景脚本中的脚本
    List<AtuScriptInfo> scriptInfoList = this.atuSceneNodeInfoService.queryScriptType(dto.getScriptId());
    //脚本去重
    Set<String> set = new HashSet<>(dto.getScriptId());
    scriptInfoList.forEach( one -> {set.add(one.getId());});
    List<String> scriptList = new ArrayList<>(set);
    //查询所有脚本
    List<AtuScriptInfo> resultQuery = this.atuScriptInfoService.queryScriptByIds(scriptList);
    map.put(ScriptConstant.CASE_NUM,resultQuery.size());

    //3、用例集中所有用例的类型
    AtuScriptInfoResultDto checkDto = checkScriptType(resultQuery);
    map.put(ScriptConstant.HAS_AND,checkDto.isHasAndroid());
    map.put(ScriptConstant.HAS_IOS,checkDto.isHasIOS());
    map.put(ScriptConstant.HAS_PC,checkDto.isHasPC());
    map.put(ScriptConstant.HAS_MOB,checkDto.isHasMob());

    //4、校验app是否被删
    List<String> appIds = new ArrayList<>();
    List<AppList> appAliveList = new ArrayList<>();
    if (dto.getAppLists()!=null && dto.getAppLists().size() > 0){
      for (AppList appList : dto.getAppLists()) {
        appIds.add(appList.getAppId());
      }
      List<App> apps = this.appService.checkAppAlive(appIds);
      for (App app : apps) {
        AppList appAlive = new AppList();
        appAlive.setAppId(app.getId());
        appAlive.setAppPackage(app.getPackageName());
        appAlive.setPlatformType(app.getPlatform());
        appAliveList.add(appAlive);
      }
    }
    //未删的软件
    map.put(ScriptConstant.APP_ALIVE,appAliveList);
    return map;
  }

  @Override
  public AtuScriptInfoResultDto checkScriptList(List<String> scriptList) {
    //场景脚本中的脚本
    Map<String, String> scriptMap = new HashMap<>();
    List<AtuScriptInfo> scriptInfoList = this.atuSceneNodeInfoService.queryScriptType(scriptList);
    List<AtuSceneInfo> sceneInfoList = atuSceneInfoService.querySceneByList(scriptList);
    if (sceneInfoList != null && sceneInfoList.size() > 0) {
      sceneInfoList.forEach(one -> {
        scriptMap.put(one.getId(), one.getSceneName());
      });
    }
    //脚本去重
    Set<String> set = new HashSet<>(scriptList);
    scriptInfoList.forEach(one -> {
      set.add(one.getId());
    });
    List<String> list = new ArrayList<>(set);
    //查询所有脚本
    List<AtuScriptInfo> resultQuery = this.atuScriptInfoService.queryScriptByIds(list);
    AtuScriptInfoResultDto result = new AtuScriptInfoResultDto();
    if (resultQuery != null && resultQuery.size() > 0) {
      resultQuery.forEach(one -> {
        scriptMap.put(one.getId(), one.getScriptName());
      });
      result = checkScriptType(resultQuery);
      result.setScriptMap(scriptMap);
    }
    return result;
  }

  @Override
  public Integer updatePrincipal(PrincipalUpdateDto dto) {
    if (dto.getScriptList().size() == 0) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_NULL_ERROR);
    }
    Long requestUserId = RequestUtil.getRequestUserId();
    dto.setUpdatedBy(String.valueOf(requestUserId));
    dto.setUpdatedTime(new Date());
    Integer result = 0;
    if (dto.getScene()){
      //场景
      result = this.atuSceneInfoService.updatePrincipal(dto);
    }else{
      result = this.atuScriptInfoService.updatePrincipal(dto);
    }
    return result;
  }

  @Override
  public PlanScriptPageDto queryScriptData(PlanPageQueryDto queryDto) {
    AtuScriptInfoResultDto resultDto = checkScriptList(queryDto.getAllList());
    PlanScriptPageDto pageDto = new PlanScriptPageDto();
    pageDto.setInfoDto(resultDto);
    //分页信息
    String setName = null;
    if (queryDto.getSetName()!=null && !queryDto.getSetName().equals("")){
      setName= queryDto.getSetName();
    }
    List<AtuCaseScriptResultDto> resultList = this.caseDataSetService.queryScriptPage(queryDto.getAllList(),setName);
    pageDto.setResultDtoList(resultList);
    return pageDto;
  }

  @Override
  public String queryScriptCode(Map<String, String> scriptMap) {
    String scriptId = "";
    if (scriptMap.get(ScriptConstant.UUID) != null && !scriptMap.get(ScriptConstant.UUID).equals("")) {
      scriptId = scriptMap.get(ScriptConstant.UUID);
    }
    if (scriptMap.get(ScriptConstant.TYPE) != null && !scriptMap.get(ScriptConstant.TYPE).equals("")) {
      String type = scriptMap.get(ScriptConstant.TYPE);
      if (type.equals(ScriptConstant.STR_FIVE)) {
        AtuSceneInfo sceneInfo = this.atuSceneInfoService.findByPrimaryKey(scriptId);
        if (sceneInfo != null) {
          putScriptCodeCache();
          return sceneInfo.getScriptCode();
        }
      } else {
        AtuScriptInfo info = this.atuScriptInfoService.findByPrimaryKey(scriptId);
        if (info != null) {
          putScriptCodeCache();
          return info.getScriptCode();
        }
      }
    }
    return null;
  }


  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public String saveScriptData(ScriptInputTableDto dto) {
    StringBuilder path = new StringBuilder();
    String scriptId = dto.getScriptId();
    path.append(generateScriptFileAndUpload(dto,scriptId, FileBusinessTypeEnum.COMMON_SCRIPT));
    //编辑已有脚本
    if (StringUtils.hasText(scriptId)) {
      //更新脚本数据
      AtuScriptInfo byPrimaryKey = atuScriptInfoService.findByPrimaryKey(scriptId);
      if (null != byPrimaryKey && ScriptConstant.STR_ZERO.equals(byPrimaryKey.getIsDeleted())) {
        AtuScriptInfo scriptInfo = new AtuScriptInfo();
        BeanUtils.copyProperties(byPrimaryKey, scriptInfo);
        scriptInfo.setDataUrl(path.toString());
        atuScriptInfoService.updateByPrimaryKey(scriptInfo);
      }
    }
    return path.toString();
  }


  /**
   * 复制脚本文件
   *
   * @param autoScript
   * @return
   */
  private Map<String,String> copyScriptFile(AtuScriptInfo autoScript) {
    Map<String,String> res = new HashMap<>();
    String scriptUrl = autoScript.getScriptUrl();
    String dataUrl = autoScript.getDataUrl();
    //复制脚本文件
    if (StringUtils.hasText(scriptUrl)) {
      //下载原脚本文件
      JSONObject scriptData = downloadScriptFile(scriptUrl);
      //复制新脚本文件
      String copyScriptStr = copyScriptJsonFile(scriptData, autoScript);
      // 图片复制
      JSONObject jsonObject = JSON.parseObject(copyScriptStr, JSONObject.class);
      String scriptType = autoScript.getScriptType();
      FileBusinessTypeEnum businessCode = null;
      if (scriptType.equals(SCRIPT_TYPE_ANDROID) || scriptType.equals(SCRIPT_TYPE_IOS)) {
        businessCode = FileBusinessTypeEnum.MOBILE_RECORD_SCREENSHOT;
      } else if (scriptType.equals(SCRIPT_TYPE_BS) || scriptType.equals(SCRIPT_TYPE_CS)) {
        businessCode = FileBusinessTypeEnum.PC_RECORD_SCREENSHOT;
      }
      getIamgeUrlByJsonArray(autoScript.getId(), jsonObject.get("commands"), new HashMap<>(), true, businessCode);
      copyScriptStr = jsonObject.toJSONString();
      String newScriptPath = generateScriptFileAndUpload(copyScriptStr, autoScript.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      res.put(ScriptConstant.SCRIPT_URL, newScriptPath);
    }
    //复制数据文件
    if (StringUtils.hasText(dataUrl)) {
      //下载原脚本文件
      JSONObject scriptData = downloadScriptFile(dataUrl);
      //复制新脚本文件
      String copyScriptStr = copyScriptJsonFile(scriptData, autoScript);
      String newDataPath = generateScriptFileAndUpload(copyScriptStr, autoScript.getId(), FileBusinessTypeEnum.COMMON_SCRIPT);
      res.put(ScriptConstant.DATA_URL, newDataPath);
    }
    return res;
  }

  /**
   * 替换脚本ID为副本ID
   *
   * @param scriptData   原来脚本数据
   * @param newScript    现在脚本信息
   * @return
   */
  private String copyScriptJsonFile(JSONObject scriptData, AtuScriptInfo newScript) {
    String result = "";
    if (null != scriptData) {
      Object clone = scriptData.clone();
      JSONObject map = (JSONObject) clone;
      map.put(ScriptConstant.UUID, newScript.getId());
      result = JSON.toJSONString(map);
    }
    return result;
  }

  /**
   * 获取复制的脚本
   *
   * @param script
   * @param query
   * @return
   */
  private AtuScriptInfo getCopyScript(AtuScriptInfo script, AtuScriptInfoMoveDto query) {
    AtuScriptInfo copyScript = new AtuScriptInfo();
    BeanUtils.copyProperties(script, copyScript);  //复制脚本，设置复制的脚本信息
    copyScript.setGroupId(query.getGroupId());
    copyScript.setLatestVersionId(0);
    AtuScriptGroup atuScriptGroup = checkScriptGroup(query.getGroupId());
    List<AtuScriptInfo> scripts = atuScriptInfoService.findScriptCopyNum(atuScriptGroup.getProjectId(), "^" + tranScriptName(script.getScriptName()) + "-副本\\([0-9]+\\)$");
    Integer x = 1;
    if (!CollectionUtils.isEmpty(scripts)) {   //有-副本(x)字样
      Optional<Integer> optional = scripts.stream().map(item -> Integer.parseInt(item.getScriptName().replace(script.getScriptName() + "-副本(", "").replace(")", ""))).max(new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
          if (o1 >= o2) {
            return 1;
          }
          return -1;
        }
      });
      if (optional.isPresent()) {
        x = optional.get() + 1;
      }
    }
    String scriptName = String.format(ScriptConstant.COPY_SCRIPT_NAME,script.getScriptName(),x);
    copyScript.setScriptName(scriptName);
    String uuid = UUIDUtil.create32UUID();
    copyScript.setId(uuid);
    copyScript.setCreatedBy(NKSecurityContext.getUserId());
    copyScript.setTenantId(NKSecurityContext.getTenantId());
    copyScript.setCreatedTime(new Date());
    copyScript.setUpdatedBy(NKSecurityContext.getUserId());
    copyScript.setUpdatedTime(copyScript.getCreatedTime());
    return copyScript;
  }

  /**
   * 脚本名称含括号处理（脚本重名规则相关
   * @param scriptName
   * @return
   */
  private String tranScriptName(String scriptName) {
    StringBuilder sb = new StringBuilder();
    char[] chars = scriptName.toCharArray();
    for (char c :chars){
      if (c == '(' || c == ')' || c == '|' || c == '*' || c == '.' || c == '+') {
        sb.append("\\");
      }
      sb.append(c);
    }
    return sb.toString();
  }

  /**
   * 处理查询参数
   *
   * @param query
   * @return
   */
  private AtuScriptInfoQueryDto handleQueryParam(AtuScriptInfoQueryDto query) {
    AtuScriptInfoQueryDto res = new AtuScriptInfoQueryDto();
    BeanUtils.copyProperties(query, res);
    //创建人查询参数修改
    String creatorName = query.getCreator();
    if (StringUtils.hasText(creatorName)) {
      List<String> creatorIds = getUserIds(creatorName);
      if (CollectionUtils.isEmpty(creatorIds)) {
        return null;
      }
      res.setCreatorIds(creatorIds);
    }
    // 脚本负责人
    String principal = query.getPrincipal();
    if (StringUtils.hasText(principal)) {
      List<String> principalIds = getUserIds(principal);
      if (CollectionUtils.isEmpty(principalIds)) {
        return null;
      }
      res.setPrincipalIds(principalIds);
    }
    // 脚本修改人
    String updatedName = query.getUpdatedName();
    if (StringUtils.hasText(updatedName)) {
      List<String> updatedBys = getUserIds(updatedName);
      if (CollectionUtils.isEmpty(updatedBys)) {
        return null;
      }
      res.setUpdatedBys(updatedBys);
    }
    // 创建时间
    String createdTimeStart = query.getCreatedTimeStart();
    if (StringUtils.hasText(createdTimeStart)) {
      Date startCreatedTime = null;
      try {
        startCreatedTime = DateUtil.parse(createdTimeStart+ ScriptConstant.BEGIN_TIME,ScriptConstant.TIME_PATTERN);

      } catch (ParseException e) {
        logger.error("时间转换异常，createdTimeStart，{}，e,{}",createdTimeStart,e.getMessage());
        throw new PlatformRuntimeException(ScriptCaseAppError.PARSE_DATE_ERROR);
      }
      res.setStartCreatedTime(startCreatedTime);
    }
    String createdTimeEnd = query.getCreatedTimeEnd();
    if (StringUtils.hasText(createdTimeEnd)) {
      Date endCreatedTime = null;
      try {
        endCreatedTime = DateUtil.parse(createdTimeEnd+ScriptConstant.END_TIME,ScriptConstant.TIME_PATTERN);

      } catch (ParseException e){
        logger.error("时间转换异常，createdTimeEnd，{}，e,{}",createdTimeEnd,e.getMessage());
        throw new PlatformRuntimeException(ScriptCaseAppError.PARSE_DATE_ERROR);
      }
      res.setEndCreatedTime(endCreatedTime);
    }
    // 更新时间
    String updatedTimeStart = query.getUpdatedTimeStart();
    if (StringUtils.hasText(updatedTimeStart)) {
      Date startUpdatedTime = null;
      try{
        startUpdatedTime = DateUtil.parse(updatedTimeStart+ ScriptConstant.BEGIN_TIME,ScriptConstant.TIME_PATTERN);
      }catch (ParseException e){
        logger.error("时间转换异常，updatedTimeStart，{}，e,{}",updatedTimeStart,e.getMessage());
        throw new PlatformRuntimeException(ScriptCaseAppError.PARSE_DATE_ERROR);
      }
      res.setStartUpdatedTime(startUpdatedTime);
    }
    String updatedTimeEnd = query.getUpdatedTimeEnd();
    if (StringUtils.hasText(updatedTimeEnd)) {
      Date endUpdatedTime = null;
      try {
        endUpdatedTime = DateUtil.parse(updatedTimeEnd+ScriptConstant.END_TIME,ScriptConstant.TIME_PATTERN);
      } catch (ParseException e) {
        logger.error("时间转换异常，updatedTimeEnd，{}，e,{}",updatedTimeEnd,e.getMessage());
        throw new PlatformRuntimeException(ScriptCaseAppError.PARSE_DATE_ERROR);
      }
      res.setEndUpdatedTime(endUpdatedTime);
    }
    //目录查询参数修改
    String groupId = query.getGroupId();
    if (StringUtils.hasText(groupId)) {
      List<AtuScriptGroup> list = atuScriptGroupService.queryChildrenTreeList(groupId);
      if (!CollectionUtils.isEmpty(list)) {
        List<String> groupIds = list.stream().map(item->item.getId()).collect(Collectors.toList());
        res.setGroupId(null);
        res.setGroupIds(groupIds);
      }
    }
    return res;
  }

  /**
   * 根据用户名称模糊查询用户id列表
   *
   * @param name
   * @return
   */
  private List<String> getUserIds(String name) {
    UserQueryDto userQueryDto = new UserQueryDto();
    userQueryDto.setUserChnName(name);
    List<String> userList = platformFeignClient.selectUserId(userQueryDto);
    return userList;
  }

  /**
   * 处理分页查询参数
   *
   * @param query
   */
  private void handlePageParam(QueryByPage<AtuScriptInfoQueryDto> query) {
    if (query.getPageNo() <= 0) {
      query.setPageNo(1);
    }
    if (query.getPageSize() <= 0 || query.getPageSize() > 500) {
      query.setPageSize(500);
    }
    OrderBy sort = query.toSqlOrderBy();
    if (sort != null && sort.isNotEmpty() && StringUtils.hasText(sort.toString())) {
      PageMethod.orderBy(sort.toString());
    }
  }

  /**
   * 生成脚本版本
   * @param scriptInfo
   * @return
   */
  private AtuScriptVersion generateScriptVersion(AtuScriptInfo scriptInfo) {
    Long increment = redisTemplate.opsForValue().increment(RedisConstant.REDIS_SCRIPT_VERSION + scriptInfo.getId());
    int count = 0;
    if (increment != null && scriptInfo.getLatestVersionId() != null && increment > scriptInfo.getLatestVersionId()) {
      //默认是1
      count = (int) (increment - 1);
    } else {
      if (scriptInfo.getLatestVersionId() != null) {
        // redis数据丢失处理
        count = scriptInfo.getLatestVersionId();
      }
      redisTemplate.opsForValue().set(RedisConstant.REDIS_SCRIPT_VERSION, count);
    }
    int third = count % 10;
    int second = count / 10 % 10;
    int first = count / 100 + 1;
    String versionName = first + "." + second + "." + third;
    AtuScriptVersion atuScriptVersion = new AtuScriptVersion();
    BeanUtils.copyProperties(scriptInfo,atuScriptVersion);
    atuScriptVersion.setScriptId(scriptInfo.getId());
    atuScriptVersion.setUrl(scriptInfo.getScriptUrl());
    atuScriptVersion.setDataUrl(scriptInfo.getDataUrl());
    atuScriptVersion.setVersionId(++count);
    atuScriptVersion.setVersionName(versionName);
    return atuScriptVersion;
  }

  //刷脚本版本到redis里面
  @PostConstruct
  public void init() {
    long beginTime = System.currentTimeMillis();
    if(flush_redis){
      logger.info("---------------------Update script version:begin---------------------");
      List<AtuScriptVersionResultDto> resultDtoList = this.atuScriptVersionService.queryCountNum();

      for (AtuScriptVersionResultDto resultDto : resultDtoList) {
        String redisKey = RedisConstant.REDIS_SCRIPT_VERSION + resultDto.getScriptId();
        Object redisValue = redisTemplate.opsForValue().get(redisKey);
        if (redisValue == null) {
          redisTemplate.opsForValue().set(redisKey, resultDto.getCountNum());
        }
      }
      long endTime = System.currentTimeMillis();
      logger.info("---------------------Update script version:end:【{}ms】---------------------",endTime - beginTime);
    }else{
      logger.info("非初次重启，数据不做刷新");
    }

  }




  /**
   * 检查所选目录是否为存在的叶子结点
   * @param groupId
   * @return
   */
  private AtuScriptGroup checkScriptGroup(String groupId) {
    AtuScriptGroup atuScriptGroup = atuScriptGroupService.findByPrimaryKey(groupId);
    if (null == atuScriptGroup) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_TREE_NOT_EXIST);
    }
    if (ScriptConstant.STR_ZERO.equals(atuScriptGroup.getIsLeaf())) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_NODE_NOT_LEAF);
    }
    return atuScriptGroup;
  }

  /**
   * 创建脚本实体
   * @param addScript
   * @return
   */
  private AtuScriptInfo createAtuScript(AtuScriptInfoAddDto addScript) {
    AtuScriptInfo script = new AtuScriptInfo();
    BeanUtils.copyProperties(addScript, script);
    script.setIsDeleted(ScriptConstant.STR_ZERO);
    script.setAppId(addScript.getAppId());
    script.setAppPackage(addScript.getPackageName());
    script.setCreatedBy(NKSecurityContext.getUserId());
    script.setTenantId(NKSecurityContext.getTenantId());
    script.setCreatedTime(new Date());
    script.setUpdatedTime(script.getCreatedTime());
    script.setUpdatedBy(script.getCreatedBy());
    return script;
  }

  /**
   * 生成脚本文件并上传
   * @param scriptJsonStr
   * @return
   */
  @Override
  public String generateScriptFileAndUpload(Object scriptJsonStr, String objId, FileBusinessTypeEnum businessCode) {
    long start = System.currentTimeMillis();
    File file = pathUtil.objectToJsonFile(scriptJsonStr);
    try {
      NKFile nkFile = simpleStorageService.upload(NKSecurityContext.getTenantId(), file, objId, businessCode);
      String path = pathUtil.pathToId(NKSecurityContext.getTenantId(), nkFile.getId());
      logger.debug("生成脚本文件并上传耗时：{}", System.currentTimeMillis() - start);
      return path;
    } catch (FileUploadException e) {
      logger.error("上传脚本文件出错", e);
      throw new InvalidException("上传脚本文件出错");
    } finally {
      boolean delete = file.delete();
      if (!delete) {
        logger.error("删除文件失败");
      }
    }
  }
    /**
     * 获取高级查询筛选项
     * @return
     */
    @Override
    public AdvancedQueryOptions advancedQueryOptions(String projectId) {
      AdvancedQueryOptions options = new AdvancedQueryOptions();
      options.setManagerList(new ArrayList<>());
      options.setCreatorList(new ArrayList<>());
      options.setUpdaterList(new ArrayList<>());
      List<String> mangerList = atuScriptInfoService.selectManagerByProject(projectId);
      Set<Long> userIds = new HashSet<>();
      if (!CollectionUtils.isEmpty(mangerList)) {
        mangerList.forEach(id -> {
          if (id.length() <= 20) {
            userIds.add(Long.valueOf(id));
          }
        });
      }
      List<String> creatorList = atuScriptInfoService.selectCreatorByProject(projectId);
      if (!CollectionUtils.isEmpty(creatorList)) {
        creatorList.forEach(id -> {
          if (id.length() <= 20) {
            userIds.add(Long.valueOf(id));
          }
        });
      }
      List<String> updaterList = atuScriptInfoService.selectUpdaterByProject(projectId);
      if (!CollectionUtils.isEmpty(updaterList)) {
        updaterList.forEach(id -> {
          if (id.length() <= 20) {
            userIds.add(Long.valueOf(id));
          }
        });
      }
      if (CollectionUtils.isEmpty(userIds)){
        return options;
      }
      List<UserDTO> userDTOS = monsterCommonFeignClient.getUserByIds(new ArrayList<>(userIds));
      userDTOS.forEach(user -> {
        if (mangerList.contains(user.getId().toString())) {
          options.getManagerList().add(UserOptions.userDTOtoUserOptions(user));
        }
        if (creatorList.contains(user.getId().toString())) {
          options.getCreatorList().add(UserOptions.userDTOtoUserOptions(user));
        }
        if (updaterList.contains(user.getId().toString())) {
          options.getUpdaterList().add(UserOptions.userDTOtoUserOptions(user));
        }
      });
      return options;
    }

  private JSONObject downloadScriptFile(String url) {
    String[] resultPath = pathUtil.idToPath(url);
    InputStream inputStream = null;
    JSONObject scriptData = null;
    try {
      inputStream = simpleStorageService.downloadAsStream(resultPath[0], "/" + resultPath[1]);
      scriptData = pathUtil.getFileContent(inputStream, JSONObject.class);
    } catch (FileDownloadException e) {
      logger.error("读取原脚本文件失败，失败原因", e);
      throw new PlatformRuntimeException(new ErrorMessage("读取原脚本文件失败"));
    } finally {
      if (null != inputStream) {
        try {
          inputStream.close();
        } catch (IOException e) {
          logger.error("finally处理失败",e);
        }
      }
    }
    return scriptData;
  }

  /**
   * 删除服务器端脚本文件
   * @param url
   */
  private void deleteFile(String url) {
    String[] pathData = pathUtil.idToPath(url);
    try {
      simpleStorageService.delete(pathData[0], "/" + pathData[1]);
    } catch (Exception e) {
      throw new PlatformRuntimeException(new ErrorMessage("文件删除失败"));
    }
  }

  public AtuScriptInfoResultDto checkScriptType(List<AtuScriptInfo> scriptList) {
    //是否含有PC/接口的用例
    boolean hasPcScript = false;
    //是否含有移动用例
    boolean hasMobScript = false;
    //是否含有安卓用例
    boolean hasAndroidScript = false;
    //是否含有IOS用例
    boolean hasIOSScript = false;
    //是否含有B/S用例
    boolean hasBSScript = false;
    //是否含有C/S用例
    boolean hasCSScript = false;
    //是否含有接口用例
    boolean hasAPIScript = false;

    for (AtuScriptInfo scriptInfo : scriptList) {
      switch (scriptInfo.getScriptType()){
        case ScriptConstant.STR_ZERO:
          hasAPIScript = true;
          hasPcScript = true;
          break;
        case ScriptConstant.STR_ONE:
          hasBSScript = true;
          hasPcScript = true;
          break;
        case ScriptConstant.STR_TWO:
          hasCSScript = true;
          hasPcScript = true;
          break;
        case ScriptConstant.STR_THREE:
          hasMobScript = true;
          hasAndroidScript = true;
          break;
        case ScriptConstant.STR_FOUR:
          hasMobScript = true;
          hasIOSScript = true;
          break;
      }
    }

    AtuScriptInfoResultDto dto = new AtuScriptInfoResultDto();
    dto.setHasPC(hasPcScript);
    dto.setHasMob(hasMobScript);
    dto.setHasAndroid(hasAndroidScript);
    dto.setHasIOS(hasIOSScript);
    dto.setHasAPI(hasAPIScript);
    dto.setHasBS(hasBSScript);
    dto.setHasCS(hasCSScript);
    return dto;
  }

  private void createdCodeAndInsertData(AtuScriptInfo scriptInfo) {
    String proId = scriptInfo.getProjectId();
    ResultWrapper<Map<String, String>> wrapper = projectFeignClient.feignQueryProData(proId);
    Map<String, String> data = wrapper.getData();
    StringBuilder stringBuilder = new StringBuilder();
    String code = "";
    if (data.get(ScriptConstant.CODE) == null) {
      throw new PlatformRuntimeException(ScriptCaseAppError.SYSTEM_NUM_IS_NULL);
    } else {
      code = data.get(ScriptConstant.CODE);
    }
    stringBuilder.append(code);
    //脚本：系统缩写_UD00001
    List<Integer> integers = atuBusinessNoApiService.genBusinessNo(proId, ScriptConstant.SCRIPT_CODE_UD, 1);
    String format = String.format(ScriptConstant.STR_FORMAT, integers.get(0));
    stringBuilder.append(ScriptConstant.SYS_UD).append(format);
    //设置脚本编号
    scriptInfo.setScriptCode(stringBuilder.toString());
    redisTemplate.opsForValue().set(ScriptConstant.SCRIPT_CODE + scriptInfo.getId(), stringBuilder.toString());
    atuScriptInfoService.insert(scriptInfo);   //插入数据库
  }

  private void putScriptCodeCache(){
    //刷缓存  一般脚本
    AtuScriptInfo scriptInfo = new AtuScriptInfo();
    scriptInfo.setTenantId(NKSecurityContext.getTenantId());
    List<AtuScriptInfo> scriptList = this.atuScriptInfoService.query(scriptInfo);
    for (AtuScriptInfo atuScriptInfo : scriptList) {
      if (atuScriptInfo.getScriptCode()!=null && !atuScriptInfo.getScriptCode().equals("")){
        redisTemplate.opsForValue().set(ScriptConstant.SCRIPT_CODE+ atuScriptInfo.getId(),atuScriptInfo.getScriptCode());
      }
    }
    //刷缓存  场景脚本
    AtuSceneInfo sceneInfo = new AtuSceneInfo();
    sceneInfo.setTenantId(NKSecurityContext.getTenantId());
    List<AtuSceneInfo> sceneList = this.atuSceneInfoService.query(sceneInfo);
    for (AtuSceneInfo atuSceneInfo : sceneList) {
      if (atuSceneInfo.getScriptCode()!=null && !atuSceneInfo.getScriptCode().equals("")) {
        redisTemplate.opsForValue().set(ScriptConstant.SCRIPT_CODE+ atuSceneInfo.getId(),atuSceneInfo.getScriptCode());
      }
    }
  }

  private List<AtuScriptInputSet> copyScriptInput(AtuScriptInfo scriptInfo,List<String> envIds,String newId) {
    List<AtuScriptInputSet> resultList = new ArrayList<>();
    //先查询原脚本中关联的输入项草稿信息
    AtuScriptInputSet queryDto = new AtuScriptInputSet();
    queryDto.setScriptId(scriptInfo.getId());
    List<AtuScriptInputSet> query = atuScriptInputSetService.query(queryDto);
    if (query != null && query.size() > 0) {
      //草稿表数据不为空
      for (AtuScriptInputSet targetDto : query) {
        if (envIds.contains(targetDto.getEnvId())){
          targetDto.setScriptId(newId);
          targetDto.setId(UUIDUtil.create32UUID());
          JSONObject jsonObject = downloadScriptFile(targetDto.getDataUrl());
          String newDataUrl = generateScriptFileAndUpload(jsonObject, newId, FileBusinessTypeEnum.COMMON_SCRIPT_INPUT_DATA_SET);
          targetDto.setDataUrl(newDataUrl);
          resultList.add(targetDto);
        }
      }
    }else {
      //草稿表为空就查询正式表
      AtuInputSet inputSet = new AtuInputSet();
      inputSet.setScriptId(scriptInfo.getId());
      List<AtuInputSet> atuInputSetList = atuInputSetService.query(inputSet);
      if (atuInputSetList != null && atuInputSetList.size() > 0) {
        for (AtuInputSet dto : atuInputSetList) {
          AtuScriptInputSet targetDto = new AtuScriptInputSet();
          BeanUtils.copyProperties(dto,targetDto);
          targetDto.setScriptId(newId);
          targetDto.setId(UUIDUtil.create32UUID());
          JSONObject jsonObject = downloadScriptFile(dto.getDataUrl());
          String newDataUrl = generateScriptFileAndUpload(jsonObject, newId, FileBusinessTypeEnum.COMMON_SCRIPT_INPUT_DATA_SET);
          targetDto.setDataUrl(newDataUrl);
          resultList.add(targetDto);
        }
      }
    }
    return resultList;
  }

  //复制JSON文件
  private String copyJSONFile(String dataUrl, String objId, FileBusinessTypeEnum fileBusinessTypeEnum){
    JSONObject jsonObject = downloadScriptFile(dataUrl);
    if (jsonObject != null){
      return generateScriptFileAndUpload(jsonObject, objId, fileBusinessTypeEnum);
    }
    return null;
  }
  
  private List<AtuScriptInputSet> createdFileByInputSet(String scriptId,String proId,String jsonString){
    List<AtuScriptInputSet> resultList = new ArrayList<>();
    List<String> envIds = projectFeignClient.selectEnvIds(proId);
    if (envIds != null && envIds.size()>0){
      //生成默认的输入项
      JSONObject jsonObject = atuScriptInputSetService.createDefaultInputSet(jsonString);
      if (jsonObject != null){
        for (String envId : envIds) {
          AtuScriptInputSet dto = new AtuScriptInputSet();
          dto.setId(UUIDUtil.create32UUID());
          dto.setScriptId(scriptId);
          dto.setEnvId(envId);
          String upload = generateScriptFileAndUpload(jsonObject, scriptId, FileBusinessTypeEnum.COMMON_SCRIPT_INPUT_DATA_SET);
          dto.setDataUrl(upload);
          dto.setVersion(null);
          Date date = new Date();
          dto.setCreatedTime(date);
          dto.setCreatedBy(NKSecurityContext.getUserId());
          dto.setUpdatedTime(date);
          dto.setUpdatedBy(NKSecurityContext.getUserId());
          resultList.add(dto);
        }
      }
    }
    return resultList;
  }

  //克隆标签
  public void cloneScriptLabel(AtuScriptInfo scriptInfo,String scriptId) {
    AtuScriptTag scriptTag = new AtuScriptTag();
    scriptTag.setScriptId(scriptInfo.getId());
    List<AtuScriptTag> query = this.atuScriptTagService.query(scriptTag);
    if (query != null && query.size() > 0) {
      List<AtuScriptTag> insertList = new ArrayList<>();
      for (AtuScriptTag atuScriptTag : query) {
        atuScriptTag.setScriptId(scriptId);
        insertList.add(atuScriptTag);
      }
      this.atuScriptTagService.insertByBatch(insertList);
    }
  }

  @Override
  public List<ApiScriptOptionVO> getUIScriptVOByIds(List<String> scriptIdList) {
    List<ApiScriptOptionVO> scriptVOList = atuScriptInfoService.queryScriptVOList(scriptIdList);
    fillScriptNameInfo(scriptVOList);
    return scriptVOList;
  }

  @Override
  public List<ApiScriptOptionVO> getUIScriptVOByCodeAndSystemId(String scriptCode, String systemId) {
    if (systemId == null && scriptCode == null) {
      return null;
    }
    List<ApiScriptOptionVO> scriptVOList = atuScriptInfoService.queryScriptVOByCodeAndSystemId(scriptCode, systemId);
    fillScriptNameInfo(scriptVOList);
    return scriptVOList;
  }

  private void fillScriptNameInfo(List<ApiScriptOptionVO> scriptVOList) {
    if (!CollectionUtils.isEmpty(scriptVOList)) {
      for (ApiScriptOptionVO apiScriptOptionVO : scriptVOList) {
        if (apiScriptOptionVO.getManagerId() != null) {
          apiScriptOptionVO.setManagerName(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, String.valueOf(apiScriptOptionVO.getManagerId())));
        }
        if (apiScriptOptionVO.getSystemNo() != null) {
          apiScriptOptionVO.setSystemName(entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM, String.valueOf(apiScriptOptionVO.getSystemNo())));
        }
      }
    }
  }
}
