package net.northking.cctp.scriptcase.api.scenescript.service;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
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.DefaultPagination;
import net.northking.cctp.common.db.OrderBy;
import net.northking.cctp.common.db.Pagination;
import net.northking.cctp.common.dto.AdvancedQueryOptions;
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.ApiAtsEnviromentFeign;
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.QueryOrderBy;
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.scenescript.bean.Node;
import net.northking.cctp.scriptcase.api.scenescript.bean.SceneScript;
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.caseDataSet.SetTreeDto;
import net.northking.cctp.scriptcase.dto.sceneScript.*;
import net.northking.cctp.scriptcase.enums.ErrorMessage;
import net.northking.cctp.scriptcase.enums.ScriptCaseAppError;
import net.northking.cctp.scriptcase.feign.AttachmentFeignClient;
import net.northking.cctp.scriptcase.feign.ExecutePlanFeignClient;
import net.northking.cctp.scriptcase.feign.PlatformFeignClient;
import net.northking.cctp.scriptcase.feign.ProjectFeignClient;
import net.northking.cctp.scriptcase.tools.DataMgrUtils;
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.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

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

@Service
public class AtuSceneScriptApiServiceImpl implements AtuSceneScriptApiService {

    private final static Logger logger = LoggerFactory.getLogger(AtuSceneScriptApiServiceImpl.class);

    @Autowired
    private AtuSceneInfoService atuSceneInfoService;

    @Autowired
    private EntityNameCache entityNameCache;

    @Autowired
    private PlatformFeignClient platformFeignClient;

    @Autowired
    private SceneDataVerifier sceneDataVerifier;

    @Autowired
    private AtuBusinessNoApiService atuBusinessNoApiService;

    @Autowired
    private MinioPathUtils pathUtil;

    @Autowired
    private SimpleStorageService simpleStorageService;

    @Autowired
    private LogRabbitMQPublisher logRabbitMQPublisher;

    @Autowired
    private AtuSceneNodeInfoService atuSceneNodeInfoService;

    @Autowired
    private AtuInputSetService atuInputSetService;

    @Autowired
    private AtuScriptInputSetService atuScriptInputSetService;

    @Autowired
    private ProjectFeignClient projectFeignClient;

    @Autowired
    private AtuCaseDataSetApiService atuCaseDataSetApiService;

    @Autowired
    private AtuCaseDataSetService atuCaseDataSetService;

    @Autowired
    private AtuScriptInfoService atuScriptInfoService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AtuScriptVersionService atuScriptVersionService;

    @Autowired
    private PlanRabbitMQPublisher planRabbitMQPublisher;

    @Autowired
    private ExecutePlanFeignClient executePlanFeignClient;



    @Autowired
    private DataMgrUtils dataMgrUtils;

    @Autowired
    private ApiAtsEnviromentFeign apiAtsEnviromentFeign;

    @Autowired
    MonsterCommonFeignClient monsterCommonFeignClient;

    @Autowired
    private AttachmentFeignClient attachmentFeignClient;

