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

import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.constants.BaseDefineDependencyConstants;
import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.entity.Environment;
import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.exception.InvalidException;
import com.hzbank.testteam.autotest.dependencies.baseDefineDependency.vo.ResponseVO;
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.Pagination;
import net.northking.cctp.common.db.annotation.DatabaseReadOnly;
import net.northking.cctp.common.db.annotation.DatabaseWriteOnly;
import net.northking.cctp.common.db.excel.AbstractExcelService;
import net.northking.cctp.common.db.excel.ExcelHeader;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import net.northking.cctp.common.http.QueryByPage;
import net.northking.cctp.common.http.QueryOrderBy;
import net.northking.cctp.common.security.authentication.NKSecurityContext;
import net.northking.cctp.common.util.UUIDUtil;

import net.northking.cctp.common.feign.ApiAtsEnviromentFeign;
import net.northking.cctp.project.constants.ProjectAppError;
import net.northking.cctp.project.constants.ProjectConstants;
import net.northking.cctp.project.db.service.CpProjectEnvSysService;
import net.northking.cctp.project.db.entity.CpProjectEnvSys;

import net.northking.cctp.project.dto.env.*;
import org.apache.commons.lang.StringUtils;
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.integration.redis.util.RedisLockRegistry;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.stream.Collectors;

