package com.microservices.zone.common.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.StringUtils;
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
import com.microservices.common.redis.service.RedisService;
import com.microservices.system.api.RemoteCmsService;
import com.microservices.system.api.utils.FeignUtils;
import com.microservices.zone.common.service.IZoneAsyncService;
import com.microservices.zone.detail.domain.ZoneDetail;
import com.microservices.zone.detail.domain.vo.ZoneDetailUpdateVo;
import com.microservices.zone.detail.mapper.ZoneDetailMapper;
import com.microservices.zone.member.domain.ZoneMemberLevel;
import com.microservices.zone.member.domain.ZoneMemberType;
import com.microservices.zone.member.domain.vo.ZoneMemberInitVo;
import com.microservices.zone.member.domain.vo.ZoneMemberLevelInputVo;
import com.microservices.zone.member.domain.vo.ZoneMemberTypeInputVo;
import com.microservices.zone.member.mapper.ZoneMemberLevelMapper;
import com.microservices.zone.member.mapper.ZoneMemberTypeMapper;
import com.microservices.zone.member.service.IZoneMemberLevelService;
import com.microservices.zone.member.service.IZoneMemberService;
import com.microservices.zone.member.service.IZoneMemberTypeService;
import com.microservices.zone.partners.domain.vo.ZonePartnersTypeInputVo;
import com.microservices.zone.partners.service.IZonePartnersTypeService;
import com.microservices.zone.project.domain.ZoneProject;
import com.microservices.zone.project.domain.ZoneProjectType;
import com.microservices.zone.project.domain.vo.ProjectGitlinkInfoVo;
import com.microservices.zone.project.domain.vo.ZoneProjectInputVo;
import com.microservices.zone.project.domain.vo.ZoneProjectSearchVo;
import com.microservices.zone.project.domain.vo.ZoneProjectTypeInputVo;
import com.microservices.zone.project.mapper.ForgeProjectStatisticsMapper;
import com.microservices.zone.project.mapper.ZoneProjectMapper;
import com.microservices.zone.project.mapper.ZoneProjectTypeMapper;
import com.microservices.zone.project.service.IZoneProjectService;
import com.microservices.zone.project.service.IZoneProjectTypeService;
import com.microservices.zone.resource.domain.ZoneResource;
import com.microservices.zone.resource.domain.ZoneResourceToType;
import com.microservices.zone.resource.domain.ZoneResourceType;
import com.microservices.zone.resource.domain.vo.ZoneResourceDomainInputVo;
import com.microservices.zone.resource.domain.vo.ZoneResourceTypeInputVo;
import com.microservices.zone.resource.mapper.ZoneResourceMapper;
import com.microservices.zone.resource.mapper.ZoneResourceToTypeMapper;
import com.microservices.zone.resource.service.IZoneResourceDomainService;
import com.microservices.zone.resource.service.IZoneResourceService;
import com.microservices.zone.resource.service.IZoneResourceTypeService;
import com.microservices.zone.utils.ZoneConstants;
import com.microservices.zone.utils.ZoneGitLinkRequestUrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author otto
 */
@Service
public class ZoneAsyncServiceImpl implements IZoneAsyncService {
    private static final Logger logger = LoggerFactory.getLogger(ZoneAsyncServiceImpl.class);

