package com.microservices.zone.detail.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.constant.CacheConstants;
import com.microservices.common.core.constant.HttpStatus;
import com.microservices.common.core.constant.SecurityConstants;
import com.microservices.common.core.enums.SystemRole;
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.PinYinStringUtils;
import com.microservices.common.core.utils.StringUtils;
import com.microservices.common.core.utils.html.EscapeUtil;
import com.microservices.common.core.web.page.GenericsTableDataInfo;
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
import com.microservices.common.redis.service.RedisService;
import com.microservices.common.security.auth.AuthUtil;
import com.microservices.common.security.utils.DictUtils;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.system.api.RemoteCmsService;
import com.microservices.system.api.RemoteDeptService;
import com.microservices.system.api.RemoteUserService;
import com.microservices.system.api.domain.SysDept;
import com.microservices.system.api.domain.SysDictData;
import com.microservices.system.api.domain.SysUserDeptRole;
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.*;
import com.microservices.zone.detail.mapper.ZoneDetailMapper;
import com.microservices.zone.detail.service.IZoneDetailService;
import com.microservices.zone.member.domain.ZoneMember;
import com.microservices.zone.member.domain.vo.ZoneMemberSearchVo;
import com.microservices.zone.member.mapper.ZoneMemberLevelMapper;
import com.microservices.zone.member.mapper.ZoneMemberMapper;
import com.microservices.zone.member.mapper.ZoneMemberTypeMapper;
import com.microservices.zone.partners.mapper.ZonePartnersMapper;
import com.microservices.zone.partners.mapper.ZonePartnersTypeMapper;
import com.microservices.zone.project.domain.ZoneProject;
import com.microservices.zone.project.domain.vo.ProjectGitlinkInfoVo;
import com.microservices.zone.project.domain.vo.ZoneProjectSearchVo;
import com.microservices.zone.project.domain.vo.ZoneStatisticsVo;
import com.microservices.zone.project.mapper.ZoneProjectMapper;
import com.microservices.zone.project.mapper.ZoneProjectTypeMapper;
import com.microservices.zone.resource.domain.ZoneResource;
import com.microservices.zone.resource.mapper.ZoneResourceDomainMapper;
import com.microservices.zone.resource.mapper.ZoneResourceMapper;
import com.microservices.zone.resource.mapper.ZoneResourceTypeMapper;
import com.microservices.zone.specialProject.domain.ZoneSpecialProject;
import com.microservices.zone.specialProject.service.IZoneSpecialProjectService;
import com.microservices.zone.utils.ZoneConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 特色专区详情Service业务层处理
 *
 * @author otto
 * @date 2023-05-09
 */
@Service
public class ZoneDetailServiceImpl implements IZoneDetailService {
    @Autowired
    private ZoneDetailMapper zoneDetailMapper;
    @Autowired
    private GitLinkRequestHelper gitLinkRequestHelper;
    @Autowired
    private RemoteDeptService remoteDeptService;
    @Autowired
    private RemoteCmsService remoteCmsService;
    @Autowired
    private RemoteUserService remoteUserService;
    @Autowired
    private IZoneAsyncService zoneAsyncService;
    @Autowired
    private ZoneProjectMapper zoneProjectMapper;
    @Autowired
    private ZoneProjectTypeMapper zoneProjectTypeMapper;
    @Autowired
    private ZoneMemberMapper zoneMemberMapper;
    @Autowired
    private ZoneMemberTypeMapper zoneMemberTypeMapper;
    @Autowired
    private ZoneMemberLevelMapper zoneMemberLevelMapper;
    @Autowired
    private ZoneResourceTypeMapper zoneResourceTypeMapper;
    @Autowired
    private ZoneResourceMapper zoneResourceMapper;
    @Autowired
    private ZoneResourceDomainMapper zoneResourceDomainMapper;
    @Autowired
    private ZonePartnersMapper zonePartnersMapper;
    @Autowired
    private ZonePartnersTypeMapper zonePartnersTypeMapper;
    @Autowired
    @Lazy
    private IZoneSpecialProjectService zoneSpecialProjectService;
    @Value("${zone.zoneAdminUrl}")
    private String zoneAdminUrl;
    @Value("${zone.zoneConfigurationUrl}")
    private String zoneConfigurationUrl;
    @Value("${zone.adminUrl}")
    private String adminUrl;
    @Value("${zone.resourceManageUrl}")
    private String resourceManageUrl;
    @Value("${zone.docManageUrl}")
    private String docManageUrl;
    @Autowired
    private RedisService redisService;

    /**
     * 查询特色专区详情
     *
     * @param id 特色专区详情主键
     * @return 特色专区详情
     */
    @Override
    public ZoneDetail selectZoneDetailById(Long id) {
        checkZoneDataScope(id);
        return selectZoneDetailByIdNotVerifiedDataScope(id);
    }

