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

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.constant.CacheConstants;
import com.microservices.common.core.constant.SecurityConstants;
import com.microservices.common.core.exception.ServiceException;
import com.microservices.common.core.utils.DateUtils;
import com.microservices.common.core.utils.ServletUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.redis.service.RedisService;
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.service.*;
import com.microservices.pms.utils.NexusRequestHelper;
import com.microservices.pms.utils.NexusRequestUrl;
import com.microservices.system.api.RemoteFileService;
import com.microservices.system.api.domain.SysFileBytes;
import feign.Response;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * 制品库-制品Service业务层处理
 *
 * @author otto
 * @date 2024-06-27
 */
@Service
public class PmsProductLibraryComponentServiceImpl implements IPmsProductLibraryComponentService {
    private static final Logger logger = LoggerFactory.getLogger(NexusRequestHelper.class);
    @Autowired
    private PmsProductLibraryComponentMapper pmsProductLibraryComponentMapper;
    @Autowired
    private IPmsProductLibraryRepositoriesService pmsProductLibraryRepositoriesService;
    @Autowired
    @Lazy
    private IPmsProductLibraryService pmsProductLibraryProductRepoService;
    @Autowired
    private IPmsProductLibrarySnapshotRepoService pmsProductLibrarySnapshotRepoService;
    @Autowired
    private RemoteFileService fileService;
    @Autowired
    private NexusRequestHelper nexusRequestHelper;
    @Autowired
    private IPmsEnterpriseService pmsEnterpriseService;
    @Autowired
    private IPmsProductLibraryAsyncService pmsProductLibraryAsyncService;
    @Autowired
    private RedisService redisService;

    /**
     * 查询制品库-制品
     *
     * @param id 制品库-制品主键
     * @return 制品库-制品
     */
    @Override
    public PmsProductLibraryComponent selectPmsProductLibraryComponentById(Long id) {
        return pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentById(id);
    }

    /**
     * 查询制品库-制品列表
     *
     * @param enterpriseIdentifier 组织标识
     * @param componentSearchVo    制品库-制品
     * @param isProduct 是否产品
     * @return 制品库-制品
     */
    @Override
    public NexusComponentResultVo<List<NexusResultDataVo>> selectPmsProductLibraryComponentListByNexus(String enterpriseIdentifier, ComponentSearchVo componentSearchVo, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories =
                pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, componentSearchVo.getRepositoryName(), componentSearchVo.getSnapshotRepoName());
        componentSearchVo.setRepositoryName(pmsProductLibraryRepositories.getNexusRepositoriesName());