    @Autowired
    private ZoneDetailMapper zoneDetailMapper;
    @Autowired
    private RemoteCmsService remoteCmsService;
    @Autowired
    @Lazy
    private IZoneProjectTypeService zoneProjectTypeService;
    @Autowired
    @Lazy
    private IZoneProjectService zoneProjectService;
    @Autowired
    @Lazy
    private IZoneMemberTypeService zoneMemberTypeService;
    @Autowired
    @Lazy
    private IZoneMemberLevelService zoneMemberLevelService;
    @Autowired
    @Lazy
    private IZoneMemberService zoneMemberService;
    @Autowired
    @Lazy
    private IZonePartnersTypeService zonePartnersTypeService;
    @Autowired
    private ZoneProjectTypeMapper zoneProjectTypeMapper;
    @Autowired
    private ZoneProjectMapper zoneProjectMapper;
    @Autowired
    private ZoneMemberTypeMapper zoneMemberTypeMapper;
    @Autowired
    private ZoneMemberLevelMapper zoneMemberLevelMapper;
    @Autowired
    private ZoneResourceToTypeMapper zoneResourceToTypeMapper;
    @Autowired
    private ZoneResourceMapper zoneResourceMapper;
    @Autowired
    private RedisService redisService;
    @Autowired
    @Lazy
    private IZoneResourceService zoneResourceService;
    @Autowired
    @Lazy
    private IZoneResourceTypeService zoneResourceTypeService;
    @Autowired
    @Lazy
    private IZoneResourceDomainService zoneResourceDomainService;
    @Autowired
    private ForgeProjectStatisticsMapper forgeProjectStatisticsMapper;
    @Autowired
    private GitLinkRequestHelper gitLinkRequestHelper;

    @Value("${zone.initData.gitlinkProjectId}")
    private Long gitlinkProjectId;

    @Value("${zone.initData.gitLinkUserName1}")
    private String gitLinkUserName1;

    @Value("${zone.initData.gitLinkUserName2}")
    private String gitLinkUserName2;

    @Value("${zone.initData.gitLinkUserName3}")
    private String gitLinkUserName3;

    @Value("${zone.initData.gitLinkUserName4}")
    private String gitLinkUserName4;

