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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
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.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.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.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.SimpleStorageService;
import net.northking.cctp.common.security.authentication.NKSecurityContext;
import net.northking.cctp.common.util.UUIDUtil;
import net.northking.cctp.scriptcase.api.caseDataSet.service.AtuCaseDataSetApiService;
import net.northking.cctp.scriptcase.bus.AppRabbitMQPublisher;
import net.northking.cctp.scriptcase.bus.LogRabbitMQPublisher;
import net.northking.cctp.scriptcase.constants.ScriptConstant;
import net.northking.cctp.scriptcase.db.entity.App;
import net.northking.cctp.scriptcase.db.service.AppService;
import net.northking.cctp.scriptcase.dto.app.*;
import net.northking.cctp.scriptcase.enums.MobileError;
import net.northking.cctp.scriptcase.enums.ScriptCaseAppError;
import net.northking.cctp.scriptcase.feign.AttachmentFeignClient;
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.boot.autoconfigure.condition.ConditionalOnMissingBean;
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.util.*;

/**
 * 应用表服务实现类
 *
 * @author maven-cctp-plugin
 * @since 1.0
 */

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

  @Autowired
  private AppService appService;

  @Autowired
  private SimpleStorageService simpleFileStorage;

  @Autowired
  private RedisTemplate<String, String> redisTemplate;

  @Autowired
  private LogRabbitMQPublisher logPublisher;

  @Autowired
  private AppRabbitMQPublisher appPublisher;

  @Autowired
  private EntityNameCache entityNameCache;

  @Autowired
  private AtuCaseDataSetApiService caseDataSetApiService;

  @Autowired
  private MonsterCommonFeignClient monsterCommonFeignClient;

  @Autowired
  private AttachmentFeignClient attachmentFeignClient;

  private static String MINIO_URL;

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

  @Override
  public ExcelHeader[] excelHeaders()
  {
    ExcelHeader id = new ExcelHeader("应用id", "id", String.class);
    ExcelHeader appName = new ExcelHeader("应用名称", "appName", String.class);
    ExcelHeader appSize = new ExcelHeader("应用大小", "appSize", String.class);
    ExcelHeader packageName = new ExcelHeader("包名称", "packageName", String.class);
    ExcelHeader buildVersion = new ExcelHeader("构建版本", "buildVersion", String.class);
    ExcelHeader platform = new ExcelHeader("平台类型$$$0-android,1-IOS", "platform", String.class);
    ExcelHeader appUrl = new ExcelHeader("脚本文件地址", "appUrl", String.class);
    ExcelHeader versionMark = new ExcelHeader("版本说明", "versionMark", String.class);
    ExcelHeader ownerId = new ExcelHeader("设备归属对象ID", "ownerId", String.class);
    ExcelHeader tenantId = new ExcelHeader("租户ID", "tenantId", String.class);
    ExcelHeader appIcon = new ExcelHeader("app图标", "appIcon", ArrayList.class);
    ExcelHeader remarks = new ExcelHeader("备注", "remarks", String.class);
    ExcelHeader versionCode = new ExcelHeader("版本编号", "versionCode", Integer.class);
    ExcelHeader activity = new ExcelHeader("activity", "activity", 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<App> beforeInsertBatch(List<App> records)
  {
    for (App record : records)
    {
      record.setId(UUIDUtil.create32UUID());
    }
    return records;
  }

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

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

  //= 增删改查 相关代码 start ==================//
  @Override
  @DatabaseReadOnly
  public Pagination<AppDetailDto> pagingQuery(QueryByPage<AppQueryDto> queryByPage)
  {
    AppQueryDto query = queryByPage.getQuery();
    Pagination<AppDetailDto> result = new DefaultPagination<>();
    if (queryByPage.getOrderByList().isEmpty()) {
      queryByPage.addQueryOrderByDesc(ScriptConstant.ORDER_BY_UPDATE_TIME);
    }

    String creatorName = query.getCreatedByName();
    if (!StringUtils.isEmpty(creatorName)) {
      List<String> creatorList = new ArrayList<>();
      List<AppCreator> creators = this.appService.queryCreator(query);
      if (CollectionUtils.isEmpty(creators)) {
        return result;
      } else {
        for (AppCreator creator : creators) {
          String name = entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, creator.getCreator());
          if (!StringUtils.isEmpty(name)) {
            if (name.contains(creatorName)) {
              creatorList.add(creator.getCreator());
            }
          }
        }
      }
      query.setCreatorList(creatorList);//更新人列表
    }

    if (!StringUtils.isEmpty(creatorName) && CollectionUtils.isEmpty(query.getCreatorList())) {
      return result;
    }
    query.setTenantId(NKSecurityContext.getTenantId());
    queryByPage.setQuery(query);
    result = this.appService.myPagingQuery(queryByPage);
    List<AppDetailDto> records = result.getRecords();
    if (records != null) {
      for (AppDetailDto record : records) {
        Map<String, Object> manifest = new HashMap<>(8);
        String platform = record.getPlatform();
        if (ScriptConstant.MOB_PLATFORM_IOS.equals(platform)) {
          manifest.put(ScriptConstant.MOB_PACKAGE, record.getPackageName());
          manifest.put(ScriptConstant.VERSION_CODE, record.getVersionCode());
          manifest.put(ScriptConstant.VERSION_NAME, record.getBuildVersion());
        } else if (ScriptConstant.MOB_PLATFORM_ANDROID.equals(platform)) {
          manifest.put(ScriptConstant.MOB_PACKAGE, record.getPackageName());
          Map<String, Object> application = new HashMap<>(8);
          List<Map<String, String>> launcherActivities = new ArrayList<>();
          Map<String, String> params = new HashMap<>(8);
          params.put(ScriptConstant.NAME, record.getActivity());
          launcherActivities.add(params);
          application.put(ScriptConstant.LAUNCHER_ACTIVE, launcherActivities);
          manifest.put(ScriptConstant.APPLICATION, application);
        }
        record.setManifest(manifest);
        record.setCreatedByName(entityNameCache.translateById(EntityNameCatalog.MONSTER_USER.name(), record.getCreatedBy()));

      }
    }


    return result;
  }

  @Override
  public String add(AppAddDto dto)
  {
    return addFunc(dto);
  }

  @Transactional
  public String addFunc(AppAddDto dto){
    String oldPlatform = dto.getOldPlatform();
    String oldPackageName = dto.getOldPackageName();
    String newPlatform = dto.getPlatform();
    String newPackageName = dto.getPackageName();
    if (StringUtils.hasText(oldPackageName) && StringUtils.hasText(oldPlatform)) {
      //相同包名校验
      if (!oldPackageName.equals(newPackageName)) {
        throw new PlatformRuntimeException(ScriptCaseAppError.APP_UPLOAD_NAME_ERR);
      }
      //安卓支持安卓+鸿蒙应用替换
      if (oldPlatform.equals(ScriptConstant.PLATFORM_ANDROID)) {
        if (!(newPlatform.equals(ScriptConstant.PLATFORM_ANDROID) || newPlatform.equals(ScriptConstant.PLATFORM_HARMONY))) {
          throw new PlatformRuntimeException(ScriptCaseAppError.APP_UPLOAD_PLATFORM_ERR);
        }
      }else {
        //ios和鸿蒙仅支持同平台应用替换
        if (!oldPlatform.equals(newPlatform)) {
          throw new PlatformRuntimeException(ScriptCaseAppError.APP_UPLOAD_NAME_ERR);
        }
      }
    }
    App app = new App();
    app.setTenantId(NKSecurityContext.getTenantId());
    app.setPlatform(dto.getPlatform());
    app.setPackageName(dto.getPackageName());
    app.setBuildVersion(dto.getBuildVersion());
    app.setOwnerId(dto.getOwnerId());
    long count = appService.count(app);
    String[] appUrlSplit = MinioPathUtils.idToPath(dto.getAppUrl());
    if (count > 0) {   //防止重复添加
      try {
        simpleFileStorage.delete(NKSecurityContext.getTenantId(), "/"+appUrlSplit[1]);
      }catch (Exception e){
        logger.error("删除app应用异常", e);
      }
      throw new InvalidException("该应用已存在相同版本" + dto.getBuildVersion() + "，请检查");
    }

    String uuid = UUIDUtil.create32UUID();
    App entity = new App();
    BeanUtils.copyProperties(dto, entity);
    entity.setId(uuid);
    this.appService.insert(entity);
    //保存成功删除redis临时清理文件路径
    redisTemplate.delete(ScriptConstant.ATU_MOB_APP + appUrlSplit[1]);
    // 关联文件记录
    ArrayList<String> fileIds = new ArrayList<>();
    fileIds.add("/" + appUrlSplit[1]);
    AssociatedFilesDto associatedFilesDto = new AssociatedFilesDto();
    associatedFilesDto.setObjId(uuid);
    associatedFilesDto.setFileIds(fileIds);
    ResultWrapper<String> wrapper = attachmentFeignClient.associatedFiles(associatedFilesDto);
    if (wrapper == null || !wrapper.isSuccess()) {
      throw new InvalidException("文件关联异常");
    }
    return uuid;
  }


  @Override
  @DatabaseWriteOnly
  public Integer updateByPK(AppUpdateDto dto) throws IllegalAccessException
  {
    App entity = new App();
    BeanUtils.copyProperties(dto, entity);
    return this.appService.updateByPrimaryKey(entity);
  }

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

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

  @Override
  @Transactional
  public Integer deleteByPK(String id)
  {
    App entity = new App();
    entity.setId(id);
    AppDetailDto appDetailDto = this.findByPK(id);
    int i;
    if (appDetailDto != null) {
      String[] pathData = MinioPathUtils.idToPath(appDetailDto.getAppUrl());
      try {
        simpleFileStorage.delete(pathData[0], "/" + pathData[1]);
      } catch (Exception e) {
        throw new PlatformRuntimeException(ScriptCaseAppError.APP_DEL_ERR);
      }
      i = this.appService.deleteByExample(entity);
    } else {
      throw new PlatformRuntimeException(MobileError.APP_IS_NULL);
    }
    //删除应用增加平台日志
    CpLogAddDto cpLogAddDto = new CpLogAddDto();
    String projectName = entityNameCache.translateById(EntityNameCatalog.MONSTER_SYSTEM.name(), appDetailDto.getOwnerId());
    String content = String.format(ScriptConstant.DEL_APP_MSG,projectName,appDetailDto.getAppName());
    cpLogAddDto.setContent(content);
    cpLogAddDto.setModule(ScriptConstant.APP_MGR_MODULE);
    cpLogAddDto.setType(ScriptConstant.LOG_DEL_STATUS);
    MonsterLogServer.sendLogToMonster(cpLogAddDto);
    logPublisher.deployLogContent(cpLogAddDto);
    //发送删除应用ID到mq
    AppDeleteDto appDeleteDto = new AppDeleteDto();
    appDeleteDto.setAppId(id);
    appPublisher.sendDeleteAppInfo(appDeleteDto);
    return i;
  }

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

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

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


  @Override
  public AppDetailDto getAppDetail(String appId) {
    App app = this.appService.findByPrimaryKey(appId);
    if (null == app) {
      return null;
    }
    AppDetailDto dto = new AppDetailDto();
    BeanUtils.copyProperties(app, dto);
    dto.setAppUrl(MINIO_URL + "/" + dto.getAppUrl());
    String fileType = dto.getAppUrl().substring(dto.getAppUrl().lastIndexOf("."));
    dto.setAppName(dto.getAppName() + "_" + dto.getBuildVersion() + fileType);
    return dto;
  }

  @Override
  public List<AppDetailDto> queryByIds(List<String> ids) {
    List<AppDetailDto> resultList = new ArrayList<>();
    List<App> appList = this.appService.checkAppAlive(ids);
    if (appList == null || appList.size() <= 0){
      return resultList;
    }
    for (App app : appList) {
      AppDetailDto dto = new AppDetailDto();
      BeanUtils.copyProperties(app, dto);
      resultList.add(dto);
    }
    return resultList;
  }

    @Override
    public Pagination<AtuAppVersionDto> pagingQueryAppVersions(QueryByPage<AppVersionQueryDto> queryByPage) {
      Pagination<AtuAppVersionDto> result = new DefaultPagination<>();
      if (queryByPage.getOrderByList().isEmpty()) {
        queryByPage.addQueryOrderByDesc(ScriptConstant.ORDER_BY_UPDATE_TIME);
      }
      AppVersionQueryDto query = queryByPage.getQuery();
      List<String> platforms = new ArrayList<>();
      if (StrUtil.isNotBlank(query.getPlanId())){
        // 查询计划绑定的脚本平台类型
        platforms = caseDataSetApiService.queryScriptPlatforms(query.getPlanId());
        if (CollUtil.isEmpty(platforms)){
          logger.info("计划平台类型为空");
          return result;
        }
      }else if(StrUtil.isNotBlank(query.getPlatform())){
        platforms.add(query.getPlatform());
      }
      query.setPlatforms(platforms);
      Pagination<App> appPage = this.appService.PagingQueryGroupByPackage(queryByPage);
      List<App> records = appPage.getRecords();
      if (CollUtil.isEmpty(records)){
        return result;
      }
      List<AtuAppVersionDto> appVersionDtoList = new ArrayList<>();
      for (App app : records) {
        App queryParams = new App();
        queryParams.setPlatform(app.getPlatform());
        queryParams.setPackageName(app.getPackageName());
        queryParams.setOwnerId(app.getOwnerId());
        List<App> appList = this.appService.queryAppList(queryParams);
        if (CollUtil.isNotEmpty(appList)) {
          appList.forEach(one -> {
            String createdBy = entityNameCache.translateById(EntityNameCatalog.MONSTER_USER, one.getCreatedBy());
            one.setCreatedBy(createdBy);
          });
        }
        AtuAppVersionDto appVersionDto = new AtuAppVersionDto();
        appVersionDto.setAppList(appList);
        appVersionDtoList.add(appVersionDto);
      }
      BeanUtils.copyProperties(appPage, result);
      result.setRecords(appVersionDtoList);
      return 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 = appService.selectCreatorByProject(projectId);
      if (!CollectionUtils.isEmpty(creatorList)) {
        creatorList.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));
        }
      });
      return options;
    }
}
