package com.microservices.pms.productLibrary.service.impl;

import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.PageUtils;
import com.microservices.common.core.utils.ServletUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.web.page.GenericsTableDataInfo;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.pms.enterprise.domain.PmsEnterprise;
import com.microservices.pms.enterprise.service.IPmsEnterpriseService;
import com.microservices.pms.productLibrary.domain.PmsProductLibraryComponent;
import com.microservices.pms.productLibrary.domain.PmsProductLibraryRepositories;
import com.microservices.pms.productLibrary.domain.ProductLibraryRepositoriesFormatEnum;
import com.microservices.pms.productLibrary.domain.vo.*;
import com.microservices.pms.productLibrary.mapper.PmsProductLibraryComponentMapper;
import com.microservices.pms.productLibrary.mapper.PmsProductLibraryRepositoriesMapper;
import com.microservices.pms.productLibrary.service.IPmsProductLibraryAsyncService;
import com.microservices.pms.productLibrary.service.IPmsProductLibraryComponentService;
import com.microservices.pms.productLibrary.service.IPmsProductLibraryProductRepoService;
import com.microservices.pms.productLibrary.service.IPmsProductLibraryRepositoriesService;
import com.microservices.pms.utils.NexusRequestHelper;
import com.microservices.pms.utils.NexusRequestUrl;
import com.microservices.pms.utils.PmsUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * @author OTTO
 */
@Service
public class PmsProductLibraryProductRepoServiceImpl implements IPmsProductLibraryProductRepoService {

    @Autowired
    private PmsProductLibraryRepositoriesMapper pmsProductLibraryRepositoriesMapper;
    @Autowired
    private PmsProductLibraryComponentMapper pmsProductLibraryComponentMapper;
    @Autowired
    private NexusRequestHelper nexusRequestHelper;
    @Autowired
    private IPmsEnterpriseService pmsEnterpriseService;
    @Autowired
    private IPmsProductLibraryAsyncService pmsProductLibraryAsyncService;
    @Autowired
    private IPmsProductLibraryComponentService pmsProductLibraryComponentService;
    @Autowired
    private IPmsProductLibraryRepositoriesService pmsProductLibraryRepositoriesService;