        NexusComponentSearchVo<ComponentSearchVo> nexusComponentSearchVo = NexusComponentSearchVo.toRead(componentSearchVo, nexusRequestHelper.getNexusTid());
        return nexusRequestHelper.doRequestToJavaObjectList(
                NexusRequestUrl.DO_OPERATION(),
                JSONObject.from(nexusComponentSearchVo),
                NexusComponentResultVo.class,
                NexusResultDataVo.class
        );
    }

    @Override
    public List<PmsProductLibraryComponent> selectPmsProductLibraryComponentListByDatabase(Long repoId) {
        PmsProductLibraryComponent componentSearch = new PmsProductLibraryComponent();
        componentSearch.setRepoId(repoId);
        return pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentList(componentSearch);
    }


    @Override
    public NexusComponentResultVo<NexusAssetResultDataVo> getAssetDetailByAssetId(String enterpriseIdentifier, String repoName, String snapshotName, String assetId, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, repoName, snapshotName);
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toReadAsset(pmsProductLibraryRepositories.getNexusRepositoriesName(), assetId, nexusRequestHelper.getNexusTid());
        NexusComponentResultVo<NexusAssetResultDataVo> assetResultDataVo =
                nexusRequestHelper.doRequestToJavaObject(
                        NexusRequestUrl.DO_OPERATION(),
                        JSONObject.from(nexusComponentSearchVo),
                        NexusComponentResultVo.class,
                        NexusAssetResultDataVo.class
                );
        // 当成功获取制品文件详细信息时，通过数据库解析该制品文件额外属性
        if (assetResultDataVo != null && assetResultDataVo.getResult() != null) {
            NexusComponentResultStateVo<NexusAssetResultDataVo> nexusComponentResultStateVo = assetResultDataVo.getResult();
            if (nexusComponentResultStateVo.getSuccess()) {
                NexusAssetResultDataVo nexusAssetResultDataVo = nexusComponentResultStateVo.getData();
                // 检查数据库中是否已存在该制品文件记录
                PmsProductLibraryComponent pmsProductLibraryComponent =
                        pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentByPath(
                                nexusAssetResultDataVo.getName(),
                                pmsProductLibraryRepositories.getId(),
                                pmsProductLibraryRepositories.getPmsEnterpriseId()
                        );
                if (pmsProductLibraryComponent != null) {
                    nexusAssetResultDataVo.setFileIdentifier(pmsProductLibraryComponent.getFileIdentifier());
                    nexusAssetResultDataVo.setVersion(pmsProductLibraryComponent.getVersion());
                    nexusAssetResultDataVo.setFileName(pmsProductLibraryComponent.getName());
                    if (ProductLibraryRepositoriesFormatEnum.isNexusRaw(pmsProductLibraryRepositories.getFormat())) {
                        String customAttributeStr = pmsProductLibraryComponent.getAttributes();
                        if (StringUtils.isNotEmpty(customAttributeStr)) {
                            JSONObject customAttribute = JSONObject.parseObject(customAttributeStr);
                            JSONObject attributes = nexusAssetResultDataVo.getAttributes();
                            attributes.put("customAttribute", customAttribute);
                            nexusAssetResultDataVo.setAttributes(attributes);
                        }
                    }
                }
                // 当制品版本为空时解析并返回制品文件版本
                if (StringUtils.isEmpty(nexusAssetResultDataVo.getVersion())) {
                    nexusAssetResultDataVo.setVersion(nexusAssetResultDataVo.parseNexusVersion());
                }
                if (StringUtils.isEmpty(nexusAssetResultDataVo.getFileName())) {
                    nexusAssetResultDataVo.setFileName(nexusAssetResultDataVo.parseFileName());
                }
                nexusAssetResultDataVo.setDirectory(nexusAssetResultDataVo.parseDirectory());
                nexusComponentResultStateVo.setData(nexusAssetResultDataVo);
                assetResultDataVo.setResult(nexusComponentResultStateVo);
            }
        }
        return assetResultDataVo;
    }

    @Override
    public NexusComponentResultVo<NexusComponentResultDataVo> getComponentDetailByComponentId(String enterpriseIdentifier, String repoName, String snapshotName, String componentId, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, repoName, snapshotName);
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toReadComponent(pmsProductLibraryRepositories.getNexusRepositoriesName(), componentId, nexusRequestHelper.getNexusTid());
        NexusComponentResultVo<NexusComponentResultDataVo> componentResultVo =
                nexusRequestHelper.doRequestToJavaObject(
                        NexusRequestUrl.DO_OPERATION(),
                        JSONObject.from(nexusComponentSearchVo),
                        NexusComponentResultVo.class,
                        NexusComponentResultDataVo.class
                );
        // 当制品库格式为RAW时，设置版本号
        if (ProductLibraryRepositoriesFormatEnum.isNexusRaw(pmsProductLibraryRepositories.getFormat())) {
            // 当成功获取制品文件详细信息时，通过数据库解析该制品文件额外属性
            if (componentResultVo != null && componentResultVo.getResult() != null) {
                NexusComponentResultStateVo<NexusComponentResultDataVo> nexusComponentResultStateVo = componentResultVo.getResult();
                if (nexusComponentResultStateVo.getSuccess()) {
                    NexusComponentResultDataVo nexusComponentResultDataVo = nexusComponentResultStateVo.getData();
                    // 检查数据库中是否已存在该制品文件记录
                    PmsProductLibraryComponent pmsProductLibraryComponent =
                            pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentByPath(
                                    nexusComponentResultDataVo.getName(),
                                    pmsProductLibraryRepositories.getId(),
                                    pmsProductLibraryRepositories.getPmsEnterpriseId()
                            );
                    if (pmsProductLibraryComponent != null) {
                        nexusComponentResultDataVo.setVersion(pmsProductLibraryComponent.getVersion());
                    }
                    nexusComponentResultStateVo.setData(nexusComponentResultDataVo);
                    componentResultVo.setResult(nexusComponentResultStateVo);
                }
            }
        }
        return componentResultVo;
    }

    @Override
    public NexusComponentResultVo<Boolean> getCanDeleteFolderByNode(String enterpriseIdentifier, ComponentSearchVo componentSearchVo, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, componentSearchVo.getRepositoryName(), componentSearchVo.getSnapshotRepoName());
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toCanDeleteFolder(pmsProductLibraryRepositories.getNexusRepositoriesName(), componentSearchVo.getNode(), nexusRequestHelper.getNexusTid());
        return nexusRequestHelper.doRequestToJavaObject(
                NexusRequestUrl.DO_OPERATION(),
                JSONObject.from(nexusComponentSearchVo),
                NexusComponentResultVo.class,
                Boolean.class
        );
    }

    @Override
    public NexusComponentResultVo<Boolean> getCanDeleteComponentByComponentId(String enterpriseIdentifier, String repoName, String snapshotName, String componentId, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, repoName, snapshotName);
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toCanDeleteComponent(pmsProductLibraryRepositories.getNexusRepositoriesName(), componentId, nexusRequestHelper.getNexusTid());
        return nexusRequestHelper.doRequestToJavaObject(
                NexusRequestUrl.DO_OPERATION(),
                JSONObject.from(nexusComponentSearchVo),
                NexusComponentResultVo.class,
                Boolean.class
        );
    }

    @Override
    public NexusComponentResultVo<Boolean> getCanDeleteAssetByAssetId(String enterpriseIdentifier, String repoName, String snapshotName, String assetId, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, repoName, snapshotName);
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toCanDeleteAsset(pmsProductLibraryRepositories.getNexusRepositoriesName(), assetId, nexusRequestHelper.getNexusTid());
        return nexusRequestHelper.doRequestToJavaObject(
                NexusRequestUrl.DO_OPERATION(),
                JSONObject.from(nexusComponentSearchVo),
                NexusComponentResultVo.class,
                Boolean.class
        );
    }

    @Override
    public NexusComponentResultVo<List<String>> deleteAssetByAssetId(String enterpriseIdentifier, String repoName, String snapshotName, String assetId, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, repoName, snapshotName);
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(enterpriseIdentifier, pmsProductLibraryRepositories.getId());
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toDeleteAsset(pmsProductLibraryRepositories.getNexusRepositoriesName(), assetId, nexusRequestHelper.getNexusTid());
        NexusComponentResultVo<List<String>> assetResultDataVo =
                nexusRequestHelper.doRequestToJavaObjectList(
                        NexusRequestUrl.DO_OPERATION(),
                        JSONObject.from(nexusComponentSearchVo),
                        NexusComponentResultVo.class,
                        String.class
                );
        deleteDatabaseAsset(pmsProductLibraryRepositories, assetResultDataVo);
        return assetResultDataVo;
    }

    @Override
    public NexusComponentResultVo<List<String>> deleteComponentByComponentId(String enterpriseIdentifier, String repoName, String snapshotName, String componentId, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, repoName, snapshotName);
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(enterpriseIdentifier, pmsProductLibraryRepositories.getId());
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toDeleteComponent(pmsProductLibraryRepositories.getNexusRepositoriesName(), componentId, nexusRequestHelper.getNexusTid());
        NexusComponentResultVo<List<String>> assetResultDataVo =
                nexusRequestHelper.doRequestToJavaObjectList(
                        NexusRequestUrl.DO_OPERATION(),
                        JSONObject.from(nexusComponentSearchVo),
                        NexusComponentResultVo.class,
                        String.class
                );
        deleteDatabaseAsset(pmsProductLibraryRepositories, assetResultDataVo);
        return assetResultDataVo;
    }

    @Override
    public NexusComponentResultVo<Object> deleteFolderByNode(String enterpriseIdentifier, ComponentSearchVo componentSearchVo, boolean isProduct) {
        PmsProductLibraryRepositories pmsProductLibraryRepositories = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(isProduct, enterpriseIdentifier, componentSearchVo.getRepositoryName(), componentSearchVo.getSnapshotRepoName());
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(enterpriseIdentifier, pmsProductLibraryRepositories.getId());
        NexusComponentSearchVo<String> nexusComponentSearchVo =
                NexusComponentSearchVo.toDeleteFolder(pmsProductLibraryRepositories.getNexusRepositoriesName(), componentSearchVo.getNode(), nexusRequestHelper.getNexusTid());
        NexusComponentResultVo<Object> assetResultDataVo =
                nexusRequestHelper.doRequestToJavaObjectList(
                        NexusRequestUrl.DO_OPERATION(),
                        JSONObject.from(nexusComponentSearchVo),
                        NexusComponentResultVo.class,
                        String.class
                );
        // 删除路径下所有制品文件记录
        List<PmsProductLibraryComponent> pmsProductLibraryComponentList =
                pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentUnderThePath(
                        componentSearchVo.getNode(),
                        pmsProductLibraryRepositories.getId(),
                        pmsProductLibraryRepositories.getPmsEnterpriseId()
                );
        for (PmsProductLibraryComponent pmsProductLibraryComponent : pmsProductLibraryComponentList) {
            pmsProductLibraryComponentMapper.deletePmsProductLibraryComponentById(pmsProductLibraryComponent.getId());
        }

        return assetResultDataVo;
    }

    private void deleteDatabaseAsset(PmsProductLibraryRepositories pmsProductLibraryRepositories, NexusComponentResultVo<List<String>> assetResultDataVo) {
        // 当制品库格式为RAW或者Maven时，需检查数据库中是否存在记录，存在记录则需要进行删除
        if (ProductLibraryRepositoriesFormatEnum.isNexusRaw(pmsProductLibraryRepositories.getFormat())
                || ProductLibraryRepositoriesFormatEnum.MAVEN.getKey().equals(pmsProductLibraryRepositories.getFormat())) {

            if (assetResultDataVo != null && assetResultDataVo.getResult() != null) {
                NexusComponentResultStateVo<List<String>> nexusComponentResultStateVo = assetResultDataVo.getResult();
                if (nexusComponentResultStateVo.getSuccess()) {
                    List<String> deletePathList = nexusComponentResultStateVo.getData();
                    for (String deletePath : deletePathList) {
                        // 检查数据库中是否已存在该制品文件记录
                        PmsProductLibraryComponent pmsProductLibraryComponent =
                                pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentByPath(
                                        deletePath,
                                        pmsProductLibraryRepositories.getId(),
                                        pmsProductLibraryRepositories.getPmsEnterpriseId()
                                );
                        if (pmsProductLibraryComponent != null) {
                            pmsProductLibraryComponentMapper.deletePmsProductLibraryComponentById(pmsProductLibraryComponent.getId());
                        }
                    }
                }
            }
        }
    }

    /**
     * 新增制品库-制品
     *
     * @param pmsProductLibraryComponent 制品库-制品
     * @return 结果
     */
    public int insertPmsProductLibraryComponent(PmsProductLibraryComponent pmsProductLibraryComponent) {
        PmsEnterprise pmsEnterprise = pmsEnterpriseService.selectPmsEnterpriseByIdentifier(pmsProductLibraryComponent.getPmsEnterpriseIdentifier());
        PmsProductLibraryComponent oldPmsProductLibraryComponent =
                pmsProductLibraryComponentMapper.selectPmsProductLibraryComponentByPath(
                        pmsProductLibraryComponent.getPath(),
                        pmsProductLibraryComponent.getRepoId(),
                        pmsEnterprise.getId());
        // 当制品文件不存在时新增该文件
        if (oldPmsProductLibraryComponent == null) {
            pmsProductLibraryComponent.setCreateBy(SecurityUtils.getUsername());
            pmsProductLibraryComponent.setCreateTime(DateUtils.getNowDate());
            pmsProductLibraryComponent.setPmsEnterpriseId(pmsEnterprise.getId());
            pmsProductLibraryComponent.setDeptId(pmsEnterprise.getDeptId());
            return pmsProductLibraryComponentMapper.insertPmsProductLibraryComponent(pmsProductLibraryComponent);
        }
        // 当制品文件已存在时更新该文件
        pmsProductLibraryComponent.setId(oldPmsProductLibraryComponent.getId());
        return updatePmsProductLibraryComponent(pmsProductLibraryComponent);
    }

    /**
     * 修改制品库-制品
     *
     * @param pmsProductLibraryComponent 制品库-制品
     * @return 结果
     */
    @Override
    public int updatePmsProductLibraryComponent(PmsProductLibraryComponent pmsProductLibraryComponent) {
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(pmsProductLibraryComponent.getPmsEnterpriseIdentifier(), pmsProductLibraryComponent.getId());
        pmsProductLibraryComponent.setUpdateBy(SecurityUtils.getUsername());
        pmsProductLibraryComponent.setUpdateTime(DateUtils.getNowDate());
        return pmsProductLibraryComponentMapper.updatePmsProductLibraryComponent(pmsProductLibraryComponent);
    }

    @Override
    public Boolean insertMavenComponent(ComponentMavenInputVo componentMavenInputVo) {
        // 构建制品列表，用于数据库记录
        List<PmsProductLibraryComponent> pmsProductLibraryComponents = new ArrayList<>();
        PmsProductLibraryRepositories repo = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(
                false,
                componentMavenInputVo.getEnterpriseIdentifier(),
                componentMavenInputVo.getRepoName(),
                componentMavenInputVo.getSnapshotName()
        );
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(repo.getPmsEnterpriseIdentifier(), repo.getId());
        if (!ProductLibraryRepositoriesFormatEnum.MAVEN.getKey().equals(repo.getFormat())) {
            throw new ServiceException("该制品库非Maven格式，无法上传(制品库标识[%s])", repo.getName());
        }
        // 创建一个MultipartEntityBuilder
        MultipartEntityBuilder builder = MultipartEntityBuilder
                .create()
                .setContentType(ContentType.MULTIPART_FORM_DATA)
                .setCharset(StandardCharsets.UTF_8);
        addTextBody(builder, "maven2.groupId", componentMavenInputVo.getGroupId());
        addTextBody(builder, "maven2.artifactId", componentMavenInputVo.getArtifactId());
        addTextBody(builder, "maven2.version", componentMavenInputVo.getVersion());
        addTextBody(builder, "maven2.generate-pom", String.valueOf(componentMavenInputVo.getGeneratePom()));
        // 若需要生成Pom，则存在一个Pom的制品文件
        if (componentMavenInputVo.getGeneratePom()) {
            pmsProductLibraryComponents.add(componentMavenInputVo.toPmsProductLibraryComponent(repo.getId(), componentMavenInputVo.getPomComponentName()));
        }
        addTextBody(builder, "maven2.packaging", componentMavenInputVo.getPackaging());

        List<AssetMavenInputVo> assetMavenInputVoList = componentMavenInputVo.getAssetList();
        for (int i = 0; i < assetMavenInputVoList.size(); i++) {
            AssetMavenInputVo assetMavenInputVo = assetMavenInputVoList.get(i);
            String componentAssetName = assetMavenInputVo.getComponentAssetName(componentMavenInputVo);
            if (pmsProductLibraryComponents.stream().anyMatch(x -> componentAssetName.equals(x.getName()))) {
                throw new ServiceException("不允许上传重复的制品文件(制品文件名称(%s)", componentAssetName);
            }
            // 将制品的每一个文件创建对应的记录
            PmsProductLibraryComponent componentAsset = componentMavenInputVo.toPmsProductLibraryComponent(repo.getId(), componentAssetName);
            componentAsset.setFileIdentifier(assetMavenInputVo.getFileIdentifier());
            pmsProductLibraryComponents.add(componentAsset);
            addTextBody(builder, String.format("maven2.asset%d.extension", i + 1), assetMavenInputVo.getExtension());
            addTextBody(builder, String.format("maven2.asset%d.classifier", i + 1), assetMavenInputVo.getClassifier());
            SysFileBytes fileBytes;
            if (assetMavenInputVo.getFileBytes() != null) {
                fileBytes = assetMavenInputVo.getFileBytes();
            } else {
                fileBytes = getFeignFile(assetMavenInputVo.getFileIdentifier());
            }
            if (fileBytes.getFileInputStream() == null) {
                throw new ServiceException("制品文件读取失败");
            }
            builder.addBinaryBody(String.format("maven2.asset%d", i + 1), fileBytes.getFileInputStream(), ContentType.DEFAULT_BINARY, fileBytes.getFileName());
        }
        JSONObject bodyLog = toBodyLog(componentMavenInputVo);
        nexusRequestHelper.doRequest(NexusRequestUrl.UPLOAD_COMPONENTS(componentMavenInputVo.getNexusRepoName()), builder.build(), bodyLog);
        // 数据库中插入制品文件记录
        int success = 0;
        for (int i = 0; i < pmsProductLibraryComponents.size(); i++) {
            PmsProductLibraryComponent pmsProductLibraryComponent = pmsProductLibraryComponents.get(i);
            success += insertPmsProductLibraryComponent(pmsProductLibraryComponent);
            pmsProductLibraryComponents.set(i, pmsProductLibraryComponent);
        }
        pmsProductLibraryAsyncService.syncNexusMavenRepoComponent(repo, pmsProductLibraryComponents);
        return success > 0;
    }


    @Override
    public Boolean insertRawComponent(ComponentRawInputVo componentRawInputVo) {
        componentRawInputVo.setDirectory(ServletUtils.urlEncodeExcludeSlashes(componentRawInputVo.getDirectory()));
        // 构建制品列表，用于数据库记录
        List<PmsProductLibraryComponent> pmsProductLibraryComponents = new ArrayList<>();
        PmsProductLibraryRepositories repo = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(
                ProductLibraryRepositoriesFormatEnum.isProduct(componentRawInputVo.getFormat()),
                componentRawInputVo.getEnterpriseIdentifier(),
                componentRawInputVo.getRepoName(),
                componentRawInputVo.getSnapshotName());
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(repo.getPmsEnterpriseIdentifier(), repo.getId());

        if (!componentRawInputVo.getFormat().equals(repo.getFormat())) {
            throw new ServiceException("该制品库非%s格式，无法上传(制品库标识[%s])", componentRawInputVo.getFormat(), repo.getName());
        }
        // 创建一个MultipartEntityBuilder
        MultipartEntityBuilder builder = MultipartEntityBuilder
                .create()
                .setContentType(ContentType.MULTIPART_FORM_DATA)
                .setCharset(StandardCharsets.UTF_8);
        // 对输入目录进行转码，解决Nexus不支持中文目录的问题
        addTextBody(builder, "raw.directory", componentRawInputVo.getDirectory());
        List<AssetRawInputVo> assetRawInputVos = componentRawInputVo.getAssetList();
        for (int i = 0; i < assetRawInputVos.size(); i++) {
            AssetRawInputVo assetRawInputVo = assetRawInputVos.get(i);
            String fileName = ServletUtils.urlEncodeExcludeSlashes(assetRawInputVo.getFilename());
            if (pmsProductLibraryComponents.stream().anyMatch(x -> fileName.equals(x.getName()))) {
                throw new ServiceException("不允许上传重复的制品文件(制品文件名称(%s)", fileName);
            }
            // 将制品的每一个文件创建对应的记录
            PmsProductLibraryComponent componentAsset = componentRawInputVo.toPmsProductLibraryComponent(repo.getId(), fileName);
            componentAsset.setFileIdentifier(assetRawInputVo.getFileIdentifier());
            componentAsset.setIdentifier(assetRawInputVo.getAssetIdentifier());
            pmsProductLibraryComponents.add(componentAsset);
            addTextBody(builder, String.format("raw.asset%d.filename", i + 1), fileName);
            SysFileBytes fileBytes;
            if (assetRawInputVo.getFileBytes() != null) {
                fileBytes = assetRawInputVo.getFileBytes();
            } else {
                fileBytes = getFeignFile(assetRawInputVo.getFileIdentifier());
            }
            if (fileBytes.getFileInputStream() == null) {
                throw new ServiceException("制品文件读取失败");
            }
            builder.addBinaryBody(String.format("raw.asset%d", i + 1), fileBytes.getFileInputStream(), ContentType.DEFAULT_BINARY, fileBytes.getFileName());
        }
        JSONObject bodyLog = toBodyLog(componentRawInputVo);
        nexusRequestHelper.doRequest(NexusRequestUrl.UPLOAD_COMPONENTS(componentRawInputVo.getNexusRepoName()), builder.build(), bodyLog);
        // 数据库中插入制品文件记录
        int success = 0;
        for (int i = 0; i < pmsProductLibraryComponents.size(); i++) {
            PmsProductLibraryComponent pmsProductLibraryComponent = pmsProductLibraryComponents.get(i);
            success += insertPmsProductLibraryComponent(pmsProductLibraryComponent);
            pmsProductLibraryComponents.set(i, pmsProductLibraryComponent);
        }
        return success > 0;
    }

    @Override
    public Boolean insertNpmComponent(ComponentInputVo componentInputVo) {
        PmsProductLibraryRepositories repo = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(
                false,
                componentInputVo.getEnterpriseIdentifier(),
                componentInputVo.getRepoName(),
                componentInputVo.getSnapshotName()
        );
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(repo.getPmsEnterpriseIdentifier(), repo.getId());
        if (!ProductLibraryRepositoriesFormatEnum.NPM.getKey().equals(repo.getFormat())) {
            throw new ServiceException("该制品库非Npm格式，无法上传(制品库标识[%s])", repo.getName());
        }
        // 创建一个MultipartEntityBuilder
        MultipartEntityBuilder builder = MultipartEntityBuilder
                .create()
                .setContentType(ContentType.MULTIPART_FORM_DATA)
                .setCharset(StandardCharsets.UTF_8);
        SysFileBytes fileBytes;
        if (componentInputVo.getFileBytes() != null) {
            fileBytes = componentInputVo.getFileBytes();
        } else {
            fileBytes = getFeignFile(componentInputVo.getFileIdentifier());
        }
        if (fileBytes.getFileInputStream() == null) {
            throw new ServiceException("制品文件读取失败");
        }

        builder.addBinaryBody("npm.asset", fileBytes.getFileInputStream(), ContentType.DEFAULT_BINARY, fileBytes.getFileName());
        JSONObject bodyLog = toBodyLog(componentInputVo);
        try {
            nexusRequestHelper.doRequest(NexusRequestUrl.UPLOAD_COMPONENTS(componentInputVo.getNexusRepoName()), builder.build(), bodyLog);
        } catch (Exception e) {
            logger.error("上传npm制品失败：{}", e.getMessage());
            throw new ServiceException("上传的npm制品文件格式错误，请调整后重新上传");
        }
        return true;
    }

    @Override
    public Boolean insertPypiComponent(ComponentInputVo componentInputVo) {
        PmsProductLibraryRepositories repo = pmsProductLibraryRepositoriesService.getPmsProductLibraryRepositories(
                false,
                        componentInputVo.getEnterpriseIdentifier(),
                componentInputVo.getRepoName(),
                componentInputVo.getSnapshotName());
        pmsProductLibraryRepositoriesService.checkLockRepositoryStatus(repo.getPmsEnterpriseIdentifier(), repo.getId());
        if (!ProductLibraryRepositoriesFormatEnum.PYPI.getKey().equals(repo.getFormat())) {
            throw new ServiceException("该制品库非Pypi格式，无法上传(制品库标识[%s])", repo.getName());
        }
        // 创建一个MultipartEntityBuilder
        MultipartEntityBuilder builder = MultipartEntityBuilder
                .create()
                .setContentType(ContentType.MULTIPART_FORM_DATA)
                .setCharset(StandardCharsets.UTF_8);
        SysFileBytes fileBytes;
        if (componentInputVo.getFileBytes() != null) {
            fileBytes = componentInputVo.getFileBytes();
        } else {
            fileBytes = getFeignFile(componentInputVo.getFileIdentifier());
        }
        if (fileBytes.getFileInputStream() == null) {
            throw new ServiceException("制品文件读取失败");
        }
        builder.addBinaryBody("pypi.asset1", fileBytes.getFileInputStream(), ContentType.DEFAULT_BINARY, fileBytes.getFileName());
        JSONObject bodyLog = toBodyLog(componentInputVo);
        JSONObject res;
        try {
            res = nexusRequestHelper.doRequest(NexusRequestUrl.UPLOAD_COMPONENTS(componentInputVo.getNexusRepoName()), builder.build(), bodyLog);
        } catch (Exception e) {
            logger.error("上传pypi制品失败：{}", e.getMessage());
            throw new ServiceException("上传的pypi制品文件格式错误，请调整后重新上传");
        }
        return checkPypiUploadRes(res);
    }

    private JSONObject toBodyLog(ComponentInputVo componentInputVo) {
        JSONObject bodyLog = JSONObject.from(componentInputVo);
        if (componentInputVo.getFileBytes() != null) {
            bodyLog.put("fileName", componentInputVo.getFileBytes().getFileName());
            bodyLog.remove("fileBytes");
        }
        return bodyLog;
    }

    private JSONObject toBodyLog(ComponentMavenInputVo componentMavenInputVo) {
        JSONObject bodyLog = JSONObject.from(componentMavenInputVo);
        List<JSONObject> assetJsonList = new ArrayList<>();
        for (AssetMavenInputVo assetMavenInputVo : componentMavenInputVo.getAssetList()) {
            JSONObject assetJson = JSONObject.from(assetMavenInputVo);
            if (assetMavenInputVo.getFileBytes() != null) {
                assetJson.put("fileName", assetMavenInputVo.getFileBytes().getFileName());
                assetJson.remove("fileBytes");
            }
            assetJsonList.add(assetJson);
        }
        bodyLog.put("assetList", assetJsonList);
        return bodyLog;
    }

    private JSONObject toBodyLog(ComponentRawInputVo componentRawInputVo) {
        JSONObject bodyLog = JSONObject.from(componentRawInputVo);
        List<JSONObject> assetJsonList = new ArrayList<>();
        for (AssetRawInputVo assetRawInputVo : componentRawInputVo.getAssetList()) {
            JSONObject assetJson = JSONObject.from(assetRawInputVo);
            if (assetRawInputVo.getFileBytes() != null) {
                if (!assetJson.containsKey("filename")) {
                    assetJson.put("fileName", assetRawInputVo.getFileBytes().getFileName());
                }
                assetJson.remove("fileBytes");
            }
            assetJsonList.add(assetJson);
        }
        bodyLog.put("assetList", assetJsonList);
        return bodyLog;
    }

    private void addTextBody(MultipartEntityBuilder builder, String key, String value) {
        if (value != null) {
            builder.addTextBody(key, value);
        }
    }

    private boolean checkPypiUploadRes(JSONObject res) {
        if (res == null) {
            return false;
        }
        JSONArray data = res.getJSONArray("data");
        if (data != null && !data.isEmpty()) {
            JSONObject messageObj = data.getJSONObject(0);
            throw new ServiceException("Pypi制品文件上传错误：%s", messageObj.getString("message"));
        }
        return true;
    }

    @Override
    public void lockComponentList(Long productRepoId, List<String> componentIdList) {
        for (String componentId : componentIdList) {
            String lockComponentKey = CacheConstants.getLockProductLibraryIdComponentIdKey(productRepoId, componentId);
            if (redisService.hasKey(lockComponentKey)) {
                int count = redisService.getCacheObject(lockComponentKey);
                redisService.setCacheObject(lockComponentKey, ++count);
            } else {
                redisService.setCacheObject(lockComponentKey, 1);
            }
        }
    }

    @Override
    public void unlockComponentList(Long productRepoId, List<String> componentIdList) {
        for (String componentId : componentIdList) {
            String lockComponentKey = CacheConstants.getLockProductLibraryIdComponentIdKey(productRepoId, componentId);
            if (redisService.hasKey(lockComponentKey)) {
                int count = redisService.getCacheObject(lockComponentKey);
                count--;
                if (count <= 0) {
                    redisService.deleteObject(lockComponentKey);
                } else {
                    redisService.setCacheObject(lockComponentKey, count);
                }
            }
        }
    }

    @Override
    public boolean getLockComponentStatus(Long productRepoId, String componentId) {
        String lockComponentKey = CacheConstants.getLockProductLibraryIdComponentIdKey(productRepoId, componentId);
        if (redisService.hasKey(lockComponentKey)) {
            int count = redisService.getCacheObject(lockComponentKey);
            return count > 0;
        }
        return false;
    }

    private SysFileBytes getFeignFile(String fileIdentifier) {
        try {
            Response response = fileService.getFileEntityByIdentifier(fileIdentifier, SecurityConstants.INNER);
            if (response == null) {
                throw new ServiceException("文件服务请求失败");
            }
            InputStream inputStream = response.body().asInputStream();
            Collection<String> fileNameCollection = response.headers().get("FileName");
            String fileName = null;
            if (fileNameCollection != null) {
                fileName = fileNameCollection.stream().findFirst().orElse(null);
            }
            SysFileBytes sysFileBytes = new SysFileBytes();
            sysFileBytes.setFileInputStream(inputStream);
            sysFileBytes.setFileName(fileName);
            return sysFileBytes;
        } catch (IOException e) {
            throw new ServiceException("获取文件失败：" + e.getMessage());
        }
    }
}