/**
 * 系统环境被测系统信息服务实现类
 *
 * @author maven-cctp-plugin
 * @since 1.0
 */

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

  @Autowired
  private CpProjectEnvSysService cpProjectEnvSysService;



  @Autowired
  private EntityNameCache entityNameCache;

  @Autowired
  private RedisLockRegistry redisLockRegistry;

  @Autowired
  private ApiAtsEnviromentFeign apiAtsEnviromentFeign;

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

  @Override
  public ExcelHeader[] excelHeaders()
  {
    ExcelHeader id = new ExcelHeader("主键", "id", String.class);
    ExcelHeader tenantId = new ExcelHeader("租户id", "tenantId", String.class);
    ExcelHeader projectId = new ExcelHeader("系统id", "projectId", String.class);
    ExcelHeader envId = new ExcelHeader("环境id", "envId", String.class);
    ExcelHeader sysUrl = new ExcelHeader("被测系统地址", "sysUrl", String.class);
    ExcelHeader sysName = new ExcelHeader("系统名称", "sysName", String.class);
    ExcelHeader memo = new ExcelHeader("描述", "memo", 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);
    ExcelHeader deleted = new ExcelHeader("是否删除", "deleted", Boolean.class);
    return new ExcelHeader[]{};
  }

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

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

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

  //= 增删改查 相关代码 start ==================//
  @Override
  @DatabaseReadOnly
  public Pagination<CpProjectEnvSysDetailDto> pagingQuery(QueryByPage<CpProjectEnvSysQueryDto> queryByPage)
  {
    List<QueryOrderBy> orderByList = new ArrayList<>();
    QueryOrderBy orderBy = new QueryOrderBy();
    orderBy.desc(ProjectConstants.CREATED_TIME);
    orderByList.add(orderBy);
    queryByPage.setOrderByList(orderByList);
    Pagination<CpProjectEnvSysDetailDto> pagingQuery = this.cpProjectEnvSysService.pagingQuery(queryByPage);
    if (pagingQuery.getRecords() == null || pagingQuery.getRecords().size() <= 0){
      return pagingQuery;
    }
    for (CpProjectEnvSysDetailDto record : pagingQuery.getRecords()) {
      String createdBy = entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, record.getCreatedBy());
      record.setCreatedBy(StringUtils.isBlank(createdBy)?record.getCreatedBy():createdBy);
      String updatedBy = entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, record.getUpdatedBy());
      record.setUpdatedBy(StringUtils.isBlank(updatedBy)?record.getUpdatedBy():updatedBy);
    }
    return pagingQuery;
  }

  @Override
  @DatabaseWriteOnly
  @Transactional(rollbackFor = Exception.class)
  public String add(CpProjectEnvSysAddDto dto)
  {
    // 校验名称是否存在
    Lock lock = redisLockRegistry.obtain(ProjectConstants.PROJECT_ENV_SYS_LOCK
            +":"+dto.getProjectId()+":"+dto.getEnvId()+":"+dto.getSysName());
    CpProjectEnvSys sameNameParams = new CpProjectEnvSys();
    sameNameParams.setTenantId(NKSecurityContext.getTenantId());
    sameNameParams.setProjectId(dto.getProjectId());
    sameNameParams.setEnvId(dto.getEnvId());
    sameNameParams.setSysName(dto.getSysName());
    List<CpProjectEnvSys> sameNameSysList = this.cpProjectEnvSysService.query(sameNameParams);
    if (sameNameSysList != null && sameNameSysList.size() > 0) {
      throw new PlatformRuntimeException(ProjectAppError.PROJECT_ENV_SYS_IS_EXISTS);
    }
    boolean hasLock = lock.tryLock();
    logger.info("加所是否成功：hasLock:{}",hasLock);
    try {
      if (hasLock) {
        List<CpProjectEnvSys> envSysList = new ArrayList<>();
        String uuid = UUIDUtil.create32UUID();
        CpProjectEnvSys entity = new CpProjectEnvSys();
        BeanUtils.copyProperties(dto, entity);
        entity.setId(uuid);
        entity.setTenantId(NKSecurityContext.getTenantId());
        entity.setCreatedBy(NKSecurityContext.getUserId());
        entity.setCreatedTime(new Date());
        entity.setUpdatedBy(NKSecurityContext.getUserId());
        entity.setUpdatedTime(new Date());
        envSysList.add(entity);

        ResponseVO<List<Environment>> responseVo = apiAtsEnviromentFeign.listByProject(Long.valueOf(dto.getProjectId()));
        if (responseVo == null || !responseVo.getCode().equals(BaseDefineDependencyConstants.SYSTEM_RESPONSE_CODE_SUCCESS)) {
          throw new InvalidException("服务间调用获取系统环境失败");
        }
        List<Environment> envList = responseVo.getData();
        for (Environment vo : envList) {
          if (vo.getId().toString().equals(dto.getEnvId())) {
            continue;
          }
          // 同步该被测心痛信息至其他环境下
          CpProjectEnvSys envSys = new CpProjectEnvSys();
          envSys.setId(UUIDUtil.create32UUID());
          envSys.setTenantId(entity.getTenantId());
          envSys.setProjectId(entity.getProjectId());
          envSys.setEnvId(vo.getId().toString());
          envSys.setSysName(dto.getSysName());
          envSys.setCreatedBy(NKSecurityContext.getUserId());
          envSys.setCreatedTime(new Date());
          envSys.setUpdatedBy(NKSecurityContext.getUserId());
          envSys.setUpdatedTime(new Date());
          envSysList.add(envSys);
        }
        this.cpProjectEnvSysService.insertByBatch(envSysList);
        return uuid;
      }

    } catch (PlatformRuntimeException e) {
      throw e;
    } catch (Exception exception) {
      logger.error("保存被测系统错误，请联系运维人员，exception,{}", exception.getMessage());
      throw new PlatformRuntimeException(ProjectAppError.PROJECT_ENV_SYS_SAVE_ERROR);

    } finally {
      if (hasLock) {
        lock.unlock();
      }
    }
    throw new PlatformRuntimeException(ProjectAppError.PROJECT_ENV_SYS_SAVE_ERROR);
  }

  @Override
  @DatabaseWriteOnly
  public Integer updateByPK(CpProjectEnvSysUpdateDto dto) throws IllegalAccessException
  {
    CpProjectEnvSys entity = new CpProjectEnvSys();
    BeanUtils.copyProperties(dto, entity);
    entity.setUpdatedBy(NKSecurityContext.getUserId());
    entity.setUpdatedTime(new Date());
    return this.cpProjectEnvSysService.updateByPrimaryKey(entity);
  }

  @Override
  @DatabaseReadOnly
  public CpProjectEnvSysDetailDto findByPK(String uuid)
  {
    CpProjectEnvSys example = new CpProjectEnvSys();
    example.setId(uuid);
    List<CpProjectEnvSys> entitys = this.cpProjectEnvSysService.query(example);
    if (entitys.isEmpty())
    {
      return null;
    }

    CpProjectEnvSysDetailDto dto = new CpProjectEnvSysDetailDto();
    BeanUtils.copyProperties(entitys.get(0), dto);
    return dto;
  }

  @Override
  @DatabaseWriteOnly
  public Integer deleteByPK(String uuid)
  {
    CpProjectEnvSys envSys = this.cpProjectEnvSysService.findByPrimaryKey(uuid);
    if (envSys == null){
      throw new PlatformRuntimeException(ProjectAppError.PROJECT_ENV_SYS_IS_NULL);
    }
    CpProjectEnvSys entity = new CpProjectEnvSys();
    entity.setProjectId(envSys.getProjectId());
    entity.setSysName(envSys.getSysName());
    return this.cpProjectEnvSysService.deleteByExample(entity);
  }

  @Override
  public List<String> addBatch(List<CpProjectEnvSysAddDto> batch)
  {
    List<String> result = new ArrayList<>();
    for (CpProjectEnvSysAddDto dto : batch)
    {
      result.add(this.add(dto));
    }
    return result;
  }

  @Override
  public Integer updateBatch(List<CpProjectEnvSysUpdateDto> batch) throws IllegalAccessException
  {
    int sum = 0;
    for (CpProjectEnvSysUpdateDto dto : batch)
    {
      sum = sum + this.updateByPK(dto);
    }
    return sum;
  }

  @Override
  public Integer deleteBatch(List<Object> batch)
  {
    return this.cpProjectEnvSysService.deleteByPrimaryKeys(batch);
  }

  @Override
  public List<CpProjectEnvSysSelectDto> findSelect(String projectId, String envId) {
    List<CpProjectEnvSysSelectDto> resultList = new ArrayList<>();
    CpProjectEnvSys params = new CpProjectEnvSys();
    params.setProjectId(projectId);
    params.setEnvId(envId);
    List<CpProjectEnvSys> envSysList = this.cpProjectEnvSysService.query(params);
    if (envSysList == null || envSysList.size() <= 0){
      return resultList;
    }
    for (CpProjectEnvSys envSys : envSysList) {
      CpProjectEnvSysSelectDto selectDto = new CpProjectEnvSysSelectDto();
      selectDto.setLabel(envSys.getSysName());
      selectDto.setValue(envSys.getId());
      selectDto.setSysUrl(envSys.getSysUrl());
      resultList.add(selectDto);
    }
    return resultList;
  }

    @Override
    public String querySysUrl(CpProjectEnvSysUrlSearchDto searchDto) {
      CpProjectEnvSys params = new CpProjectEnvSys();
      BeanUtils.copyProperties(searchDto, params);
      List<CpProjectEnvSys> envSysList = this.cpProjectEnvSysService.query(params);
      if (envSysList == null || envSysList.size() <= 0){
        throw new PlatformRuntimeException(ProjectAppError.PROJECT_ENV_SYS_IS_NULL);
      }
      CpProjectEnvSys envSys = envSysList.get(0);
      if (StringUtils.isBlank(envSys.getSysUrl())){
        throw new PlatformRuntimeException(ProjectAppError.PROJECT_ENV_SYS_URL_IS_NULL);
      }
      return envSys.getSysUrl();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncProjectEnvSys(String projectId, List<String> envIds) {
      // 删除不在修改的环境数据源信息
      CpProjectEnvSysDeleteDto deleteDto = new CpProjectEnvSysDeleteDto();
      deleteDto.setTenantId(NKSecurityContext.getTenantId());
      deleteDto.setProjectId(projectId);
      deleteDto.setEnvIds(envIds);
      cpProjectEnvSysService.deleteByProjectIdNoInEnvIds(deleteDto);

      // 查询剩余的环境被测系统信息
      CpProjectEnvSys params = new CpProjectEnvSys();
      params.setTenantId(NKSecurityContext.getTenantId());
      params.setProjectId(projectId);
      List<CpProjectEnvSys> envDsList = cpProjectEnvSysService.query(params);
      if (envDsList != null && envDsList.size() > 0){
        List<String> oldEnvIds = envDsList.stream().map(CpProjectEnvSys::getEnvId).collect(Collectors.toList());
        List<String> diffEnvIds = new ArrayList<>(envIds);
        diffEnvIds.removeAll(oldEnvIds);
        if (diffEnvIds.size() > 0){
          CpProjectEnvSys cpProjectEnvSys = envDsList.get(0);
          List<CpProjectEnvSys> sysBatchList = new ArrayList<>();
          for (String envId : diffEnvIds) {
            CpProjectEnvSys newEnvSys = new CpProjectEnvSys();
            newEnvSys.setId(UUIDUtil.create32UUID());
            newEnvSys.setTenantId(NKSecurityContext.getTenantId());
            newEnvSys.setProjectId(projectId);
            newEnvSys.setEnvId(envId);
            newEnvSys.setSysName(cpProjectEnvSys.getSysName());
            newEnvSys.setCreatedBy(NKSecurityContext.getUserId());
            newEnvSys.setCreatedTime(new Date());
            newEnvSys.setUpdatedBy(NKSecurityContext.getUserId());
            newEnvSys.setUpdatedTime(new Date());
            sysBatchList.add(newEnvSys);
          }
          cpProjectEnvSysService.insertByBatch(sysBatchList);
        }
      }
    }

}