    @Value("${zone.needCalcScoreZoneId}")
    private Long needCalcScoreZoneId;
    /**
     * 创建线程池
     * 初始化专区耗时长在初始化文章，经实验在文章初始化完成前其他步骤均已执行完成，故设核心线程数为2
     * 存在并发创建专区的情况，设置有界队列长度为10，最大线程数为6
     * 当超出队列已满且达到最大线程数时抛出异常
     * Ncpu=CPU数量
     * Ucpu=目标CPU的使用率，0<=Ucpu<=1
     * W/C=任务等待时间与任务计算时间的比率
     * Nthreads =Ncpu*Ucpu*(1+W/C)
     */
    static ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
            2
            , 10
            , 10
            , TimeUnit.SECONDS
            , new ArrayBlockingQueue<>(100)
            , Executors.defaultThreadFactory()
            , (r, executor) -> {
        throw new ServiceException("【%s】目前创建的人太多了，请稍后再试", DateUtils.getNowDate());
    }
    );

    @Override
    public void asyncInitZoneData(ZoneDetail zoneDetail) {
        System.out.printf("%s:线程【%s】开始处理专区【%s】的首页配置", DateUtils.getNowDate(), Thread.currentThread().getName(), zoneDetail.getName());
        threadPoolExecutor.execute(() -> initHomePage(zoneDetail));
        System.out.printf("%s:线程【%s】开始处理专区【%s】的文章初始化", DateUtils.getNowDate(), Thread.currentThread().getName(), zoneDetail.getName());
        threadPoolExecutor.execute(() -> initCms(zoneDetail));
        System.out.printf("%s:线程【%s】开始处理专区【%s】的项目聚合初始化", DateUtils.getNowDate(), Thread.currentThread().getName(), zoneDetail.getName());
        threadPoolExecutor.execute(() -> initProject(zoneDetail));
        System.out.printf("%s:线程【%s】开始处理专区【%s】的会员聚合初始化", DateUtils.getNowDate(), Thread.currentThread().getName(), zoneDetail.getName());
        threadPoolExecutor.execute(() -> initMember(zoneDetail));
        System.out.printf("%s:线程【%s】开始处理专区【%s】的合作伙伴初始化", DateUtils.getNowDate(), Thread.currentThread().getName(), zoneDetail.getName());
        threadPoolExecutor.execute(() -> initPartners(zoneDetail));
        System.out.printf("%s:线程【%s】开始处理专区【%s】的资源聚合初始化", DateUtils.getNowDate(), Thread.currentThread().getName(), zoneDetail.getName());
        threadPoolExecutor.execute(() -> initResource(zoneDetail));
    }

    @Override
    public void initResource(ZoneDetail zoneDetail) {
        initZoneResourceDomain(zoneDetail.getId(), "资源领域一");
        initZoneResourceDomain(zoneDetail.getId(), "资源领域二");
        initZoneResourceDomain(zoneDetail.getId(), "资源领域三");
        initZoneResourceDomain(zoneDetail.getId(), "资源领域四");

        initZoneResourceType(zoneDetail.getId(), "图片文件", "png,jpg,jpeg,webp,gif,bmp,tiff,tif,svg");
        initZoneResourceType(zoneDetail.getId(), "文档文件", "txt,docx,doc,pdf,rtf,xlsx,xls,csv,pptx,ppt,md,odt");
        initZoneResourceType(zoneDetail.getId(), "视频文件", "mp4,avi,mkv,mov,wmv,flv,m4v");
        initZoneResourceType(zoneDetail.getId(), "音频文件", "mp3,wav,flac,aac,ogg,wma");
        initZoneResourceType(zoneDetail.getId(), "压缩文件", "zip,rar,7z,tar,gz,bz2,iso");
        initZoneResourceType(zoneDetail.getId(), "应用程序文件", "exe,lnk,sh,bat,cmd,msi,apk,app");
        initZoneResourceType(zoneDetail.getId(), "网页文件", "html,htm,css,js,xml,json,php,asp,jsp");
        initZoneResourceType(zoneDetail.getId(), "数据库文件", "sql,sqlite,db,mdb,accdb,pgd,pgdump,mongodb,rdb,db2");
        initZoneResourceType(zoneDetail.getId(), "其他文件", "");
    }

    private void initZoneResourceDomain(Long zoneId, String name) {
        ZoneResourceDomainInputVo zoneResourceDomainInputVo = new ZoneResourceDomainInputVo();
        zoneResourceDomainInputVo.setZoneId(zoneId);
        zoneResourceDomainInputVo.setName(name);
        zoneResourceDomainService.insertZoneResourceDomain(zoneResourceDomainInputVo);
    }

    private void initZoneResourceType(Long zoneId, String name, String fileTypeList) {
        ZoneResourceTypeInputVo zoneResourceTypeInputVo = new ZoneResourceTypeInputVo();
        zoneResourceTypeInputVo.setZoneId(zoneId);
        zoneResourceTypeInputVo.setName(name);
        zoneResourceTypeInputVo.setFileTypeList(fileTypeList);
        zoneResourceTypeService.insertZoneResourceType(zoneResourceTypeInputVo);
    }

    @Override
    @Async
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void asyncUpdateZoneResourceToTargetType(ZoneResourceType currentResourceType, ZoneResourceType targetResourceType) {
        List<ZoneResourceToType> zoneResourceToTypeList =
                zoneResourceToTypeMapper.selectResourceToTypeListByTypeId(currentResourceType.getId());
        for (ZoneResourceToType zoneResourceToType : zoneResourceToTypeList) {
            // 删除资源与当前资源类别的关联
            zoneResourceToTypeMapper
                    .deleteResourceToTypeByResourceIdAndTypeId(zoneResourceToType.getResourceId(), currentResourceType.getId());
            // 新增资源与目标资源类别的关联
            zoneResourceToTypeMapper
                    .insertResourceToType(zoneResourceToType.getResourceId(), targetResourceType.getId());
        }
    }

    @Override
    @Async
    public void asyncUpdateType() {
        redisService.deleteObject(redisService.keys("*" + ZoneConstants.REDIS_KEY_FILE_SUFFIX_OF_RESOURCE_TYPE_PREFIX + "*"));
        List<ZoneResource> zoneResourceList = zoneResourceMapper.selectAllZoneResourceList();
        for (ZoneResource zoneResource : zoneResourceList) {
            // 获取所有附件后缀
            List<String> fileSuffixList = zoneResourceService.getAllFileSuffix(zoneResource.getFileIds());
            // 基于后缀获取资源类型
            List<ZoneResourceType> zoneResourceTypeList =
                    zoneResourceTypeService.selectZoneResourceTypeListBySuffixList(
                            zoneResource.getZoneId(), fileSuffixList);
            // 获取资源原关联类型
            List<ZoneResourceToType> oldZoneResourceToTypeList =
                    zoneResourceToTypeMapper.selectResourceToTypeListByResourceId(zoneResource.getId());
            Long[] typeIds = oldZoneResourceToTypeList
                    .stream()
                    .map(ZoneResourceToType::getTypeId)
                    .collect(Collectors.toList())
                    .toArray(new Long[oldZoneResourceToTypeList.size()]);
            if (typeIds.length > 0) {
                // 清理原类型关联关系
                zoneResourceToTypeMapper.deleteResourceToTypesByResourceIdAndTypeIds(zoneResource.getId(), typeIds);
            }

            List<ZoneResourceToType> newZoneResourceToTypeList =
                    zoneResourceTypeList
                            .stream().map(x -> new ZoneResourceToType(zoneResource.getId(), x.getId()))
                            .collect(Collectors.toList());
            if (!newZoneResourceToTypeList.isEmpty()) {
                // 建立资源和资源类别关联
                zoneResourceToTypeMapper.batchResourceToType(newZoneResourceToTypeList);
            }

        }
    }

    @Override
    public void initPartners(ZoneDetail zoneDetail) {
        //初始化合作伙伴默认分类
        ZonePartnersTypeInputVo zonePartnersTypeInputVo = new ZonePartnersTypeInputVo();
        zonePartnersTypeInputVo.setName(ZoneConstants.DEFAULT_TYPE_NAME);
        zonePartnersTypeInputVo.setZoneId(zoneDetail.getId());
        zonePartnersTypeService.insertZonePartnersType(zonePartnersTypeInputVo);
    }

    @Override
    public void initHomePage(ZoneDetail zoneDetail) {
        //region 初始化首页配置
        ZoneDetailUpdateVo zoneDetailUpdateVo = new ZoneDetailUpdateVo();
        zoneDetailUpdateVo.setId(zoneDetail.getId());
        zoneDetailUpdateVo.setBannerList("https://www.gitlink.org.cn/api/attachments/422899");
        if (StringUtils.isEmpty(zoneDetail.getMainTitle())) {
            zoneDetailUpdateVo.setMainTitle("主标题文案内容占一行");
        }
        zoneDetailUpdateVo.setSubTitle("专区副标题文案内容专区副标题文案内容专区副标题文案内容专区副标题文案内容专区副标题文案内容专区副标题文案内容专区副标题文案内容");
        if (StringUtils.isEmpty(zoneDetail.getFirstTitle())) {
            zoneDetailUpdateVo.setFirstTitle("专区一级标题");
        }
        zoneDetailUpdateVo.setIntroductionTitle("专区二级标题");
        if (StringUtils.isEmpty(zoneDetail.getIntroductionContent())) {
            zoneDetailUpdateVo.setIntroductionContent("我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容我是专区的简介完整内容");
        }
        zoneDetailUpdateVo.setIntroductionImage("https://www.gitlink.org.cn/api/attachments/421023");
        zoneDetail = zoneDetailUpdateVo.toZoneDetail();
        zoneDetail.setUpdateTime(DateUtils.getNowDate());
        zoneDetailMapper.updateZoneDetail(zoneDetail);
        //endregion
    }

    @Override
    public void initCms(ZoneDetail zoneDetail) {
        initCms(zoneDetail.getId(), "栏目一", "第一条新闻", 1, true);
        initCms(zoneDetail.getId(), "栏目二", "第二条新闻", 2, false);
        initCms(zoneDetail.getId(), "栏目三", "第三条新闻", 3, false);
        initCms(zoneDetail.getId(), "栏目四", "第四条新闻", 4, false);
    }

    private void initCms(Long zoneId, String dirName, String docName, int sort, boolean needHeadImg) {
        //初始化栏目
        JSONObject cmsDirInput = new JSONObject();
        //初始化第一条新闻
        cmsDirInput.put("name", dirName);
        cmsDirInput.put("sort", sort);
        Object cmsDirObj = FeignUtils.getReturnData(
                remoteCmsService.initCmsDir(zoneId, cmsDirInput, SecurityConstants.INNER)
        );
        JSONObject cmsDir = JSONObject.from(cmsDirObj);
        JSONObject cmsDocInput = new JSONObject();
        cmsDocInput.put("name", docName);
        cmsDocInput.put("content",
                encodeContent("第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容行第一条新闻的新闻详情正文内容..."
                        .replaceAll("第一条新闻", docName)));
        if (needHeadImg) {
            cmsDocInput.put("headImg", "https://www.gitlink.org.cn/api/attachments/421073");
        }
        cmsDocInput.put("summary",
                "第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容第一条新闻的新闻详情正文内容行第一条新闻的新闻详情正文内容..."
                        .replaceAll("第一条新闻", docName));
        remoteCmsService.initCmsDoc(
                cmsDir.getLong("id")
                , cmsDocInput
                , SecurityConstants.INNER);
    }

    @Override
    public void initProject(ZoneDetail zoneDetail) {
        //region 初始化项目
        //初始化项目类型
        ZoneProjectType zoneProjectType = initZoneProjectType(zoneDetail.getId(), "项目分类一");
        initZoneProjectType(zoneDetail.getId(), "项目分类二");
        initZoneProjectType(zoneDetail.getId(), "项目分类三");
        initZoneProjectType(zoneDetail.getId(), "项目分类四");

        //初始化项目聚合
        List<ZoneProjectInputVo> zoneProjectInputVoList = new ArrayList<>();
        ZoneProjectInputVo zoneProjectInputVo = new ZoneProjectInputVo();
        zoneProjectInputVo.setProjectTypeId(zoneProjectType.getId());
        zoneProjectInputVo.setZoneId(zoneDetail.getId());
        zoneProjectInputVo.setGitlinkProjectId(gitlinkProjectId);
        zoneProjectInputVoList.add(zoneProjectInputVo);
        zoneProjectService.insertBatchZoneProject(zoneProjectInputVoList);
        //自动将初始化的项目设置为首页展示
        ZoneProject zoneProject = zoneProjectMapper
                .selectZoneProjectByGitLinkProjectIdAndZoneId(zoneProjectInputVo.getGitlinkProjectId(), zoneDetail.getId());
        zoneProjectService.updateZoneProjectHomePageShow(zoneProject.getId());
        //endregion
    }

    private ZoneProjectType initZoneProjectType(Long zoneId, String name) {
        ZoneProjectTypeInputVo zoneProjectTypeInputVo = new ZoneProjectTypeInputVo();
        zoneProjectTypeInputVo.setZoneId(zoneId);
        zoneProjectTypeInputVo.setName(name);
        zoneProjectTypeService.insertZoneProjectType(zoneProjectTypeInputVo);
        return zoneProjectTypeMapper
                .selectZoneProjectTypeByNameAndZoneId(zoneProjectTypeInputVo.getName(), zoneId);
    }

    @Override
    public void initMember(ZoneDetail zoneDetail) {
        //region 初始化会员
        //初始化会员类别
        initZoneMember(
                zoneDetail.getId()
                , "PMC（项目管理委员会）"
                , "PMC（Project Management Committee）是本专区的核心组织，负责监督和管理社区项目的开发进程。PMC成员负责制定项目的战略、管理项目过程及资源、协调开发者之间的合作，确保项目按照计划运行。PMC也是指导社区繁荣发展、吸引更多的贡献者、维护良好社区氛围的关键人员"
                , "最强王者"
                , 1
                , gitLinkUserName1
        );
        initZoneMember(
                zoneDetail.getId()
                , "Commiter（代码合作者）"
                , "Committer是一个为社区特定项目做出贡献的人员团队。通常是开源社区的有资深经验的成员，他们通常拥有专区开源项目的授权和贡献者身份，并参与到代码编写阶段，为用户和PMC成员提供技术指导和支持"
                , "钻石"
                , 2
                , gitLinkUserName2
        );
        initZoneMember(
                zoneDetail.getId()
                , "Developer（项目开发者）"
                , "Developer（项目开发者）是为专区开源项目编写代码，提交代码，以及维护文档等工作的成员。他们在项目开始的不同阶段参与编写代码并提出优化、建议、解决问题和错误等，以便确保项目的顺利进行"
                , "铂金"
                , 3
                , gitLinkUserName3
        );
        initZoneMember(
                zoneDetail.getId()
                , "User（项目使用者）"
                , "User是使用专区开源项目的会员用户，他们通过专区官方的网站，获得与专区相关的资源、文档、项目、新闻、及参与社区交流等。同时专区会员用户也可以贡献自己的意见、反馈bug、甚至提供代码，是项目不断发展的重要基石"
                , "黄金"
                , 4
                , gitLinkUserName4
        );
        initZoneMemberLevel(zoneDetail.getId(), "白银", 5);
        initZoneMemberLevel(zoneDetail.getId(), "青铜", 6);

        //endregion
    }

    private void initZoneMember(
            Long zoneId
            , String typeName
            , String typeIntroduction
            , String levelName
            , Integer sort
            , String gitLinkUserName) {
        ZoneMemberTypeInputVo zoneMemberTypeInputVo = new ZoneMemberTypeInputVo();
        zoneMemberTypeInputVo.setName(typeName);
        zoneMemberTypeInputVo.setIntroduction(typeIntroduction);
        zoneMemberTypeInputVo.setZoneId(zoneId);
        zoneMemberTypeService.insertZoneMemberType(zoneMemberTypeInputVo.toZoneMemberType());
        ZoneMemberType zoneMemberType = zoneMemberTypeMapper
                .selectZoneMemberTypeByNameAndZoneId(zoneMemberTypeInputVo.getName(), zoneId);
        ZoneMemberLevel zoneMemberLevel = initZoneMemberLevel(zoneId, levelName, sort);
        ZoneMemberInitVo zoneMemberInitVo = new ZoneMemberInitVo();
        zoneMemberInitVo.setGitLinkUserName(gitLinkUserName);
        zoneMemberInitVo.setIntroduction(gitLinkUserName + " 在华为加拿大研究所工作，负责设计、架构和关键特性的开发，并拥有20年的IBM和Platform Computing工作经验。");
        zoneMemberInitVo.setMemberTypeId(zoneMemberType.getId());
        zoneMemberInitVo.setMemberLevelId(zoneMemberLevel.getId());
        zoneMemberInitVo.setZoneId(zoneId);
        zoneMemberService.initZoneMember(zoneMemberInitVo);
    }

    private ZoneMemberLevel initZoneMemberLevel(Long zoneId, String levelName, Integer sort) {
        ZoneMemberLevelInputVo zoneMemberLevelInputVo = new ZoneMemberLevelInputVo();
        zoneMemberLevelInputVo.setName(levelName);
        zoneMemberLevelInputVo.setSort(sort);
        zoneMemberLevelInputVo.setZoneId(zoneId);
        zoneMemberLevelService.insertZoneMemberLevel(zoneMemberLevelInputVo.toZoneMemberLevel());
        return zoneMemberLevelMapper
                .selectZoneMemberLevelByNameAndZoneId(zoneMemberLevelInputVo.getName(), zoneId);
    }

    private String encodeContent(String content) {
        String base64encodeString;
        try {
            // 解码
            byte[] testByte = content.getBytes(StandardCharsets.UTF_8);
            base64encodeString = Base64.getEncoder().encodeToString(testByte);
        } catch (Exception e) {
            base64encodeString = "";
        }
        return base64encodeString;
    }

    @Override
    public void initProjectGitlinkInfo() {
        ZoneProjectSearchVo zoneProjectSearchVo = new ZoneProjectSearchVo();
        zoneProjectSearchVo.setZoneId(needCalcScoreZoneId);
        List<ZoneProject> zoneProjectList = zoneProjectMapper.selectZoneProjectList(zoneProjectSearchVo);
        for (ZoneProject zoneProject : zoneProjectList) {
            setProjectGitlinkInfoCache(zoneProject);
        }
    }


    @Override
    public void setProjectGitlinkInfoCache(ZoneProject zoneProject) {
        threadPoolExecutor.execute(() -> {
            if (zoneProject == null || !Objects.equals(zoneProject.getZoneId(), needCalcScoreZoneId)) {
                return;
            }
            ProjectGitlinkInfoVo projectGitlinkInfo = new ProjectGitlinkInfoVo();
            try {
                // 获取项目贡献者数量
                JSONArray contributorsArray = gitLinkRequestHelper.getAllDataByPage(
                        ZoneGitLinkRequestUrl.CONTRIBUTORS(zoneProject.getFullName()), "list"
                );
                projectGitlinkInfo.setContributorsCount((long) contributorsArray.size());
                projectGitlinkInfo.setContributorsList(contributorsArray);
            } catch (ServiceException e) {
                logger.error("【{}】获取项目贡献者数量失败：{}", zoneProject.getFullName(), e.getMessage());
            }
            // 获取历史总提交数
            Long commitCount = forgeProjectStatisticsMapper.selectAllCommitCountByProjectId(zoneProject.getGitlinkProjectId());
            projectGitlinkInfo.setCommitCount(commitCount);
            // 获取上周活跃度
            Date now = DateUtils.getNowDate();
            String lastMonday = DateUtils.mondayOfLastWeek(now, 1);
            String lastSunday = DateUtils.sundayOfLastWeek(now, 1);
            projectGitlinkInfo.setLastWeekScore(calcProjectScore(zoneProject, lastMonday, lastSunday));

            // 获取上上周活跃度
            String secondLastMonday = DateUtils.mondayOfLastWeek(now, 2);
            String secondLastSunday = DateUtils.sundayOfLastWeek(now, 2);
            calcProjectScore(zoneProject, secondLastMonday, secondLastSunday);
            redisService.setCacheObject(CacheConstants.getZoneProjectGitlinkInfo(zoneProject.getGitlinkProjectId()), projectGitlinkInfo);
            logger.info("成功从Gitlink同步【{}】项目信息：{}", zoneProject.getFullName(), projectGitlinkInfo);
        });
    }

    @Override
    public void clearZoneProjectSortByScoreCache(ZoneProject zoneProject) {
        redisService.keys(CacheConstants.getAllZoneProjectSortByScore(zoneProject.getZoneId())).forEach(key -> {
            redisService.removeSortSetObject(key, zoneProject.getGitlinkProjectId());
        });
    }

    private Double calcProjectScore(ZoneProject zoneProject, String startDate, String endDate) {
        Double theWeekScore = forgeProjectStatisticsMapper
                .selectLastWeekScoreByProjectId(zoneProject.getGitlinkProjectId(), startDate, endDate);
        if (theWeekScore == null) {
            theWeekScore = 0D;
        }
        // 一个月过期
        redisService.setSortSetObject(
                CacheConstants.getZoneProjectSortByScore(startDate, zoneProject.getZoneId(), zoneProject.getProjectTypeId()),
                zoneProject.getGitlinkProjectId(),
                theWeekScore,
                30L, TimeUnit.DAYS);
        return theWeekScore;
    }

}