    /**
     * 查询特色专区详情(不校验数据权限)
     *
     * @param id 特色专区详情主键
     * @return 特色专区详情
     */
    @Override
    public ZoneDetail selectZoneDetailByIdNotVerifiedDataScope(Long id) {
        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailById(id);
        if (zoneDetail == null) {
            throw new ServiceException("该特色专区不存在或无权限访问(专区id[" + id + "])");
        }
        return zoneDetail;
    }

    @Override
    public ZoneDetailDataVo selectZoneDetailDataById(Long id) {
        ZoneDetail zoneDetail = selectZoneDetailById(id);
        return selectZoneDetailDataByZoneDetail(zoneDetail);
    }

    private ZoneDetailDataVo getZoneDetailDataVoAndCmsProject(ZoneDetail zoneDetail) {
        ZoneDetailDataVo zoneDetailDataVo = zoneDetail.toZoneDetailDataVo();
        String cmsProjectJson = FeignUtils.getReturnData(
                remoteCmsService.getProjectByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER)
        );
        if (StringUtils.isNotEmpty(cmsProjectJson)) {
            JSONObject jsonObject = JSONObject.parseObject(cmsProjectJson);
            if (jsonObject == null) {
                return zoneDetailDataVo;
            }
            JSONObject gitlinkProject = new JSONObject();
            gitlinkProject.put("projectId", jsonObject.getLong("id"));
            String owner = jsonObject.getString("username");
            gitlinkProject.put("owner", owner);
            String identifier = jsonObject.getString("identifier");
            gitlinkProject.put("identifier", identifier);
            String wikiUrl = EscapeUtil.removeExtraSlashOfUrl(
                    String.format("%s/%s/%s/wiki", gitLinkRequestHelper.gitLinkUrl, owner, identifier)
            );
            gitlinkProject.put("wiki_url", wikiUrl);
            zoneDetailDataVo.setGitlinkProject(gitlinkProject);
        }