    @Override
    public PmsProductLibraryRepositoriesDataVo selectPmsProductLibraryDataByName(String enterpriseIdentifier, String repoName) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories =
                selectPmsProductLibraryByName(enterpriseIdentifier, repoName);
        return pmsProductLibraryRepositories.toPmsProductLibraryRepositoriesDataVo();
    }


    @Override
    public PmsProductLibraryRepositories selectPmsProductLibraryByName(String enterpriseIdentifier, String name) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories =
                pmsProductLibraryRepositoriesMapper.selectPmsProductLibraryByName(enterpriseIdentifier, name);
        if (pmsProductLibraryRepositories == null) {
            throw new ServiceException("组织下不存在该产品库(组织标识[%s],产品库名称[%s])", enterpriseIdentifier, name);
        }
        return pmsProductLibraryRepositories;
    }

    @Override
    public GenericsTableDataInfo<PmsProductLibrarySimpleVo> selectPmsProductLibraryPageList(String enterpriseIdentifier, String name) {
        return PageUtils.toPage(
                pmsProductLibraryRepositoriesMapper.selectPmsProductLibraryList(enterpriseIdentifier, name),
                PmsProductLibraryRepositories::toPmsProductLibrarySimpleVo);
    }

    @Override
    public int updatePmsProductLibrary(ProductRepositoriesOperateVo productRepositoriesOperateVo) {
        PmsProductLibraryRepositories oldRepo = selectPmsProductLibraryByName(
                productRepositoriesOperateVo.getEnterpriseIdentifier(),
                productRepositoriesOperateVo.getName());
        // 构建更新对象
        PmsProductLibraryRepositories pmsProductLibraryRepositories = productRepositoriesOperateVo.toPmsProductLibraryRepositories();
        pmsProductLibraryRepositories.setId(oldRepo.getId());
        pmsProductLibraryRepositories.setUpdateTime(DateUtils.getNowDate());
        pmsProductLibraryRepositories.setUpdateBy(SecurityUtils.getUsername());
        NexusHostedRepoInputVo requestBody = productRepositoriesOperateVo.toNexusRepoDataVo();

        // 调用制品库更新接口更新制品库
        nexusRequestHelper.doRequest(
                NexusRequestUrl.UPDATE_REPOSITORIES(
                        requestBody.getType(),
                        requestBody.getFormat(),
                        requestBody.getName()),
                JSONObject.from(requestBody)
        );

        return pmsProductLibraryRepositoriesMapper.updatePmsProductLibraryRepositories(pmsProductLibraryRepositories);
    }


    @Override
    public int insertPmsProductLibrary(ProductRepositoriesInputVo productRepositoriesInputVo) {
        PmsEnterprise pmsEnterprise = pmsEnterpriseService.selectPmsEnterpriseByIdentifier(productRepositoriesInputVo.getEnterpriseIdentifier());
        // 校验制品库名称
        Integer count = pmsProductLibraryRepositoriesMapper.selectPmsProductLibraryRepositoriesByNameCount(
                productRepositoriesInputVo.getName(), productRepositoriesInputVo.getEnterpriseIdentifier(), productRepositoriesInputVo.getFormat());
        if (count > 0) {
            throw new ServiceException("该产品库名称在当前企业下已存在(产品库名称[%s])", productRepositoriesInputVo.getName());
        }
        NexusHostedRepoInputVo requestBody = productRepositoriesInputVo.toNexusRepoDataVo();

        // 调用制品库创建接口创建产品库
        nexusRequestHelper.doRequest(
                NexusRequestUrl.ADD_REPOSITORIES(
                        requestBody.getType(),
                        requestBody.getFormat()),
                JSONObject.from(requestBody)
        );
        // 数据库添加该制品库
        PmsProductLibraryRepositories pmsProductLibraryRepositories = productRepositoriesInputVo.toPmsProductLibraryRepositories();
        pmsProductLibraryRepositories.setPmsEnterpriseId(pmsEnterprise.getId());
        pmsProductLibraryRepositories.setDeptId(pmsEnterprise.getDeptId());
        pmsProductLibraryRepositories.setCreateTime(DateUtils.getNowDate());
        pmsProductLibraryRepositories.setCreateBy(SecurityUtils.getUsername());
        return pmsProductLibraryRepositoriesMapper.insertPmsProductLibraryRepositories(pmsProductLibraryRepositories);
    }

    @Override
    public int deletePmsProductLibraryByName(String enterpriseIdentifier, String name) {
        PmsProductLibraryRepositories oldRepo = selectPmsProductLibraryByName(enterpriseIdentifier, name);
        // 调用制品库删除接口删除制品库
        nexusRequestHelper.doRequest(
                NexusRequestUrl.DELETE_REPOSITORIES(PmsProductLibraryRepositories.getNexusProductRepositoriesName(enterpriseIdentifier, name))
        );
        return pmsProductLibraryRepositoriesMapper.deletePmsProductLibraryRepositoriesById(oldRepo.getId());
    }

    @Override
    public boolean addCommonAssetToProductRepo(CommonAssetAddToProductRepoVo commonAssetAddToProductRepoVo) {
        // 先校验产品库、制品库、制品库下制品Id列表是否存在，再进行异步处理
        PmsProductLibraryRepositories productRepo = selectPmsProductLibraryByName(
                commonAssetAddToProductRepoVo.getEnterpriseIdentifier(),
                commonAssetAddToProductRepoVo.getProductRepoName());
        PmsProductLibraryRepositories repo =
                pmsProductLibraryRepositoriesService.selectPmsProductLibraryRepositoriesByName(
                        commonAssetAddToProductRepoVo.getEnterpriseIdentifier(),
                        commonAssetAddToProductRepoVo.getRepoName());
        if (ProductLibraryRepositoriesFormatEnum.DOCKER.getKey().equals(repo.getFormat())) {
            throw new ServiceException("Docker制品移入不能使用该接口");
        }
        List<NexusAssetResultDataVo> nexusAssetResultDataVoList = new ArrayList<>();
        for (String assetId : commonAssetAddToProductRepoVo.getAssetIdList()) {
            NexusComponentResultVo<NexusAssetResultDataVo> nexusAssetResultVo = pmsProductLibraryComponentService.getAssetDetailByAssetId(
                    commonAssetAddToProductRepoVo.getEnterpriseIdentifier(),
                    commonAssetAddToProductRepoVo.getRepoName(),
                    null,
                    assetId,
                    false
            );
            if (nexusAssetResultVo == null || nexusAssetResultVo.getResult() == null || !nexusAssetResultVo.getResult().getSuccess()) {
                throw new ServiceException("该制品不存在(制品库[%s],制品Id[%s])", commonAssetAddToProductRepoVo.getRepoName(), assetId);
            } else {
                nexusAssetResultDataVoList.add(nexusAssetResultVo.getResult().getData());
            }
        }
        pmsProductLibraryAsyncService.asyncAddCommonAssetToProductRepo(productRepo, repo, nexusAssetResultDataVoList);
        return true;
    }

    @Override
    public NexusComponentResultVo<List<NexusResultDataVo>> selectPmsProductLibraryKeyComponentList(String enterpriseIdentifier, ComponentSearchVo componentSearchVo) {
        PmsProductLibraryRepositories productRepo =
                pmsProductLibraryComponentService.getPmsProductLibraryRepositories(true, enterpriseIdentifier, componentSearchVo.getProductRepoName(), null);
        PmsProductLibraryComponent productComponentSearch = new PmsProductLibraryComponent();
        productComponentSearch.setRepoId(productRepo.getId());
        List<PmsProductLibraryComponent> productComponentList = pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentList(productComponentSearch);
        PmsProductLibraryRepositories repo =
                pmsProductLibraryComponentService.getPmsProductLibraryRepositories(false, enterpriseIdentifier, componentSearchVo.getRepositoryName(), null);
        componentSearchVo.setRepositoryName(repo.getNexusRepositoriesName());
        // Docker类型调用Nexus获取制品列表接口获取
        if (ProductLibraryRepositoriesFormatEnum.DOCKER.getKey().equals(repo.getFormat())) {
            List<NexusResultDataVo> keyNexusResultDataVoList = new ArrayList<>();
            // 需循环遍历获取所有镜像列表
            boolean isAll = false;
            // Nexus分页Token
            String continuationToken = null;
            while (!isAll) {
                NexusComponentAndAssetListVo<NexusDockerComponentVo> assetListVo = nexusRequestHelper.doRequestToJavaObject(
                        NexusRequestUrl.GET_COMPONENTS(repo.getNexusRepositoriesName(), continuationToken),
                        NexusComponentAndAssetListVo.class,
                        NexusDockerComponentVo.class);
                if (assetListVo != null) {
                    if (StringUtils.isEmpty(assetListVo.getContinuationToken())) {
                        isAll = true;
                    } else {
                        continuationToken = assetListVo.getContinuationToken();
                    }
                    for (NexusDockerComponentVo nexusDockerComponentVo : assetListVo.getItems()) {
                        NexusResultDataVo nexusResultDataVo = nexusDockerComponentVo.toNexusResultDataVo();
                        keyNexusResultDataVoList.add(nexusResultDataVo);
                    }
                } else {
                    isAll = true;
                }

            }
            return buildDockerResultVo(keyNexusResultDataVoList);
        } else {
            NexusComponentSearchVo<ComponentSearchVo> nexusComponentSearchVo = NexusComponentSearchVo.toRead(componentSearchVo, nexusRequestHelper.getNexusTid());
            NexusComponentResultVo<List<NexusResultDataVo>> assetResultDataVo = nexusRequestHelper.doRequestToJavaObjectList(
                    NexusRequestUrl.DO_OPERATION(),
                    JSONObject.from(nexusComponentSearchVo),
                    NexusComponentResultVo.class,
                    NexusResultDataVo.class
            );
            if (assetResultDataVo != null && assetResultDataVo.getResult() != null) {
                NexusComponentResultStateVo<List<NexusResultDataVo>> nexusComponentResultStateVo = assetResultDataVo.getResult();
                if (nexusComponentResultStateVo.getSuccess()) {
                    List<NexusResultDataVo> nexusResultDataVoList = nexusComponentResultStateVo.getData();
                    setNexusResultDataVoChoose(repo, productComponentList, nexusResultDataVoList);
                    // 当制品库为Maven时，需排除自动生成的制品数据
                    if (ProductLibraryRepositoriesFormatEnum.MAVEN.getKey().equals(repo.getFormat())) {
                        List<NexusResultDataVo> keyNexusResultDataVoList = new ArrayList<>();
                        for (NexusResultDataVo nexusResultDataVo : nexusResultDataVoList) {
                            // 当类型为asset时，需检查数据库是否存在记录，若存在则返回
                            if ("asset".equals(nexusResultDataVo.getType())) {
                                PmsProductLibraryComponent pmsProductLibraryComponent =
                                        pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentByPath(
                                                nexusResultDataVo.getId(),
                                                repo.getId(),
                                                repo.getPmsEnterpriseId()
                                        );
                                if (pmsProductLibraryComponent != null) {
                                    keyNexusResultDataVoList.add(nexusResultDataVo);
                                }
                            } else {
                                keyNexusResultDataVoList.add(nexusResultDataVo);
                            }
                        }
                        nexusComponentResultStateVo.setData(keyNexusResultDataVoList);
                        assetResultDataVo.setResult(nexusComponentResultStateVo);
                    }
                }
            }
            return assetResultDataVo;
        }
    }

    private void setNexusResultDataVoChoose(PmsProductLibraryRepositories repo, List<PmsProductLibraryComponent> productComponentList, List<NexusResultDataVo> nexusResultDataVoList) {
        for (PmsProductLibraryComponent component : productComponentList) {
            nexusResultDataVoList.forEach(x -> {
                String decodeId = ServletUtils.urlDecode(x.getId());
                // 去除多余连接符
                String nexusComponentId = PmsUtils.encodeChineseCharacters(repo.getAlias()) + "/" + decodeId.replaceAll("/-/", "/");
                String componentPath = component.getPath().replaceAll("/-/", "/");
                if (nexusComponentId.equals(componentPath)) {
                    x.setIsChoose(true);
                }
            });
        }
    }

    private NexusComponentResultVo<List<NexusResultDataVo>> buildDockerResultVo(List<NexusResultDataVo> data) {
        NexusComponentResultVo<List<NexusResultDataVo>> target = new NexusComponentResultVo<>();
        target.setAction("coreui_Browse");
        target.setMethod("read");
        target.setTid(1);
        target.setType("rpc");
        NexusComponentResultStateVo<List<NexusResultDataVo>> nexusComponentResultStateVo = new NexusComponentResultStateVo<>();
        nexusComponentResultStateVo.setData(data);
        nexusComponentResultStateVo.setSuccess(true);
        target.setResult(nexusComponentResultStateVo);
        return target;
    }
}
