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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.Page;
import com.github.pagehelper.page.PageMethod;
import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.exception.InvalidException;
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.BasicService;
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.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.bus.LogRabbitMQPublisher;
import net.northking.cctp.scriptcase.constants.ScriptConstant;
import net.northking.cctp.scriptcase.db.entity.AtuElementGroup;
import net.northking.cctp.scriptcase.db.entity.AtuElementInfo;
import net.northking.cctp.scriptcase.db.service.AtuElementGroupService;
import net.northking.cctp.scriptcase.db.service.AtuElementInfoService;
import net.northking.cctp.scriptcase.dto.atuScript.UserQueryDto;
import net.northking.cctp.scriptcase.dto.elementLibrary.*;
import net.northking.cctp.scriptcase.enums.ElementLibraryError;
import net.northking.cctp.scriptcase.enums.ScriptCaseAppError;
import net.northking.cctp.scriptcase.feign.AttachmentFeignClient;
import net.northking.cctp.scriptcase.feign.PlatformFeignClient;
import net.northking.cctp.scriptcase.tools.MinioPathUtils;
import net.northking.cctp.scriptcase.tools.StreamUtils;
import org.apache.poi.poifs.filesystem.FileMagic;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
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 org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.ParseException;
import java.util.*;

/**
 * 元素信息管理服务实现类
 *
 * @author maven-cctp-plugin
 * @since 1.0
 */

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

  @Autowired
  private AtuElementInfoService atuElementInfoService;
  @Autowired
  private AtuElementGroupService atuElementGroupService;
  @Autowired
  private EntityNameCache entityNameCache;
  @Autowired
  private SimpleStorageService simpleStorageService;
  @Autowired
  private LogRabbitMQPublisher logPublisher;
  @Autowired
  private PlatformFeignClient platformFeignClient;
  @Autowired
  MonsterCommonFeignClient monsterCommonFeignClient;
  @Autowired
  AttachmentFeignClient attachmentFeignClient;

  //= Excel 导入导出相关代码 start ==================//
  @Override
  public BasicService<AtuElementInfo> getService()
  {
    return this.atuElementInfoService;
  }

  @Override
  public ExcelHeader[] excelHeaders()
  {
    ExcelHeader id = new ExcelHeader("元素ID", "id", String.class);
    ExcelHeader groupId = new ExcelHeader("元素分组ID", "groupId", String.class);
    ExcelHeader name = new ExcelHeader("元素名称", "name", String.class);
    ExcelHeader type = new ExcelHeader("元素类型", "type", String.class);
    ExcelHeader fetchType = new ExcelHeader("元素获取方式", "fetchType", String.class);
    ExcelHeader fetchValue = new ExcelHeader("元素属性表达式", "fetchValue", String.class);
    ExcelHeader secondFtype = new ExcelHeader("元素备选获取方式", "secondFtype", String.class);
    ExcelHeader secondFvalue = new ExcelHeader("元素备选属性表达式", "secondFvalue", 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<AtuElementInfo> beforeInsertBatch(List<AtuElementInfo> records)
  {
    for (AtuElementInfo record : records)
    {
      record.setId(UUIDUtil.create32UUID());
    }
    return records;
  }

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

  //= Excel 导入导出相关代码 end =======================//

  //= 增删改查 相关代码 start ==================//
  @Override
  @DatabaseReadOnly
  public Pagination<AtuElementInfoDetailDto> pagingQuery(QueryByPage<AtuElementInfoQueryDto> queryByPage)
  {
    DefaultPagination<AtuElementInfoDetailDto> pagination = new DefaultPagination();
    //目录查询参数修改
    String treeId = queryByPage.getQuery().getGroupId();
    if (StringUtils.hasText(treeId)) {
      List<String> groupIds = atuElementGroupService.queryChildrenTreeIds(treeId);
      if (!CollectionUtils.isEmpty(groupIds)) {
        queryByPage.getQuery().setGroupId(null);
        queryByPage.getQuery().setGroupIds(groupIds);
      }else {
        return pagination;
      }
    }
    buildQueryPage(queryByPage);
    String creator = queryByPage.getQuery().getCreator();
    if (StringUtils.hasText(creator)) {
      List<String> createBys = getUserIds(creator);
      if (!CollectionUtils.isEmpty(createBys)) {
        queryByPage.getQuery().setCreateBys(createBys);
      } else {
        return pagination;
      }
    }
    String updateName = queryByPage.getQuery().getUpdatedName();
    if (StringUtils.hasText(updateName)) {
      List<String> updateBys = getUserIds(updateName);
      if (!CollectionUtils.isEmpty(updateBys)) {
        queryByPage.getQuery().setUpdatedBys(updateBys);
      } else {
        return pagination;
      }
    }
    //数据集查询租户隔离
    queryByPage.getQuery().setTenantId(NKSecurityContext.getTenantId());
    //处理分页参数
    handlePageParam(queryByPage);
    pagination.setPageSize(queryByPage.getPageSize());
    pagination.setPageNo(queryByPage.getPageNo());
    Page<AtuElementInfoDetailDto> page = PageMethod.startPage(queryByPage.getPageNo(), queryByPage.getPageSize());  //开始分页
    List<AtuElementInfoDetailDto> result = atuElementInfoService.queryElementList(queryByPage);
    //处理返回数据
    for (AtuElementInfoDetailDto detailDto : result) {
      //创建修改人名称
      detailDto.setCreator(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, detailDto.getCreatedBy()));
      detailDto.setModifier(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, detailDto.getUpdatedBy()));
      try {
        List<AtuElementFetchTypeDto> fetchTypeList = JSONUtil.toList(detailDto.getFetchValue(), AtuElementFetchTypeDto.class);
        detailDto.setFetchTypeList(fetchTypeList);
      }catch (Exception e){
        logger.error("获取元素方式切换异常");
      }
    }
    pagination.setRecords(result);
    pagination.setRecordCount(page.getTotal());
    return pagination;
  }

  private void buildQueryPage(QueryByPage<AtuElementInfoQueryDto> queryByPage) {
    AtuElementInfoQueryDto atuElementInfoQueryDto = queryByPage.getQuery();

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

  /**
   * 处理分页查询参数
   *
   * @param query
   */
  private void handlePageParam(QueryByPage<AtuElementInfoQueryDto> 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(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public String add(AtuElementInfoAddDto dto, String projectId)
  {
    //元素目录校验
    AtuElementGroup elementGroup = atuElementGroupService.findByPrimaryKey(dto.getGroupId());
    if (null == elementGroup || ScriptConstant.STR_ZERO.equals(elementGroup.getIsLeaf())) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_DIR_IS_VALID);
    }
    //元素名称校验
    List<AtuElementInfo> atuElementInfos = atuElementInfoService.findByName(dto.getName(), projectId);
    if (!CollectionUtils.isEmpty(atuElementInfos)) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_IS_EXISTS);
    }
    // 校验获取方式是否为空
    if (CollUtil.isEmpty(dto.getFetchTypeList())){
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_FETCH_TYPE_NO_EXISTS);
    }
    String uuid = UUIDUtil.create32UUID();
    AtuElementInfo entity = new AtuElementInfo();
    BeanUtils.copyProperties(dto, entity);
    entity.setId(uuid);
    entity.setIsDeleted(ScriptConstant.STR_ZERO);
    entity.setCreatedBy(NKSecurityContext.getUserId());
    entity.setCreatedTime(new Date());
    entity.setUpdatedBy(entity.getCreatedBy());
    entity.setUpdatedTime(entity.getCreatedTime());
    entity.setTenantId(NKSecurityContext.getTenantId());
    dto.getFetchTypeList().forEach(e -> {
      // 图片识别
      if (e.getType().equals("3")) {
        String imgUri = e.getValue().get("imgUri").toString();
        String copyImgUri = copyFile(imgUri, entity.getId(), FileBusinessTypeEnum.ELEMENT_IMAGE);
        e.getValue().put("imgUri", copyImgUri);
      }
    });
    handleFetchType(entity, dto.getFetchTypeList());
    this.atuElementInfoService.insert(entity);
    return uuid;
  }

  private void handleFetchType(AtuElementInfo entity, List<AtuElementFetchTypeDto>  fetchTypeList){
    AtuElementFetchTypeDto atuElementFetchTypeDto = fetchTypeList.get(0);
    if (atuElementFetchTypeDto == null){
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_FETCH_TYPE_NO_EXISTS);
    }
    entity.setSecondFtype(atuElementFetchTypeDto.getType());
    String secondFvalue = JSONUtil.toJsonStr(atuElementFetchTypeDto.getValue());
    if (StringUtils.hasText(secondFvalue) && secondFvalue.length() > 520) {
        throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_VALUE_IS_TOO_LONG);
    }
    entity.setSecondFvalue(secondFvalue);
    // 所有元素获取方式存一起
    entity.setFetchValue(JSON.toJSONString(fetchTypeList));
  }

  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;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer updateByPK(AtuElementInfoUpdateDto dto, String projectId) throws IllegalAccessException
  {
    //参数校验
    AtuElementInfo oldElement = atuElementInfoService.findByPrimaryKey(dto.getId());
    if (oldElement == null || ScriptConstant.STR_ONE.equals(oldElement.getIsDeleted())) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_NO_EXISTS);
    }
    //元素名称校验
    List<AtuElementInfo> atuElementInfos = atuElementInfoService.findByNameButNotSelf(dto.getName(), dto.getId(), projectId);
    if (!CollectionUtils.isEmpty(atuElementInfos)) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_IS_EXISTS);
    }
    // 校验获取方式是否为空
    if (CollUtil.isEmpty(dto.getFetchTypeList())){
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_FETCH_TYPE_NO_EXISTS);
    }
    String oldFetchValue = oldElement.getFetchValue();
    List<AtuElementFetchTypeDto> oldFetchTypeDtos = JSON.parseArray(oldFetchValue, AtuElementFetchTypeDto.class);
    oldFetchTypeDtos.forEach(item -> {
        // 图片识别
        if (item.getType().equals("3")) {
          String oldImgUri = item.getValue().get("imgUri").toString();
          for (AtuElementFetchTypeDto newFetchTypeDto : dto.getFetchTypeList()) {
            if (newFetchTypeDto.getType().equals("3")) {
              if (!oldImgUri.equals(newFetchTypeDto.getValue().get("imgUri").toString())) {
                // 删除文件
                attachmentFeignClient.deleteFileByObjId(dto.getId(), FileBusinessTypeEnum.ELEMENT_IMAGE.getCode());
              }
            }
          }
        }
    });
    List<String> fileIds = new ArrayList<>();
    dto.getFetchTypeList().forEach(e -> {
      // 图片识别
      if (e.getType().equals("3")) {
        String imgUri = e.getValue().get("imgUri").toString();
        String[] strings = MinioPathUtils.idToPath(imgUri);
        fileIds.add("/" + strings[1]);
      }
    });
    if (!CollectionUtils.isEmpty(fileIds)) {
      AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
      associatedFilesDto.setObjId(dto.getId());
      associatedFilesDto.setFileIds(fileIds);
      ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
      if (wrapper == null || !wrapper.isSuccess()) {
        throw new InvalidException("文件关联异常");
      }
    }
    AtuElementInfo entity = new AtuElementInfo();
    BeanUtils.copyProperties(dto, entity);
    entity.setUpdatedBy(NKSecurityContext.getUserId());
    entity.setUpdatedTime(new Date());
    handleFetchType(entity, dto.getFetchTypeList());
    return this.atuElementInfoService.updateByPrimaryKey(entity);
  }

  @Override
  @DatabaseReadOnly
  public AtuElementInfoDetailDto findByPK(String uuid)
  {
    //参数校验
    AtuElementInfo oldElement = atuElementInfoService.findByPrimaryKey(uuid);
    if (oldElement == null || ScriptConstant.STR_ONE.equals(oldElement.getIsDeleted())) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_NO_EXISTS);
    }
    AtuElementInfoDetailDto dto = new AtuElementInfoDetailDto();
    BeanUtils.copyProperties(oldElement, dto);
    dto.setCreator(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER,dto.getCreatedBy()));
    dto.setModifier(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER,dto.getUpdatedBy()));
    try {
      List<AtuElementFetchTypeDto> fetchTypeList = JSONUtil.toList(dto.getFetchValue(), AtuElementFetchTypeDto.class);
      dto.setFetchTypeList(fetchTypeList);
    }catch (Exception e){
      logger.error("获取元素方式切换异常", e);
    }
    return dto;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer deleteByPK(String uuid)
  {
    //参数校验
    AtuElementInfo oldElement = atuElementInfoService.findByPrimaryKey(uuid);
    if (oldElement == null || ScriptConstant.STR_ONE.equals(oldElement.getIsDeleted())) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_NO_EXISTS);
    }
    AtuElementInfo entity = new AtuElementInfo();
    BeanUtils.copyProperties(oldElement,entity);
    entity.setIsDeleted(ScriptConstant.STR_ONE);
    entity.setUpdatedBy(NKSecurityContext.getUserId());
    entity.setUpdatedTime(new Date());
    // 删除文件
    attachmentFeignClient.deleteFileByObjId(uuid, null);
    int count = this.atuElementInfoService.updateByPrimaryKey(entity);
    //删除脚本增加平台日志
    CpLogAddDto cpLogAddDto = new CpLogAddDto();
    String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), oldElement.getProjectId());
    String content = String.format(ScriptConstant.DEL_ELE_INFO,projectName,oldElement.getName());
    cpLogAddDto.setContent(content);
    cpLogAddDto.setModule(ScriptConstant.ELE_INFO_MODULE);
    cpLogAddDto.setType(ScriptConstant.LOG_DEL_STATUS);
    MonsterLogServer.sendLogToMonster(cpLogAddDto);
    logPublisher.deployLogContent(cpLogAddDto);
    return count;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer deleteBatch(AtuElementInfoDelDto dto)
  {
    List<String> elementIds = dto.getIds();
    if (CollectionUtils.isEmpty(elementIds)) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_NO_EXISTS);
    }
    //获取脚本信息
    List<AtuElementInfo> elementInfoList = atuElementInfoService.queryByIds(elementIds);
    List<String> elementNames = new ArrayList<>();
    for (AtuElementInfo atuElementInfo : elementInfoList) {
      if (null == atuElementInfo) continue;
      elementNames.add(atuElementInfo.getName());
      // 删除文件
      attachmentFeignClient.deleteFileByObjId(atuElementInfo.getId(), FileBusinessTypeEnum.ELEMENT_IMAGE.getCode());
    }
    String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), dto.getProjectId());
    //逻辑删除脚本
    AtuElementInfo elementInfo = new AtuElementInfo();
    elementInfo.setIsDeleted(ScriptConstant.STR_ONE);
    elementInfo.setUpdatedTime(new Date());
    elementInfo.setUpdatedBy(NKSecurityContext.getUserId());
    int num = atuElementInfoService.deleteElementBatch(elementInfo,elementIds);
    //删除脚本增加平台日志
    CpLogAddDto cpLogAddDto = new CpLogAddDto();
    String content = String.format(ScriptConstant.DEL_ELE_INFO_LIST,projectName,num);
    cpLogAddDto.setContent(content);
    cpLogAddDto.setModule(ScriptConstant.ELE_INFO_MODULE);
    cpLogAddDto.setType(ScriptConstant.LOG_DEL_STATUS);
    cpLogAddDto.setContentDetails(elementNames);
    MonsterLogServer.sendLogToMonster(cpLogAddDto);
    logPublisher.deployLogContent(cpLogAddDto);
    return num;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public Integer moveElement(AtuElementInfoMoveDto dto) {
    //参数校验
    AtuElementInfo oldElement = atuElementInfoService.findByPrimaryKey(dto.getId());
    if (null == oldElement || ScriptConstant.STR_ONE.equals(oldElement.getIsDeleted())) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_NO_EXISTS);
    }
    AtuElementGroup targetTree = atuElementGroupService.findByPrimaryKey(dto.getGroupId());
    if (null == targetTree) {
      throw new PlatformRuntimeException(ElementLibraryError.TREE_NO_EXISTS);
    }
    if (ScriptConstant.STR_ZERO.equals(targetTree.getIsLeaf())) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_MOVE_NO_LEAF);
    }
    //更新数据
    Date now = new Date();
    AtuElementInfo newElement = new AtuElementInfo();
    BeanUtils.copyProperties(dto,newElement);
    newElement.setUpdatedBy(NKSecurityContext.getUserId());
    newElement.setUpdatedTime(now);
    int count = atuElementInfoService.updateByPrimaryKey(newElement);
    return count;
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public String uploadImage(MultipartFile file) {
    //校验文件格式
    checkFile(file);
    //上传文件
    try {
      NKFile nkFile = simpleStorageService.upload(NKSecurityContext.getTenantId(), file, "-1", FileBusinessTypeEnum.ELEMENT_IMAGE);
      String path = MinioPathUtils.pathToId(NKSecurityContext.getTenantId(), nkFile.getId());
      return path;
    } catch (Exception e) {
      logger.error("上传图片失败", e);
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_FILE_UPLOAD_IS_FAIL);
    }
  }

  @Override
  @Transactional(isolation = Isolation.DEFAULT, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
  public void downloadImage(HttpServletResponse response, String url) {
    if (null == url) {
      logger.debug("文件id不存在");
      return;
    }
    logger.debug("请求文件服务下载报告：{}", url);
    String[] result = MinioPathUtils.idToPath(url);
    try {
      response.setHeader(ScriptConstant.CONTENT_DISPOSITION, ScriptConstant.FILE_NAME + URLEncoder.encode(result[2], ScriptConstant.STR_ENCODE));
    } catch (UnsupportedEncodingException e) {
      logger.error("文件名编码格式不支持");
    }
    downLoadAndReturn(response, result);
  }

    @Override
    public AdvancedQueryOptions advancedQueryOptions(String projectId) {
      AdvancedQueryOptions options = new AdvancedQueryOptions();
      options.setCreatorList(new ArrayList<>());
      options.setUpdaterList(new ArrayList<>());
      Set<Long> userIds = new HashSet<>();
      List<String> creatorList = atuElementInfoService.selectCreatorByProject(projectId);
      if (!CollectionUtils.isEmpty(creatorList)) {
        creatorList.forEach(id -> {
          if (id.length() <= 20) {
            userIds.add(Long.valueOf(id));
          }
        });
      }
      List<String> updaterList = atuElementInfoService.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 (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 void downLoadAndReturn(HttpServletResponse response, String[] result) {
    File file = null;
    try {
      file = simpleStorageService.downloadAsFile(result[0], "/" + result[1]);
      response.setContentLengthLong(file.length());
      StreamUtils.toResponse(response, new FileInputStream(file));
    } catch (FileDownloadException e) {
      logger.error(e.getMessage(), e);
    } catch (Exception e) {
      logger.error("文件下载失败", e);
    } finally {
      if(file != null){
        boolean delete = file.delete();
        if (!delete) {
          logger.error("文件删除失败");
        }
      }
    }

  }

  /**
   * 校验是否为符合要求的图像文件
   * @param file
   */
  private String checkFile(MultipartFile file) {
    if (file == null || file.isEmpty()) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_FILE_IS_NULL);
    }
    String filename = file.getOriginalFilename();
    String suffix = filename.substring(filename.lastIndexOf(".")+1);
    suffix = suffix.toLowerCase();
    if (!(suffix.equals(ScriptConstant.BMP) || suffix.equals(ScriptConstant.JPG) || suffix.equals(ScriptConstant.PNG))) {
      throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_FILE_FORMART_IS_ERROR);
    }
    try (BufferedInputStream bis = new BufferedInputStream(file.getInputStream())){
      FileMagic fileMagic = FileMagic.valueOf(bis);
      if (!(Objects.equals(fileMagic,FileMagic.BMP) || Objects.equals(fileMagic,FileMagic.JPEG) || Objects.equals(fileMagic,FileMagic.PNG))) {
        throw new PlatformRuntimeException(ElementLibraryError.ELEMENT_FILE_FORMART_IS_ERROR);
      }
    } catch (Exception e) {
      logger.error("校验图像文件出错：",e);
    }
    return filename;
  }

  /**
   * 根据用户名称模糊查询用户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;
  }
}