        return zoneDetailDataVo;
    }

    private ZoneDetailDataVo selectZoneDetailDataByZoneDetail(ZoneDetail zoneDetail) {
        ZoneDetailDataVo zoneDetailDataVo = getZoneDetailDataVoAndCmsProject(zoneDetail);
        ZoneMemberSearchVo zoneMemberSearchVo = new ZoneMemberSearchVo();
        zoneMemberSearchVo.setZoneId(zoneDetail.getId());
        zoneMemberSearchVo.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
        Integer memberCount = zoneMemberMapper.selectZoneMemberListCount(zoneMemberSearchVo);
        zoneDetailDataVo.setMemberCount(Long.valueOf(memberCount));
        ZoneProjectSearchVo zoneProjectSearchVo = new ZoneProjectSearchVo();
        zoneProjectSearchVo.setZoneId(zoneDetail.getId());
        Integer projectCount = zoneProjectMapper.selectZoneProjectListCount(zoneProjectSearchVo);
        zoneDetailDataVo.setProjectCount(Long.valueOf(projectCount));
        Long cmsCount = FeignUtils.getReturnData(
                remoteCmsService.getCmsCountByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER)
        );
        zoneDetailDataVo.setCmsCount(cmsCount);
        zoneDetailDataVo.setZoneUrl(
                EscapeUtil.removeExtraSlashOfUrl(
                        gitLinkRequestHelper.gitLinkUrl + "/zone/" + zoneDetail.getKey()
                )
        );
        return zoneDetailDataVo;
    }

    /**
     * 查询特色专区详情列表
     *
     * @param zoneDetailSearchVo 特色专区详情
     * @return 特色专区详情
     */
    @Override
    public GenericsTableDataInfo<ZoneDetailDataVo> selectZoneDetailList(ZoneDetailSearchVo zoneDetailSearchVo) {
        List<ZoneDetail> zoneDetailList = zoneDetailMapper.selectZoneDetailList(zoneDetailSearchVo.toZoneDetail());
        return PageUtils.toPage(zoneDetailList, this::selectZoneDetailDataByZoneDetail);
    }

    /**
     * 新增特色专区详情
     *
     * @param zoneDetail 特色专区详情
     * @return 结果
     */
    @Override
    public int insertZoneDetail(ZoneDetail zoneDetail) {
        zoneDetail.setCreateTime(DateUtils.getNowDate());
        zoneDetail.setCreateBy(SecurityUtils.getUsername());
        return zoneDetailMapper.insertZoneDetail(zoneDetail);
    }

    /**
     * 修改特色专区详情
     *
     * @param zoneDetailUpdateVo 特色专区详情
     * @return 结果
     */
    @Override
    public int updateZoneDetail(ZoneDetailUpdateVo zoneDetailUpdateVo) {
        ZoneDetail oldZoneDetail = selectZoneDetailById(zoneDetailUpdateVo.getId());
        if (StringUtils.isNotEmpty(zoneDetailUpdateVo.getKey())) {
            if (!zoneDetailUpdateVo.getKey().equals(oldZoneDetail.getKey())) {
                ZoneDetail zoneDetailByKey = zoneDetailMapper.selectZoneDetailByKey(zoneDetailUpdateVo.getKey());
                if (zoneDetailByKey != null) {
                    throw new ServiceException(String.format("该专区标识已被[%s]专区使用(专区标识[%s])", zoneDetailByKey.getName(), zoneDetailUpdateVo.getKey()));
                }
            }
            checkZoneKey(zoneDetailUpdateVo.getKey());
        }
        ZoneDetail zoneDetail = zoneDetailUpdateVo.toZoneDetail();
        zoneDetail.setUpdateTime(DateUtils.getNowDate());
        //更新专区数据时需清理Redis中专区数据，保证取到的时最新专区数据
        String zoneJSONOfZoneIdKey = CacheConstants.ZONE_JSON_OF_ZONE_ID_KEY + oldZoneDetail.getId();
        redisService.deleteObject(zoneJSONOfZoneIdKey);
        String zoneJSONOfDeptIdKey = CacheConstants.ZONE_JSON_OF_DEPT_ID_KEY + oldZoneDetail.getDeptId();
        redisService.deleteObject(zoneJSONOfDeptIdKey);
        // 专区资源审核设置由需要审核修改为不需要审核时，需检查当前专区下是否存在待审核资源，如果存在，需要处理完成后再修改配置
        if (zoneDetail.getResourceNeedAudit() != null && (0 == zoneDetail.getResourceNeedAudit())) {
            ZoneResource zoneResourceSearch = new ZoneResource();
            zoneResourceSearch.setZoneId(zoneDetail.getId());
            zoneResourceSearch.setAuditStatus(ZoneConstants.RESOURCE_NOT_AUDIT);
            Integer notAuditCount = zoneResourceMapper.selectZoneResourceCount(zoneResourceSearch);
            if (notAuditCount > 0) {
                throw new ServiceException("当前专区下存在待审核资源，需完成审核后才能将专区资源修改为不需要审核(专区名称[%s],待审核资源数量[%d])", oldZoneDetail.getName(), notAuditCount);
            }
        }
        // 专区资讯审核设置由需要审核修改为不需要审核时，需检查当前专区下是否存在待审核资讯，如果存在，需要处理完成后再修改配置
        if (zoneDetail.getDocNeedAudit() != null && (0 == zoneDetail.getDocNeedAudit())) {
            Long notAuditCount = FeignUtils.getReturnData(
                    remoteCmsService.getNotAuditCmsCountByDeptId(oldZoneDetail.getDeptId(), SecurityConstants.INNER)
            );
            if (notAuditCount != null && notAuditCount > 0) {
                throw new ServiceException("当前专区下存在待审核资讯，需完成审核后才能将专区资讯修改为不需要审核(专区名称[%s],待审核资讯数量[%d])", oldZoneDetail.getName(), notAuditCount);
            }
        }
        int updateCount = zoneDetailMapper.updateZoneDetail(zoneDetail);
        // 专区资讯审核设置发生变化时，自动更新分支保护设置
        if (zoneDetail.getDocNeedAudit() != null &&
                updateCount > 0 && (!oldZoneDetail.getDocNeedAudit().equals(zoneDetail.getDocNeedAudit()))) {
            String cmsProjectJson = FeignUtils.getReturnData(remoteCmsService.getProjectByDeptId(oldZoneDetail.getDeptId(), SecurityConstants.INNER));
            if (StringUtils.isNotEmpty(cmsProjectJson)) {
                JSONObject jsonObject = JSONObject.parseObject(cmsProjectJson);
                if (jsonObject != null) {
                    String userName = jsonObject.getString("username");
                    String identifier = jsonObject.getString("identifier");
                    String operationType = zoneDetail.getDocNeedAudit() == 1 ? "create" : "delete";
                    FeignUtils.getReturnData(remoteCmsService.autoOperateZoneCmsProjectWhenAuditStatusChangedByDept(userName, identifier, oldZoneDetail.getDeptId(), operationType, SecurityConstants.INNER));
                }
            }
        }
        return updateCount;
    }

    @Override
    public void checkZoneKey(String key) {
        int minLength = 2;
        int maxLength = 20;
        if (key.length() < minLength || key.length() > maxLength) {
            throw new ServiceException("专区标识长度最小为2，最大为20");
        }
        String pattern = "^[a-zA-Z0-9][a-zA-Z0-9_\\-.]*[a-zA-Z0-9]$";
        if (!key.matches(pattern)) {
            throw new ServiceException("专区标识只能包含数字，字母，下划线(_)，中划线(-)，英文句号(.)，必须以数字和字母开头，不能以下划线/中划线/英文句号开头和结尾");
        }
    }

    /**
     * 批量删除特色专区详情
     *
     * @param ids 需要删除的特色专区详情主键
     * @return 结果
     */
    @Override
    public int deleteZoneDetailByIds(Long[] ids) {
        return zoneDetailMapper.deleteZoneDetailByIds(ids);
    }

    /**
     * 删除特色专区详情信息
     *
     * @param deptName 特色专区名称
     * @param deptName
     * @return 结果
     */
    @Override
    public int deleteZoneDetailByDeptName(String deptName) {
        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByName(deptName);
        if (zoneDetail == null) {
            return 0;
        }
        // 1、删除专区对应项目
        remoteCmsService.removeByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER);
        // 2、删除专区会员聚合、会员类别、会员等级
        zoneMemberMapper.deleteZoneMemberByZoneId(zoneDetail.getId());
        zoneMemberTypeMapper.deleteZoneMemberTypeByZoneId(zoneDetail.getId());
        zoneMemberLevelMapper.deleteZoneMemberLevelByZoneId(zoneDetail.getId());
        // 3、删除专区项目聚合、项目类别
        zoneProjectMapper.deleteZoneProjectByZoneId(zoneDetail.getId());
        zoneProjectTypeMapper.deleteZoneProjectTypeByZoneId(zoneDetail.getId());
        // 4、删除专区资源聚合、资源类型、资源领域
        zoneResourceMapper.deleteZoneResourceByZoneId(zoneDetail.getId());
        zoneResourceTypeMapper.deleteZoneResourceTypeByZoneId(zoneDetail.getId());
        zoneResourceDomainMapper.deleteZoneResourceDomainByZoneId(zoneDetail.getId());
        // 5、删除专区合作伙伴、合作伙伴类型
        zonePartnersMapper.deleteZonePartnersByZoneId(zoneDetail.getId());
        zonePartnersTypeMapper.deleteZonePartnersTypeByZoneId(zoneDetail.getId());
        return zoneDetailMapper.deleteZoneDetailById(zoneDetail.getId());
    }

    @Override
    public Long insertZoneDetailByDept(Long deptId) {
        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByDeptId(deptId);
        if (zoneDetail != null) {
            throw new ServiceException("该组织已创建特色专区(组织id[" + deptId + "])");
        }
        zoneDetail = setZoneDetailPreData(deptId);

        zoneDetail.setKey(genZoneKey(zoneDetail.getName()));
        boolean isSuccess = insertZoneDetail(zoneDetail) > 0;
        if (isSuccess) {
            zoneAsyncService.asyncInitZoneData(zoneDetail);
        }

        return zoneDetail.getId();
    }

    @Override
    public Long createZoneByApplication(ZoneApplicationCreateZoneVo zoneApplicationCreateZoneVo) {
        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByKey(zoneApplicationCreateZoneVo.getKey());
        if (zoneDetail != null) {
            throw new ServiceException("该专区标识已存在(专区标识[%s])", zoneApplicationCreateZoneVo.getKey());
        }
        //通过Feign创建部门
        Long deptId = FeignUtils.getReturnData(remoteDeptService.addDeptByZone(zoneApplicationCreateZoneVo.getName(), SecurityConstants.INNER));
        if (deptId == null) {
            throw new ServiceException("组织创建失败(专区名称[" + zoneApplicationCreateZoneVo.getName() + "])");
        }
        zoneDetail = setZoneDetailPreData(deptId);
        zoneDetail.setKey(zoneApplicationCreateZoneVo.getKey());
        zoneDetail.setMainTitle(zoneApplicationCreateZoneVo.getName());
        zoneDetail.setFirstTitle(zoneApplicationCreateZoneVo.getName());
        zoneDetail.setIntroductionContent(zoneApplicationCreateZoneVo.getIntroduction());
        boolean isSuccess = insertZoneDetail(zoneDetail) > 0;
        if (isSuccess) {
            zoneAsyncService.asyncInitZoneData(zoneDetail);
        }

        return zoneDetail.getId();
    }

    private ZoneDetail setZoneDetailPreData(Long deptId) {
        //通过Feign获取部门信息
        SysDept sysDept = FeignUtils.getReturnData(remoteDeptService.getDeptByDeptId(deptId, SecurityConstants.INNER));
        if (sysDept == null) {
            throw new ServiceException("该组织不存在(组织id[" + deptId + "])");
        }
        //通过Feign创建特色专区新闻动态对应项目
        Long cmsProjectId = FeignUtils.getReturnData(
                remoteCmsService.autoAddZoneCmsProjectByDept(deptId, SecurityConstants.INNER));

        if (cmsProjectId == null || cmsProjectId == 0) {
            throw new ServiceException("特色专区创建新闻动态对应的GitLink项目失败(组织id[" + deptId + "])");
        }
        ZoneDetail zoneDetail = new ZoneDetail();
        zoneDetail.setCmsProjectId(cmsProjectId);
        zoneDetail.setName(sysDept.getDeptName());
        zoneDetail.setDeptId(deptId);
        zoneDetail.setCmsProjectId(cmsProjectId);
        return zoneDetail;
    }

    @Override
    public String genZoneKey(String deptName) {
        String zoneKey = PinYinStringUtils.toFirstChar(deptName);
        String extraZoneKey = zoneKey;
        ZoneDetail zoneDetailByZoneKey = zoneDetailMapper.selectZoneDetailByKey(extraZoneKey);
        int zoneDetailExtra = 1;
        while (zoneDetailByZoneKey != null) {
            extraZoneKey = zoneKey + zoneDetailExtra;
            zoneDetailByZoneKey = zoneDetailMapper.selectZoneDetailByKey(extraZoneKey);
            zoneDetailExtra++;
        }
        return extraZoneKey;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateZoneDetailByDept(SysDept dept) {
        ZoneDetail zoneDetail = selectZoneDetailByDeptId(dept.getDeptId());
        zoneDetail.setName(dept.getDeptName());
        boolean result = Boolean.TRUE.equals(FeignUtils.getReturnData(
                remoteCmsService.autoUpdateZoneCmsProjectByDept(dept, SecurityConstants.INNER)));
        if (!result) {
            throw new ServiceException("特色专区更新新闻动态对应的GitLink项目失败(特色专区Id[" + zoneDetail.getId() + "])");
        }
        zoneDetail.setUpdateTime(DateUtils.getNowDate());
        return zoneDetailMapper.updateZoneDetail(zoneDetail) > 0;
    }

    @Override
    public String getZoneJSONByZoneId(Long zoneId) {
        ZoneDetail zoneDetail = selectZoneDetailById(zoneId);
        return JSON.toJSONString(zoneDetail);
    }

    @Override
    public Long getZoneHomePageCmsSizeByDeptId(Long deptId) {
        ZoneDetail zoneDetail = selectZoneDetailByDeptId(deptId);
        Long cmsHomePageSize = zoneDetail.getHomepageCmsSize();
        if (cmsHomePageSize == null) {
            return 0L;
        }
        return cmsHomePageSize;
    }

    @Override
    public String checkZoneRole(Long zoneId, HttpServletRequest request) {
        try {
            ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailById(zoneId);
            if (zoneDetail == null) {
                return null;
            }
            SysDept sysDept = FeignUtils.getReturnData(
                    remoteDeptService.getDeptByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER)
            );
            if (sysDept == null) {
                return null;
            }
            String gitLinkToken = AuthUtil.getGitLinkRequestToken(request);
            if (StringUtils.isEmpty(gitLinkToken)) {
                return null;
            }
            String userName = FeignUtils.getReturnData(
                    remoteUserService.getUserNameByGitLinkToken(gitLinkToken, SecurityConstants.INNER)
            );
            if (StringUtils.isEmpty(userName)) {
                return null;
            }
            List<String> deptAncestors = Arrays.asList(sysDept.getAncestors().split(","));
            List<SysUserDeptRole> userIdentifyList =
                    FeignUtils.getReturnData(remoteUserService.getSysUserDeptRoleListByUserName(userName, SecurityConstants.INNER));
            if (userIdentifyList != null && !userIdentifyList.isEmpty()) {
                // 查找该用户父级组织中的非会员身份
                SysUserDeptRole notMemberParentUserIdentify = userIdentifyList.stream()
                        .filter(x -> !zoneDetail.getDeptId().equals(x.getDeptId())
                                && deptAncestors.contains(String.valueOf(x.getDeptId()))
                                && (x.getSysRole() != null && !SystemRole.ZONE_MEMBER.getRoleKey().equals(x.getSysRole().getRoleKey())))
                        .findFirst().orElse(null);
                //优先判断该用户是否存在本专区的管理权限，若存在则直接切到本专区管理身份，便于管理
                //切到本专区时，前台的后台管理按钮将跳转到首页配置页面
                SysUserDeptRole userIdentify = userIdentifyList.stream()
                        .filter(x -> zoneDetail.getDeptId().equals(x.getDeptId()))
                        .findFirst().orElse(null);
                if (userIdentify != null) {
                    return genChangeCurrentUserIdentityUrl(userIdentify, gitLinkToken, zoneId, notMemberParentUserIdentify);
                }
                // 当不存在当前专区对应的管理权限时查找在父级组织中是否存在身份
                userIdentify = userIdentifyList.stream()
                        .filter(x -> deptAncestors.contains(String.valueOf(x.getDeptId())))
                        .findFirst().orElse(null);
                if (userIdentify != null) {
                    return genChangeCurrentUserIdentityUrl(userIdentify, gitLinkToken, zoneId, notMemberParentUserIdentify);
                }
            }
            return null;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * <a href="https://www.gitlink.org.cn/Gitlink/forgeplus/issues/3523">参照需求</a>
     *
     * @param userIdentify
     * @param gitLinkToken
     * @param zoneId
     * @param notMemberParentUserIdentify
     * @return
     */
    private String genChangeCurrentUserIdentityUrl(SysUserDeptRole userIdentify, String gitLinkToken, Long zoneId, SysUserDeptRole notMemberParentUserIdentify) {
        String roleKey = userIdentify.getSysRole().getRoleKey();
        Long deptId = userIdentify.getDeptId();
        if (SystemRole.ZONE_MEMBER.getRoleKey().equals(roleKey)) {
            if (notMemberParentUserIdentify != null) {
                roleKey = notMemberParentUserIdentify.getSysRole().getRoleKey();
                deptId = notMemberParentUserIdentify.getDeptId();
            }
        }
        if (SystemRole.ZONE_ADMIN.getRoleKey().equals(roleKey)
                || SystemRole.ZONE_OPERATOR.getRoleKey().equals(roleKey)) {
            return zoneConfigurationUrl + "?changeCurrentUserIdentity=" + deptId;
        }
        if (SystemRole.PLATFORM_ADMIN.getRoleKey().equals(roleKey)) {
            return zoneConfigurationUrl + "/" + zoneId + "?changeCurrentUserIdentity=" + deptId;
        }

        return null;
    }


    private void zoneTemplateCheck(String template, ZoneDetailDataVo zoneDetailDataVo) {
        SysDictData zoneDefaultTemplate = DictUtils.getDictDataCacheByLabel(
                CacheConstants.ZONE_TEMPLATE,
                CacheConstants.ZONE_TEMPLATE_DEFAULT_LABEL);
        if (zoneDefaultTemplate != null) {
            //当用户查询模板不为空且非通用模板，需检查该专区是否可以使用该模板
            if (StringUtils.isNotEmpty(template)
                    && !zoneDefaultTemplate.getDictValue().equals(template)) {
                //若查询模板非专区设置模板，即模板不可访问
                if (!template.equals(zoneDetailDataVo.getTemplate())) {
                    throw new ServiceException("该特色专区无法访问该模板(专区名称[" + zoneDetailDataVo.getName() + "]，模板名[" + template + "])"
                            , HttpStatus.NOT_FOUND);
                }
            }
            //当专区设置了非通用模板时，需检查是否与查询的模板相匹配（空代表为通用模板）
            if (StringUtils.isNotEmpty(zoneDetailDataVo.getTemplate())
                    && !zoneDefaultTemplate.getDictValue().equals(zoneDetailDataVo.getTemplate())) {
                //若此时查询的为通用模板，应拒绝用户访问
                if (StringUtils.isEmpty(template) || zoneDefaultTemplate.getDictValue().equals(template)) {
                    throw new ServiceException("该特色专区无法访问该模板(专区名称[" + zoneDetailDataVo.getName() + "]，模板名[" + zoneDefaultTemplate.getDictValue() + "])"
                            , HttpStatus.NOT_FOUND);
                }
            }
        }
    }

    @Override
    public ZoneDetailDataVo selectZoneDetailDataByName(String zoneName) {
        SysDictData zoneKey = DictUtils.getDictDataCacheByLabel(CacheConstants.ZONE_KEY_ID, zoneName);
        if (zoneKey != null && StringUtils.isNotEmpty(zoneKey.getDictValue())) {
            Long zoneId = Long.valueOf(zoneKey.getDictValue());
            //            zoneTemplateCheck(template,zoneDetailDataVo);
            return selectZoneDetailDataById(zoneId);
        }
        throw new ServiceException(HttpStatus.NOT_FOUND, "该特色专区不存在或无权限访问(专区名称[" + zoneName + "])");
    }

    @Override
    public Integer selectZoneDetailCount(ZoneDetailSearchVo zoneDetailSearchVo) {
        return zoneDetailMapper.selectZoneDetailCount(zoneDetailSearchVo);
    }

    @Override
    public ZoneDetailDataVo selectZoneDetailDataByKey(String zoneKey) {
        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByKey(zoneKey);
        if (zoneDetail == null) {
            throw new ServiceException(HttpStatus.NOT_FOUND, "该特色专区不存在或无权限访问(专区标识[" + zoneKey + "])");
        }
        //        zoneTemplateCheck(template,zoneDetailDataVo);
        return getZoneDetailDataVoAndCmsProject(zoneDetail);

    }

    @Override
    public int publishZoneDetail(Long id) {
        ZoneDetail zoneDetail = selectZoneDetailById(id);
        if (0 == zoneDetail.getIsPublish()) {
            zoneDetail.setIsPublish(1);
        } else {
            zoneDetail.setIsPublish(0);
        }
        zoneDetail.setUpdateTime(DateUtils.getNowDate());
        zoneDetail.setUpdateBy(SecurityUtils.getUsername());
        return zoneDetailMapper.updateZoneDetail(zoneDetail);
    }

    @Override
    public List<ZoneBaseDataVo> selectPublishedZoneBaseList() {
        ZoneDetailSearchVo zoneDetailSearchVo = new ZoneDetailSearchVo();
        zoneDetailSearchVo.setIsPublish(1);
        List<ZoneDetail> zoneDetailList = zoneDetailMapper.selectZoneDetailList(zoneDetailSearchVo.toZoneDetail());
        return zoneDetailList.stream().map(ZoneDetail::toZoneBaseDataVo).collect(Collectors.toList());
    }

    @Override
    public String getZoneJSONByDeptId(Long deptId) {
        ZoneDetail zoneDetail = selectZoneDetailByDeptId(deptId);
        return JSON.toJSONString(zoneDetail);
    }

    @Override
    public ZoneFrontRoleVo checkCurrentRoleInZone(Long zoneId) {
        ZoneFrontRoleVo zoneFrontRoleVo = new ZoneFrontRoleVo();
        ZoneDetail zoneDetail = selectZoneDetailById(zoneId);
        boolean isZoneAdmin = AuthUtil.hasUserIdentity(zoneDetail.getDeptId(), SystemRole.ZONE_ADMIN.getRoleKey());
        boolean isZoneOperator = AuthUtil.hasUserIdentity(zoneDetail.getDeptId(), SystemRole.ZONE_OPERATOR.getRoleKey());
        boolean isZoneMember = AuthUtil.hasUserIdentity(zoneDetail.getDeptId(), SystemRole.ZONE_MEMBER.getRoleKey());
        if (isZoneAdmin || isZoneOperator) {
            zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_MANAGER);
            zoneFrontRoleVo.setResourceManageUrl(resourceManageUrl);
            zoneFrontRoleVo.setDocManageUrl(docManageUrl);
        } else if (isZoneMember) {
            zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_MEMBER);
        } else {
            zoneFrontRoleVo.setRole(ZoneConstants.FRONT_ROLE_NONE);
        }

        return zoneFrontRoleVo;
    }

    @Override
    public int lockCmsByDeptId(Long deptId, Integer lockStatus) {
        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByDeptId(deptId);
        ZoneDetailUpdateVo zoneDetailUpdateVo = new ZoneDetailUpdateVo();
        zoneDetailUpdateVo.setId(zoneDetail.getId());
        zoneDetailUpdateVo.setIsLockCms(lockStatus);
        return updateZoneDetail(zoneDetailUpdateVo);
    }

    /**
     * 关联需求：https://www.gitlink.org.cn/Gitlink/forgeplus/issues/3526
     *
     * @return 结果
     */
    @Override
    public String getChangeUserIdentityZoneUrl() {
        SysUserDeptRole userIdentify = SecurityUtils.getUserIdentity();
        if (userIdentify == null || userIdentify.getSysRole() == null || userIdentify.getSysDept() == null) {
            return null;
        }
        String roleKey = userIdentify.getSysRole().getRoleKey();
        Long deptId = userIdentify.getSysDept().getDeptId();
        if (SystemRole.ZONE_MEMBER.getRoleKey().equals(roleKey)) {
            return adminUrl;
        }
        if (SystemRole.ZONE_ADMIN.getRoleKey().equals(roleKey)
                || SystemRole.ZONE_OPERATOR.getRoleKey().equals(roleKey)) {
            return zoneConfigurationUrl;
        }
        if (SystemRole.PLATFORM_ADMIN.getRoleKey().equals(roleKey)) {
            ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByDeptId(deptId);
            if (zoneDetail == null) {
                return zoneAdminUrl;
            }
            return zoneConfigurationUrl + "/" + zoneDetail.getId();
        }

        return adminUrl;
    }

    @Override
    public void checkZoneDataScope(Long zoneId) {
        ZoneDetail zoneDetail = new ZoneDetail();
        zoneDetail.setId(zoneId);
        List<ZoneDetail> zoneDetailList = zoneDetailMapper.selectZoneDetailList(zoneDetail);
        if (zoneDetailList.stream().noneMatch(x -> x.getId().equals(zoneId))) {
            throw new ServiceException(HttpStatus.FORBIDDEN, "用户无当前专区权限");
        }
    }

    @Override
    public ZoneDetail selectZoneDetailByKey(String key) {
        return zoneDetailMapper.selectZoneDetailByKey(key);
    }

    @Override
    public ZoneDetail selectZoneDetailByName(String name) {
        return zoneDetailMapper.selectZoneDetailByName(name);
    }


    /**
     * 通过组织Id查找特色专区，不存在时抛出异常
     *
     * @param deptId
     * @return
     */
    private ZoneDetail selectZoneDetailByDeptId(Long deptId) {
        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailByDeptId(deptId);
        if (zoneDetail == null) {
            throw new ServiceException("该组织未创建特色专区(组织id[" + deptId + "])");
        }
        return zoneDetail;
    }

    @Override
    public ZoneStatisticsVo getZoneStatistics(Long zoneId) {
        ZoneStatisticsVo zoneStatisticsVo = new ZoneStatisticsVo();

        ZoneDetail zoneDetail = zoneDetailMapper.selectZoneDetailById(zoneId);
        Set<String> usernameSet = new HashSet<>();
        // 获取专区会员数
        ZoneMemberSearchVo zoneMemberSearchVo = new ZoneMemberSearchVo();
        zoneMemberSearchVo.setZoneId(zoneId);
        List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo);
        zoneMemberList.forEach(x -> {
            if (x.getSysUser() != null) {
                usernameSet.add(x.getSysUser().getUserName());
            }
        });

        // 获取专区内用户列表
        GenericsTableDataInfo<SysUserDeptRole> userTable = FeignUtils.getReturnData(
                remoteUserService.searchUserIdentifierListByDept(zoneDetail.getDeptId(), null, null, null, SecurityConstants.INNER)
        );
        if (userTable != null && userTable.getTotal() > 0) {
            userTable.getRows().forEach(x -> {
                if (x.getSysUser() != null) {
                    usernameSet.add(x.getSysUser().getUserName());
                }
            });
        }
        // 获取仓库贡献者数量
        ZoneProjectSearchVo zoneProjectSearchVo = new ZoneProjectSearchVo();
        zoneProjectSearchVo.setZoneId(zoneId);
        List<ZoneProject> zoneProjectList = zoneProjectMapper.selectZoneProjectList(zoneProjectSearchVo);
        zoneStatisticsVo.setProjectCount((long) zoneProjectList.size());
        for (ZoneProject zoneProject : zoneProjectList) {
            // 获取每个项目下的贡献者数量
            ProjectGitlinkInfoVo gitlinkInfoVo = redisService.getCacheObject(CacheConstants.getZoneProjectGitlinkInfo(zoneProject.getGitlinkProjectId()));
            if (gitlinkInfoVo != null && gitlinkInfoVo.getContributorsList() != null) {
                for (JSONObject contributor : gitlinkInfoVo.getContributorsList().toJavaList(JSONObject.class)) {
                    String username = contributor.getString("login");
                    if (StringUtils.isNotEmpty(username)) {
                        usernameSet.add(username);
                    } else {
                        usernameSet.add(contributor.getString("email"));
                    }

                }
            }
        }
        zoneStatisticsVo.setCommunityUserCount((long) usernameSet.size());
        Long cmsDocCount = FeignUtils.getReturnData(remoteCmsService.getCmsCountByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER));
        zoneStatisticsVo.setCmsDocCount(cmsDocCount == null ? 0L : cmsDocCount);
        Long cmsDocVisits = FeignUtils.getReturnData(remoteCmsService.getCmsDocVisitsByDeptId(zoneDetail.getDeptId(), SecurityConstants.INNER));
        zoneStatisticsVo.setCmsDocVisits(cmsDocVisits == null ? 0L : cmsDocVisits);

        ZoneResource zoneResource = new ZoneResource();
        zoneResource.setZoneId(zoneId);
        List<ZoneResource> zoneResourceList = zoneResourceMapper.selectZoneResourceList(zoneResource);
        zoneStatisticsVo.setResourceCount((long) zoneResourceList.size());

        ZoneSpecialProject zoneSpecialProject = new ZoneSpecialProject();
        zoneSpecialProject.setZoneId(zoneId);
        List<ZoneSpecialProject> zoneSpecialProjectList = zoneSpecialProjectService.selectZoneSpecialProjectList(zoneSpecialProject);
        zoneStatisticsVo.setSpecialProjectCount((long) zoneSpecialProjectList.size());

        return zoneStatisticsVo;
    }

}