    @Override
    public Pagination<AtuSceneInfoDetailDto>
    pagingQuery(QueryByPage<AtuSceneScriptQueryDto> queryByPage) {
        QueryByPage<AtuSceneScriptPagingQueryDto> qty = new QueryByPage<>();
        qty.setQuery(new AtuSceneScriptPagingQueryDto());
        qty.getQuery().setTenantId(NKSecurityContext.getTenantId());
        qty.getQuery().setProjectIds(queryByPage.getQuery().getProjectId());
        String sceneName = queryByPage.getQuery().getSceneName();
        if (StringUtils.hasText(sceneName))
            sceneName = sceneName.replace("%", "\\%").replace("_", "\\_");
        qty.getQuery().setSceneName(sceneName);
        String keyword = queryByPage.getQuery().getKeyword();
        if (StringUtils.hasText(keyword))
            keyword = keyword.replace("%", "\\%").replace("_", "\\_");
        qty.getQuery().setKeyword(keyword);
        String createName = queryByPage.getQuery().getCreateName();
        List<String> createByNameIds = new ArrayList<>();
        if (StringUtils.hasText(createName)) {
            createByNameIds.add("-1");
            UserQueryDto userQueryDto = new UserQueryDto();
            userQueryDto.setTenantId(NKSecurityContext.getTenantId());
            userQueryDto.setUserChnName(createName);
            List<String> userList = platformFeignClient.selectUserId(userQueryDto);
            userList.forEach(userId -> {
                createByNameIds.add(userId);
            });
        }
        buildQty(qty,queryByPage);

        DefaultPagination<AtuSceneInfoDetailDto> pagination = new DefaultPagination();
        qty.getQuery().setCreatedByIds(createByNameIds);
        qty.setOrderByList(queryByPage.getOrderByList());
        if (queryByPage.getOrderByList().size() == 0) {
            QueryOrderBy qtyOrder = new QueryOrderBy("created_time", "DESC");
            List<QueryOrderBy> defaultOrderlist = new ArrayList<>();
            defaultOrderlist.add(qtyOrder);
            qty.setOrderByList(defaultOrderlist);
        }
        qty.setPageNo(queryByPage.getPageNo());
        qty.setPageSize(queryByPage.getPageSize());
        pagination.setPageSize(queryByPage.getPageSize());
        pagination.setPageNo(queryByPage.getPageNo());
        handlePageParam(qty);
        Page<AtuSceneInfoDetailDto> page = PageMethod.startPage(qty.getPageNo(), qty.getPageSize());
        List<AtuSceneInfoDetailDto> result = atuSceneInfoService.queryList(qty);
        for (AtuSceneInfoDetailDto sceneInfo : result) {
            sceneInfo.setCreatedName(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, sceneInfo.getCreatedBy()));
            sceneInfo.setUpdatedName(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, sceneInfo.getUpdatedBy()));
            sceneInfo.setProjectName(entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM, sceneInfo.getProjectId()));
            sceneInfo.setPrincipal(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER,sceneInfo.getPrincipalId()));
        }

        pagination.setRecords(result);
        pagination.setRecordCount(page.getTotal());
        return pagination;
    }

    private void buildQty(QueryByPage<AtuSceneScriptPagingQueryDto> qty, QueryByPage<AtuSceneScriptQueryDto> queryByPage) {
        if (StringUtils.hasText(queryByPage.getQuery().getPrincipal())) {
            List<String> principalIds = getUserIds(queryByPage.getQuery().getPrincipal());
            if (!CollectionUtils.isEmpty(principalIds)) {
                qty.getQuery().setPrincipalIds(principalIds);
            } else {
                principalIds.add("-1");
                qty.getQuery().setPrincipalIds(principalIds);
            }
        }
        if (StringUtils.hasText(queryByPage.getQuery().getCreatorId())) {
            qty.getQuery().setCreatorId(queryByPage.getQuery().getCreatorId());
        }
        if (StringUtils.hasText(queryByPage.getQuery().getUpdateBy())) {
            qty.getQuery().setUpdateBy(queryByPage.getQuery().getUpdateBy());
        }
        if (StringUtils.hasText(queryByPage.getQuery().getPrincipalId())) {
            qty.getQuery().setPrincipalId(queryByPage.getQuery().getPrincipalId());
        }


        if (!CollectionUtils.isEmpty(queryByPage.getQuery().getPrincipalIds())) {
            qty.getQuery().setPrincipalIds(queryByPage.getQuery().getPrincipalIds());
        }
        if (StringUtils.hasText(queryByPage.getQuery().getUpdatedName())) {
            List<String> updateBys = getUserIds(queryByPage.getQuery().getUpdatedName());
            if (!CollectionUtils.isEmpty(updateBys)) {
                qty.getQuery().setUpdatedBys(updateBys);
            } else {
                updateBys.add("-1");
                qty.getQuery().setUpdatedBys(updateBys);
            }
        }

        String createdTimeStart = queryByPage.getQuery().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);
            }
            qty.getQuery().setStartCreatedTime(startCreatedTime);
        }
        String createdTimeEnd = queryByPage.getQuery().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);
            }
            qty.getQuery().setEndCreatedTime(endCreatedTime);
        }
        // 更新时间
        String updatedTimeStart = queryByPage.getQuery().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);
            }
            qty.getQuery().setStartUpdatedTime(startUpdatedTime);
        }
        String updatedTimeEnd = queryByPage.getQuery().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);
            }
            qty.getQuery().setEndUpdatedTime(endUpdatedTime);
        }

    }

    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<AtuSceneScriptPagingQueryDto> 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());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String saveScript(AtuSaveSceneScriptDto saveSceneScriptDto) throws Exception {
        //场景脚本校验
        sceneDataVerifier.verify(saveSceneScriptDto);

        AtuSceneInfo atuSceneInfo = new AtuSceneInfo();
        atuSceneInfo.setId(saveSceneScriptDto.getId());
        if (StringUtils.hasText(saveSceneScriptDto.getDataJson())) {
            String uploadDataJson = JSONObject.parse(saveSceneScriptDto.getDataJson()).toString();
            String dataUrl = generateScriptFileAndUpload(uploadDataJson, atuSceneInfo.getId(), FileBusinessTypeEnum.SCENE_SCRIPT_INPUT_DATA_SET);
            atuSceneInfo.setDataUrl(dataUrl);
        }
        if (StringUtils.hasText(saveSceneScriptDto.getScriptJson())) {
            String uploadScriptJson = JSONObject.parse(saveSceneScriptDto.getScriptJson()).toString();
            String scriptUrl = generateScriptFileAndUpload(uploadScriptJson, atuSceneInfo.getId(), FileBusinessTypeEnum.SCENE_SCRIPT);
            atuSceneInfo.setScriptUrl(scriptUrl);

        }
        atuSceneInfo.setSceneName(saveSceneScriptDto.getSceneName());
        atuSceneInfo.setUpdatedBy(NKSecurityContext.getUserId());
        atuSceneInfo.setUpdatedTime(new Date());

        AtuSceneInfo s = atuSceneInfoService.findByPrimaryKey(saveSceneScriptDto.getId());
        if (s == null) {
            atuSceneInfo.setProjectId(saveSceneScriptDto.getProjectId());
            atuSceneInfo.setTenantId(NKSecurityContext.getTenantId());
            atuSceneInfo.setCreatedBy(NKSecurityContext.getUserId());
            atuSceneInfo.setCreatedTime(new Date());
            atuSceneInfo.setIsDeleted(0);
            atuSceneInfo.setCurrentVersionId(1);
            atuSceneInfo.setPrincipalId(NKSecurityContext.getUserId());
            //创建脚本编号 新增场景脚本
            createdCodeAndInsert(atuSceneInfo);
        } else {
            atuSceneInfoService.updateByPrimaryKey(atuSceneInfo);
        }

        //保护场景节点信息
        saveSceneNodeInfoService(atuSceneInfo.getId(), atuSceneInfo.getProjectId(), saveSceneScriptDto.getScriptJson());

        return saveSceneScriptDto.getId();
    }

    @Override
    public AtuSaveScriptAndCaseResVo saveScriptAndCase(AtuSaveSceneScriptAndGenCaseDto
                                                               caseDto) throws Exception {
        logger.info("---------------开始执行逻辑 service---------------");
        long execImplStart = System.currentTimeMillis();
        String uuid = UUIDUtil.create32UUID();
        //场景脚本校验
        long verifyStartTime = System.currentTimeMillis();
        AtuSaveSceneScriptDto saveSceneScriptDto = new AtuSaveSceneScriptDto();
        saveSceneScriptDto.setId(caseDto.getId());
        saveSceneScriptDto.setProjectId(caseDto.getProjectId());
        saveSceneScriptDto.setSceneName(caseDto.getSceneName());
        saveSceneScriptDto.setScriptJson(caseDto.getScriptJson());
        sceneDataVerifier.verify(saveSceneScriptDto);
        long verifyEndTime = System.currentTimeMillis();
        logger.info(uuid + "--------------------->场景信息校验耗时:" + (verifyEndTime - verifyStartTime));
        //保存场景脚本
        long infoStartTime = System.currentTimeMillis();
        AtuSceneInfo atuSceneInfo = new AtuSceneInfo();
        atuSceneInfo.setIsDeleted(0);
        atuSceneInfo.setProjectId(caseDto.getProjectId());
        atuSceneInfo.setTenantId(NKSecurityContext.getTenantId());
        atuSceneInfo.setId(caseDto.getId());
        atuSceneInfo.setSceneName(caseDto.getSceneName());

        String uploadScriptJson = JSONObject.parse(saveSceneScriptDto.getScriptJson()).toString();
        String scriptUrl = generateScriptFileAndUpload(uploadScriptJson, atuSceneInfo.getId(), FileBusinessTypeEnum.SCENE_SCRIPT);
        atuSceneInfo.setScriptUrl(scriptUrl);

        logger.debug("生成脚本版本并保存");
        AtuScriptVersion atuScriptVersion = generateScriptVersion(atuSceneInfo);
        logger.debug("新版本为：{}", atuScriptVersion.getVersionName());
        atuSceneInfo.setCurrentVersionId(atuScriptVersion.getVersionId());

        long infoEndTime = System.currentTimeMillis();
        logger.info(uuid + "--------------------->组装数据信息耗时:" + (infoEndTime - infoStartTime));
        //保存场景脚本信息
        saveSceneScript(atuSceneInfo,uploadScriptJson);
        //保存输入项文件
        long inputStartTime = System.currentTimeMillis();
        List<String> uploadList = saveInputSetByScene(caseDto, uploadScriptJson);
        long inputEndTime = System.currentTimeMillis();
        logger.info(uuid + "--------------------->保存场景输入项信息耗时:" + (inputEndTime - inputStartTime));
        //保存脚本版本信息
        atuScriptVersionService.insert(atuScriptVersion);

        // 插入用例集目录对象
        long caseDataSetStartTime = System.currentTimeMillis();
        SetTreeDto setTreeDto = new SetTreeDto();
        setTreeDto.setId(atuSceneInfo.getId());
        setTreeDto.setProjectId(atuSceneInfo.getProjectId());
        setTreeDto.setScriptName(atuSceneInfo.getSceneName());
        setTreeDto.setScriptType(ScriptConstant.SCRIPT_TYPE_SCENE);
        setTreeDto.setVersion(atuScriptVersion.getVersionName());
        atuCaseDataSetApiService.saveSceneSetTree(setTreeDto);
        long caseDataSetEndTime = System.currentTimeMillis();
        logger.info(uuid + "--------------------->保存用例集信息耗时:" + (caseDataSetEndTime - caseDataSetStartTime));

        AtuSaveScriptAndCaseResVo vo = new AtuSaveScriptAndCaseResVo();
        vo.setId(caseDto.getId());
        if (uploadList.size() != 0) {
            vo.setDataUrl(uploadList);
        }
        vo.setScriptUrl(scriptUrl);
        long execImplEnd = System.currentTimeMillis();
        logger.info(uuid + "--------------------->逻辑执行时间:" + (execImplEnd - execImplStart));
        return vo;
    }

    @Transactional
    public void saveSceneScript(AtuSceneInfo atuSceneInfo,String uploadScriptJson) {
        //保存场景节点信息
        long nodeStartTime = System.currentTimeMillis();
        saveSceneNodeInfoService(atuSceneInfo.getId(), atuSceneInfo.getProjectId(), uploadScriptJson);
        long nodeEndTime = System.currentTimeMillis();
        logger.info("--------------------->保存场景节点信息耗时:" + (nodeEndTime - nodeStartTime));

        AtuSceneInfo queryDto = new AtuSceneInfo();
        queryDto.setIsDeleted(0);
        queryDto.setProjectId(atuSceneInfo.getProjectId());
        queryDto.setTenantId(NKSecurityContext.getTenantId());
        queryDto.setId(atuSceneInfo.getId());

        List<AtuSceneInfo> query = atuSceneInfoService.query(queryDto);
        if (CollectionUtils.isEmpty(query)) {//新增场景脚本
            long saveInfoStartTime = System.currentTimeMillis();
            atuSceneInfo.setCreatedTime(new Date());
            atuSceneInfo.setCreatedBy(NKSecurityContext.getUserId());
            atuSceneInfo.setUpdatedTime(new Date());
            atuSceneInfo.setCurrentVersionId(1);
            atuSceneInfo.setUpdatedBy(NKSecurityContext.getUserId());
            atuSceneInfo.setPrincipalId(NKSecurityContext.getUserId());
            //创建脚本编号 新增场景脚本
            createdCodeAndInsert(atuSceneInfo);
            long saveInfoEndTime = System.currentTimeMillis();
            logger.info("--------------------->新增场景信息耗时:" + (saveInfoEndTime - saveInfoStartTime));
        } else {//编辑场景脚本
            long updateInfoStartTime = System.currentTimeMillis();
            String oldScriptUrl = query.get(0).getScriptUrl();
            deleteFile(oldScriptUrl);
            atuSceneInfo.setUpdatedTime(new Date());
            atuSceneInfo.setUpdatedBy(NKSecurityContext.getUserId());
            atuSceneInfoService.updateByPrimaryKey(atuSceneInfo);
            //发送队列通知输入项发送变动
            long updateInfoEndTime = System.currentTimeMillis();
            logger.info("--------------------->编辑场景信息耗时:" + (updateInfoEndTime - updateInfoStartTime));
            long sendMQStart = System.currentTimeMillis();
            planRabbitMQPublisher.updatePlanStatusMQ(atuSceneInfo.getId());
            long sendMQEnd = System.currentTimeMillis();
            logger.info("--------------------->发送队列耗时:" + (sendMQEnd - sendMQStart));
        }
    }

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

    /**
     * 生成脚本版本
     * @param sceneInfo
     * @return
     */
    private AtuScriptVersion generateScriptVersion(AtuSceneInfo sceneInfo) {
        Long increment = redisTemplate.opsForValue().increment(RedisConstant.REDIS_SCRIPT_VERSION + sceneInfo.getId());
        //默认是1
        int count = 0;
        if (increment != null) {
            count = (int) (increment - 1);
        }else {
            redisTemplate.opsForValue().set(RedisConstant.REDIS_SCRIPT_VERSION,0);
        }
        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(sceneInfo,atuScriptVersion);
        atuScriptVersion.setScriptId(sceneInfo.getId());
        atuScriptVersion.setScriptName(sceneInfo.getSceneName());
        atuScriptVersion.setUrl(sceneInfo.getScriptUrl());
        atuScriptVersion.setDataUrl(sceneInfo.getDataUrl());
        atuScriptVersion.setVersionId(++count);
        atuScriptVersion.setVersionName(versionName);
        return atuScriptVersion;
    }

    private String fileUploadByObject(Object scriptJsonStr, String obj, FileBusinessTypeEnum businessCode) {
        File file = pathUtil.objectToJsonFile(scriptJsonStr);
        try {
            NKFile nkFile = simpleStorageService.upload(NKSecurityContext.getTenantId(), file, true, obj, businessCode);
            String path = nkFile.getId();
            return path;
        } catch (FileUploadException e) {
            return null;
        } finally {
            if(!file.delete())
                logger.debug("generateScriptFileAndUpload: 上传文件成功后删除文件失败!");
        }
    }

    private String generateScriptFileAndUpload(String scriptJsonStr, String obj, FileBusinessTypeEnum businessCode) {
        File file = pathUtil.objectToJsonFile(scriptJsonStr);
        try {
            NKFile nkFile = simpleStorageService.upload(NKSecurityContext.getTenantId(), file, true, obj, businessCode);
            String path = nkFile.getId();
            return path;
        } catch (FileUploadException e) {
            return null;
        } finally {
            if (!file.delete())
                logger.debug("generateScriptFileAndUpload: 上传文件成功后删除文件失败!");
        }
    }


    @Override
    public AtuSceneInfoDetailDto getScript(String sceneId) {
        AtuSceneInfo atuSceneInfo1 = atuSceneInfoService.findByPrimaryKey(sceneId);
        if (atuSceneInfo1 == null)
            throw new PlatformRuntimeException(new ErrorMessage("场景脚本记录不存在"));
        if (atuSceneInfo1.getIsDeleted() == 1)
            throw new PlatformRuntimeException(new ErrorMessage("场景脚本记录已经被删除"));

        AtuSceneInfoDetailDto atuSceneInfoDetailDto = new AtuSceneInfoDetailDto();
        atuSceneInfoDetailDto.setId(atuSceneInfo1.getId());
        atuSceneInfoDetailDto.setCreatedBy(atuSceneInfo1.getCreatedBy());
        String createdByName = entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, atuSceneInfo1.getCreatedBy());
        atuSceneInfoDetailDto.setCreatedName(createdByName);
        atuSceneInfoDetailDto.setCreatedTime(atuSceneInfo1.getCreatedTime());
        atuSceneInfoDetailDto.setCurrentVersionId(atuSceneInfo1.getCurrentVersionId());
        atuSceneInfoDetailDto.setDataUrl(atuSceneInfo1.getDataUrl());
        atuSceneInfoDetailDto.setSceneName(atuSceneInfo1.getSceneName());
        atuSceneInfoDetailDto.setScriptUrl(atuSceneInfo1.getScriptUrl());
        atuSceneInfoDetailDto.setProjectId(atuSceneInfo1.getProjectId());
        atuSceneInfoDetailDto.setTenantId(atuSceneInfo1.getTenantId());
        atuSceneInfoDetailDto.setIsDeleted(atuSceneInfo1.getIsDeleted());
        atuSceneInfoDetailDto.setUpdatedBy(atuSceneInfo1.getUpdatedBy());
        String updateByName = entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, atuSceneInfo1.getUpdatedBy());
        atuSceneInfoDetailDto.setUpdatedName(updateByName);
        atuSceneInfoDetailDto.setUpdatedTime(atuSceneInfo1.getUpdatedTime());
        atuSceneInfoDetailDto.setScriptCode(atuSceneInfo1.getScriptCode());

        return atuSceneInfoDetailDto;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer deleteScript(String sceneId) {
        AtuSceneInfo atuSceneInfo = atuSceneInfoService.findByPrimaryKey(sceneId);
        if (atuSceneInfo == null || 1 == atuSceneInfo.getIsDeleted())
            throw new PlatformRuntimeException(new ErrorMessage("场景脚本记录不存在"));

        // 校验脚本是否被计划使用
        Boolean status = executePlanFeignClient.checkScript(CollUtil.newArrayList(sceneId));
        if (status){//true:存在关联，删除失败  false:不存在关联
            throw new PlatformRuntimeException(ScriptCaseAppError.PLAN_HAS_SCRIPT);
        }
        AtuCaseDataSet dataSet = new AtuCaseDataSet();
        dataSet.setLeaf(true);
        dataSet.setScriptId(sceneId);
        List<AtuCaseDataSet> query = atuCaseDataSetService.query(dataSet);
        if (query != null && query.size()>0){
            throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_HAS_DATA_SET);
        }
        // 删除草稿输入项数据
        AtuScriptInputSet record = new AtuScriptInputSet();
        record.setScriptId(sceneId);
        atuScriptInputSetService.deleteByExample(record);
        // 删除正式表输入项数据
        AtuInputSet atuInputSet = new AtuInputSet();
        atuInputSet.setScriptId(sceneId);
        atuInputSetService.deleteByExample(atuInputSet);
        // 删除脚本版本表数据
        AtuScriptVersion atuScriptVersion = new AtuScriptVersion();
        atuScriptVersion.setScriptId(sceneId);
        atuScriptVersionService.deleteByExample(atuScriptVersion);
        // 更新脚本表
        AtuSceneInfo atuSceneInfo1 = new AtuSceneInfo();
        atuSceneInfo1.setId(sceneId);
        atuSceneInfo1.setIsDeleted(1);
        atuSceneInfo1.setUpdatedBy(NKSecurityContext.getUserId());
        atuSceneInfo1.setUpdatedTime(new Date());
        // 删除脚本文件
        attachmentFeignClient.deleteFileByObjId(sceneId, null);
        int count = atuSceneInfoService.updateByPrimaryKey(atuSceneInfo1);
        if (count > 0) {//增加平台日志
            CpLogAddDto cpLogAddDto = new CpLogAddDto();
            cpLogAddDto.setCreatedBy(NKSecurityContext.getUserId());
            cpLogAddDto.setCreatedTime(new Date());
            cpLogAddDto.setTenantId(NKSecurityContext.getTenantId());
            cpLogAddDto.setUpdatedBy(NKSecurityContext.getUserId());
            cpLogAddDto.setUpdatedTime(new Date());
            String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM,
                    atuSceneInfo.getProjectId());
            cpLogAddDto.setContent("【删除场景】系统：" + projectName + "，场景名称:" + atuSceneInfo.getSceneName());
            cpLogAddDto.setModule("场景管理");
            cpLogAddDto.setType("3");
            MonsterLogServer.sendLogToMonster(cpLogAddDto);
            logRabbitMQPublisher.deployLogContent(cpLogAddDto);
        }
        return count;
    }

    public void saveSceneNodeInfoService(String sceneId, String projectId, String ScriptJson) {
        if (!StringUtils.hasText(ScriptJson)) {
            logger.debug("saveSceneNodeInfoService 脚本文件为空");
            return;
        }

        SceneScript sceneScript = JSONObject.parseObject(ScriptJson, SceneScript.class);
        if (sceneScript == null || sceneScript.getNodes() == null) {
            logger.debug("saveSceneNodeInfoService 脚本文件节点为空");
            return;
        }

        List<Node> nodes = sceneScript.getNodes().stream().filter(x -> !x.getNodeType().equals(ScriptConstant.START) &&
                !x.getNodeType().equals(ScriptConstant.END)).collect(Collectors.toList());
        AtuSceneNodeInfo _where = new AtuSceneNodeInfo();
        _where.setSceneScriptId(sceneId);
        _where.setIsDeleted(0);
        List<AtuSceneNodeInfo> nodeList = atuSceneNodeInfoService.query(_where);
        if (!CollectionUtils.isEmpty(nodeList)) {
            nodeList.forEach(x -> {
                x.setIsDeleted(1);
                x.setUpdatedBy(NKSecurityContext.getUserId());
                x.setUpdatedTime(new Date());
                atuSceneNodeInfoService.updateByPrimaryKey(x);
            });
            logger.debug("saveSceneNodeInfoService 更新场景脚本旧节点信息为删除状态");
        }

        if (!CollectionUtils.isEmpty(nodes)) {
            nodes.forEach(x -> {
                AtuSceneNodeInfo _node = new AtuSceneNodeInfo();
                _node.setId(UUIDUtil.create32UUID());
                _node.setUpdatedTime(new Date());
                _node.setUpdatedBy(NKSecurityContext.getUserId());
                _node.setCreatedBy(NKSecurityContext.getUserId());
                _node.setCreatedTime(new Date());
                _node.setSceneScriptId(sceneId);
                _node.setNodeScriptId(x.getScriptId());
                _node.setProjectId(projectId);
                _node.setTenantId(NKSecurityContext.getTenantId());
                atuSceneNodeInfoService.insert(_node);
            });
            logger.debug("saveSceneNodeInfoService 添加场景脚本节点信息");
        }
    }

    @Override
    public Map<String, Object> queryScriptData(Map<String, Object> queryMap) {

        Map<String, Object> resultMap = new HashMap<>();
        //所有的脚本id
        List<String> scriptList = (List<String>) queryMap.get("scriptList");
        //场景id集合
        List<AtuSceneInfo> sceneInfos = atuSceneInfoService.querySceneByList(scriptList);
        List<String> sceneList = new ArrayList<>();
        sceneInfos.forEach(one -> {
            sceneList.add(one.getId());
        });
        //关联的场景脚本id
        resultMap.put("sceneList", sceneList);

        //查询一般脚本
        List<AtuScriptInfo> scriptInfoList = atuScriptInfoService.queryScriptByIds(scriptList);
        Set<AtuScriptInfo> scriptInfoSet = new HashSet<>(scriptInfoList);
        //查询父节点下的脚本
        List<String> parentList = (List<String>) queryMap.get("parentList");
        if (parentList != null && parentList.size() > 0) {
            for (String parentId : parentList) {
                List<AtuScriptInfo> infoList = this.atuCaseDataSetService.queryScriptByPath(parentId);
                scriptInfoSet.addAll(infoList);
            }
        }
        //需要新增关联关系的脚本id
        resultMap.put("insertList", new ArrayList<>(scriptInfoSet));
        return resultMap;
    }

    @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 = atuSceneInfoService.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 = atuSceneInfoService.selectCreatorByProject(projectId);
        if (!CollectionUtils.isEmpty(creatorList)) {
            creatorList.forEach(id -> {
                if (id.length() <= 20) {
                    userIds.add(Long.valueOf(id));
                }
            });
        }
        List<String> updaterList = atuSceneInfoService.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;
    }

    public 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("", e);
                }
            }
        }
        return scriptData;
    }

    private void createdCodeAndInsert(AtuSceneInfo sceneInfo) {
        String proId = sceneInfo.getProjectId();
        ResultWrapper<Map<String, String>> wrapper = projectFeignClient.feignQueryProData(proId);
        Map<String, String> data = wrapper.getData();
        StringBuilder stringBuilder = new StringBuilder();
        String code = data.get("code");
        if (code == null || code.equals("")) {
            throw new RuntimeException("系统编号为空，创建脚本编号失败！");
        }
        stringBuilder.append(code);
        //true 场景：系统缩写_US00001）
        List<Integer> integers = atuBusinessNoApiService.genBusinessNo(proId, ScriptConstant.SCRIPT_CODE_US, 1);
        String format = String.format("%05d", integers.get(0));
        stringBuilder.append("_US").append(format);
        sceneInfo.setScriptCode(stringBuilder.toString());
        redisTemplate.opsForValue().set("UITEST-ScriptCode:"+ sceneInfo.getId(),stringBuilder.toString());
        atuSceneInfoService.insert(sceneInfo);
    }


    private List<String> saveInputSetByScene(AtuSaveSceneScriptAndGenCaseDto dto,String uploadScriptJson) {
        //上传文件地址
        List<String> dataUrls = new ArrayList<>();
        //查询系统关联的环境id集合
        List<String> envIds = projectFeignClient.selectEnvIds(dto.getProjectId());
        if (envIds.size() > 0) {
            //清空主表中的数据
            AtuInputSet delDto = new AtuInputSet();
            delDto.setScriptId(dto.getId());
            attachmentFeignClient.deleteFileByObjId(dto.getId(), FileBusinessTypeEnum.INPUT_DATA_SET.getCode());
            this.atuInputSetService.deleteByExample(delDto);

            //同步副表中数据到主表中
            AtuScriptInputSet queryDto = new AtuScriptInputSet();
            queryDto.setScriptId(dto.getId());
            List<AtuScriptInputSet> queryList = this.atuScriptInputSetService.query(queryDto);
            if (queryList != null && queryList.size() > 0) {
                //副表存在数据 同步到主表中
                List<String> existEnvList = new ArrayList<>();
                queryList.forEach(one -> {
                    existEnvList.add(one.getEnvId());
                });
                if (existEnvList.containsAll(envIds) && envIds.containsAll(existEnvList)) {
                    //两个环境id集合相同 直接新增
                    for (AtuScriptInputSet inputSet : queryList) {
                        JSONObject jsonObject = downloadScriptFile(inputSet.getDataUrl());
                        String upload = saveInputSet(inputSet.getScriptId(), inputSet.getEnvId(), jsonObject);
                        dataUrls.add(upload);
                    }
                } else {
                    //存在不同的环境
                    for (AtuScriptInputSet inputSet : queryList) {
                        //找出相同环境的数据 同步到主表中
                        if (envIds.contains(inputSet.getEnvId())) {
                            JSONObject jsonObject = downloadScriptFile(inputSet.getDataUrl());
                            String upload = saveInputSet(inputSet.getScriptId(), inputSet.getEnvId(), jsonObject);
                            dataUrls.add(upload);
                        } else {
                            //删除副表里不存在的环境数据
                            this.atuScriptInputSetService.deleteByPrimaryKey(inputSet.getId());
                        }
                    }
                    //找一个文件解析数据
                    JSONObject scriptFile = downloadScriptFile(queryList.get(0).getDataUrl());

                    List<Map<String, Object>> tableContent = (List<Map<String, Object>>) scriptFile.get(ScriptConstant.SCRIPT_INPUT_TABLE_CONTENT);
                    List<String> tableHeaders = (List<String>) scriptFile.get(ScriptConstant.SCRIPT_INPUT_TABLE_HEADERS);
                    List<Map<String, Object>> variables = (List<Map<String, Object>>) scriptFile.get(ScriptConstant.SCRIPT_INPUT_VARIABLES);

                    //对比两个环境id集合  存在不同环境  先创建一份默认数据 保存到新环境中
                    List<Map<String, Object>> targetContent = findTableContent(tableContent);
                    for (String envId : envIds) {
                        //找出当前不存在的 创建默认输入项 保存到副表跟主表中
                        if (!existEnvList.contains(envId)) {
                            JSONObject jsonObject = new JSONObject();
                            jsonObject.put(ScriptConstant.SCRIPT_INPUT_TABLE_CONTENT, targetContent);
                            jsonObject.put(ScriptConstant.SCRIPT_INPUT_TABLE_HEADERS, tableHeaders);
                            jsonObject.put(ScriptConstant.SCRIPT_INPUT_VARIABLES,variables);
                            saveScriptInputSet(dto.getId(), envId, jsonObject);
                            String upload = saveInputSet(dto.getId(), envId, jsonObject);
                            dataUrls.add(upload);
                        }
                    }
                }
            } else {
                //输入项副表数据为空的情况 根据环境id创建默认的脚本输入项
                JSONObject jsonObject = atuScriptInputSetService.createDefaultInputSet(uploadScriptJson);
                for (String envId : envIds) {
                    //保存副表
                    saveScriptInputSet(dto.getId(), envId, jsonObject);
                    //保存主表
                    String upload = saveInputSet(dto.getId(), envId, jsonObject);
                    dataUrls.add(upload);
                }
            }
        } else {
            throw new PlatformRuntimeException(ScriptCaseAppError.SCRIPT_ENV_IS_NULL);
        }
        return dataUrls;
    }


    private List<Map<String, Object>> findTableContent(List<Map<String, Object>> content){
        List<Map<String, Object>> resultList = new ArrayList<>();
        for (Map<String, Object> map : content) {
            Map<String, Object> resultMap = new HashMap<>();
            resultMap.put(ScriptConstant.SCRIPT_TEST_PURPOSE_ID,map.get(ScriptConstant.SCRIPT_TEST_PURPOSE_ID));
            resultMap.put(ScriptConstant.SCRIPT_TEST_PURPOSE_NAME,map.get(ScriptConstant.SCRIPT_TEST_PURPOSE_NAME));
            resultList.add(resultMap);
        }
        return resultList;
    }


	private void addKey(JSONObject jsonObject,List<String> rowIds) {
        List<Map> tableContent = JSONObject.parseArray(jsonObject.get(ScriptConstant.SCRIPT_INPUT_TABLE_CONTENT).toString(), Map.class);
        if (null != tableContent && tableContent.size() != 0) {
            for (int i = 0; i < tableContent.size(); i++) {
                Object rowId = tableContent.get(i).get(ScriptConstant.SCRIPT_TEST_PURPOSE_ID);
                if (rowId == null || rowId.equals("")) {
                    tableContent.get(i).put(ScriptConstant.SCRIPT_TEST_PURPOSE_ID, rowIds.get(i));
                }
            }
            jsonObject.put(ScriptConstant.SCRIPT_INPUT_TABLE_CONTENT, tableContent);
        }
    }


    private String saveInputSet(String scriptId, String envId, JSONObject jsonObject) {
        AtuInputSet inputSet = new AtuInputSet();
        String uuid = UUIDUtil.create32UUID();
        inputSet.setId(uuid);
        inputSet.setScriptId(scriptId);
        inputSet.setEnvId(envId);
        inputSet.setCreatedBy(NKSecurityContext.getUserId());
        inputSet.setCreatedTime(new Date());
        String upload = fileUploadByObject(jsonObject, scriptId, FileBusinessTypeEnum.INPUT_DATA_SET);
        inputSet.setDataUrl(upload);
        atuInputSetService.insert(inputSet);

        Object obj = jsonObject.get(ScriptConstant.SCRIPT_INPUT_TABLE_CONTENT);
        if (obj != null){
            List<Map<String, Object>> tableContent = JSON.parseObject(JSONObject.toJSONString(obj), new TypeReference<List<Map<String, Object>>>() {
            });
            dataMgrUtils.queryInputAndDataLink(tableContent,envId,uuid,ScriptConstant.DATA_SET_LINK_BY_CASE);
        }
        return upload;
    }

    private void saveScriptInputSet(String scriptId, String envId, JSONObject jsonObject) {
        AtuScriptInputSet scriptInputSet = new AtuScriptInputSet();
        String uuid = UUIDUtil.create32UUID();
        scriptInputSet.setId(uuid);
        scriptInputSet.setScriptId(scriptId);
        scriptInputSet.setEnvId(envId);
        scriptInputSet.setCreatedBy(NKSecurityContext.getUserId());
        scriptInputSet.setCreatedTime(new Date());
        String upload = fileUploadByObject(jsonObject, scriptId, FileBusinessTypeEnum.SCENE_SCRIPT_INPUT_DATA_SET);
        scriptInputSet.setDataUrl(upload);
        atuScriptInputSetService.insert(scriptInputSet);

        Object obj = jsonObject.get(ScriptConstant.SCRIPT_INPUT_TABLE_CONTENT);
        if (obj != null){
            List<Map<String, Object>> tableContent = JSON.parseObject(JSONObject.toJSONString(obj), new TypeReference<List<Map<String, Object>>>() {
            });
            dataMgrUtils.queryInputAndDataLink(tableContent,envId,uuid,ScriptConstant.DATA_SET_LINK_BY_SCENE);
        }
    }
}
