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

import com.alibaba.fastjson2.JSONObject;
import com.microservices.common.core.constant.CacheConstants;
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.StringUtils;
import com.microservices.common.core.utils.html.EscapeUtil;
import com.microservices.common.core.utils.uuid.IdUtils;
import com.microservices.common.core.web.page.GenericsTableDataInfo;
import com.microservices.common.datascope.annotation.DataScope;
import com.microservices.common.httpClient.constant.GitLinkConstants;
import com.microservices.common.httpClient.domain.GitLinkRequestUrl;
import com.microservices.common.httpClient.util.GitLinkRequestHelper;
import com.microservices.common.redis.service.RedisService;
import com.microservices.common.security.utils.SecurityUtils;
import com.microservices.system.api.RemoteDeptService;
import com.microservices.system.api.RemoteUserService;
import com.microservices.system.api.domain.SysUser;
import com.microservices.system.api.domain.SysUserDeptRole;
import com.microservices.system.api.utils.FeignUtils;
import com.microservices.zone.detail.domain.ZoneDetail;
import com.microservices.zone.detail.service.IZoneDetailService;
import com.microservices.zone.member.domain.ZoneMember;
import com.microservices.zone.member.domain.ZoneMemberType;
import com.microservices.zone.member.domain.vo.*;
import com.microservices.zone.member.mapper.ZoneMemberMapper;
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.utils.ZoneConstants;
import com.microservices.zone.utils.ZoneGitLinkRequestUrl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 特色专区会员Service业务层处理
 *
 * @author otto
 * @date 2023-05-16
 */
@Service
public class ZoneMemberServiceImpl implements IZoneMemberService {
    private static final Logger logger = LoggerFactory.getLogger(ZoneMemberServiceImpl.class);
    @Autowired
    private ZoneMemberMapper zoneMemberMapper;
    @Autowired
    private RemoteUserService remoteUserService;
    @Autowired
    private RemoteDeptService remoteDeptService;
    @Autowired
    private GitLinkRequestHelper gitLinkRequestHelper;
    @Autowired
    private IZoneMemberTypeService zoneMemberTypeService;
    @Autowired
    private IZoneMemberLevelService zoneMemberLevelService;
    @Autowired
    private IZoneDetailService zoneDetailService;
    @Autowired
    private RedisService redisService;

    @Value("${zone.invitationLinkExpirationTime}")
    private Long invitationLinkExpirationTime;
    @Value("${zone.invitationPagePath}")
    private String invitationPagePath;
    @Value("${zone.messageTemplate}")
    private String messageTemplate;
    @Value("${zone.zoneMemberPath}")
    private String zoneMemberPath;
    @Value("${zone.memberMessageTemplate}")
    private String memberMessageTemplate;
    @Value("${zone.zoneHomepagePath}")
    private String zoneHomepagePath;
    @Value("${http.gitLinkUrl}")
    private String gitLinkUrl;

    /**
     * 查询特色专区会员
     *
     * @param id 特色专区会员主键
     * @return 特色专区会员
     */
    @Override
    public ZoneMember selectZoneMemberById(Long id) {
        ZoneMember zoneMember = zoneMemberMapper.selectZoneMemberById(id);
        if (zoneMember == null) {
            throw new ServiceException("该特色专区会员不存在或无权限访问(专区id[" + id + "])");
        }
        zoneDetailService.checkZoneDataScope(zoneMember.getZoneId());
        return zoneMember;
    }

    /**
     * 查询特色专区会员列表
     *
     * @param zoneMemberSearchVo 特色专区会员
     * @return 特色专区会员
     */
    @Override
    @DataScope(deptAlias = "zm")
    public GenericsTableDataInfo<ZoneMemberDetailVo> selectZoneMemberList(ZoneMemberSearchVo zoneMemberSearchVo, boolean isOpen) {
        zoneMemberSearchVo.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
        zoneMemberSearchVo.setIsOpen(isOpen);
        List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo);
        return PageUtils.toPage(zoneMemberList, this::toZoneMemberDetailVo);
    }

    private ZoneMemberDetailVo toZoneMemberDetailVo(ZoneMember zoneMember) {
        ZoneMemberDetailVo zoneMemberDetailVo = new ZoneMemberDetailVo();
        BeanUtils.copyProperties(zoneMember, zoneMemberDetailVo);
        String username = zoneMember.getSysUser().getUserName();
        zoneMemberDetailVo.setUsername(username);
        zoneMemberDetailVo.setGitLinkUserUrl(
                EscapeUtil.removeExtraSlashOfUrl(
                        gitLinkUrl + "/" + username
                ));
        return zoneMemberDetailVo;
    }

    private void sendInvitationMailMessage(String template, String receiver, Map<String, String> params, ZoneDetail zoneDetail) {
        SendMailVo mailVo = new SendMailVo();
        mailVo.setSource("CustomTip");
        mailVo.setTemplate_id(template);
        mailVo.setUsers_id(Arrays.asList(receiver));
        mailVo.setProps(params);
        JSONObject result = gitLinkRequestHelper.doPost(ZoneGitLinkRequestUrl.SEND_NOTICES(), mailVo);
        if (!GitLinkConstants.SUCCESS_MESSAGE.equals(result.get(GitLinkConstants.MESSAGE_KEY))) {
            throw new ServiceException("给用户发送通知失败(专区名称[" + zoneDetail.getName() + "]，GitLink用户Id[" + receiver + "])");
        }
    }

    private String getZoneMemberInvitationTokenKey(String invitationToken) {
        return CacheConstants.ZONE_MEMBER_INVITATION_TOKEN_KEY + invitationToken;
    }

    private String getZoneMemberInvitationKey(Long zoneId, Long userId) {
        return CacheConstants.ZONE_MEMBER_INVITATION_KEY + zoneId + "-" + userId;
    }

    private void createMemberUserIdentify(ZoneDetail zoneDetail, SysUser memberUser) {
        // 增加会员时给会员赋予该专区下的会员身份
        List<SysUserDeptRole> sysUserDeptRoleList = FeignUtils.getReturnData(
                remoteUserService.getSysUserDeptRoleListByUserName(memberUser.getUserName(), SecurityConstants.INNER)
        );
        boolean hasRoleInZone = false;
        if (sysUserDeptRoleList != null) {
            hasRoleInZone = sysUserDeptRoleList.stream().anyMatch(x -> zoneDetail.getDeptId().equals(x.getDeptId()));
        }
        String userKey = SecurityUtils.getUserKey();
        System.out.println(userKey);
        // 当用户在专区下没有其他角色时才需要赋予会员身份
        if (!hasRoleInZone) {
            boolean addUserIdentify = Boolean.TRUE.equals(FeignUtils.getReturnData(
                    remoteUserService.addUserIdentify(
                            zoneDetail.getDeptId()
                            , memberUser.getUserId()
                            , SystemRole.ZONE_MEMBER.getRoleKey()
                            , SecurityConstants.INNER)
            ));
            if (!addUserIdentify) {
                throw new ServiceException("会员身份创建失败，请联系管理员");
            }
        }
    }

    /**
     * 新增特色专区会员
     *
     * @param zoneMemberInputVo 特色专区会员
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int insertZoneMember(ZoneMemberInputVo zoneMemberInputVo) {
        ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailById(zoneMemberInputVo.getZoneId());
        SysUser sysUser = FeignUtils.getReturnData(
                remoteUserService.getSysUserByGitLinkUserId(zoneMemberInputVo.getGitLinkUserId(), SecurityConstants.INNER));
        if (sysUser == null) {
            sysUser = FeignUtils.getReturnData(
                    remoteUserService.createUserByGitLinkUserId(zoneMemberInputVo.getGitLinkUserId(), SecurityConstants.INNER));
            if (sysUser == null) {
                throw new ServiceException("该GitLink用户同步到本系统失败(GitLink用户Id[" + zoneMemberInputVo.getGitLinkUserId() + "])");
            }
        }
        ZoneMember zoneMember = zoneMemberMapper.selectZoneMemberByZoneIdAndUserId(zoneDetail.getId(), sysUser.getUserId());
        if (zoneMember != null) {
            throw new ServiceException("专区中已存在该会员(专区名称[" + zoneDetail.getName() + "]，用户名[" + sysUser.getUserName() + "])");
        }
        zoneMemberTypeService.selectZoneMemberTypeByIdAndZoneId(zoneMemberInputVo.getMemberTypeId(), zoneMemberInputVo.getZoneId());
        zoneMemberLevelService.selectZoneMemberLevelByIdAndZoneId(zoneMemberInputVo.getMemberLevelId(), zoneMemberInputVo.getZoneId());
        zoneMember = zoneMemberInputVo.toZoneMember();

        zoneMember.setDeptId(zoneDetail.getDeptId());
        zoneMember.setUserId(sysUser.getUserId());
        zoneMember.setCreateTime(DateUtils.getNowDate());
        zoneMember.setAuditTime(DateUtils.getNowDate());
        if (!zoneMemberInputVo.getIsSendInvitation()) {
            zoneMember.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
            createMemberUserIdentify(zoneDetail, sysUser);
        } else {
            Map<String, String> params = new HashMap<>(3);
            params.put("zoneName", zoneDetail.getName());
            params.put("username", sysUser.getUserName());
            //生成随机Token存储到Redis中，Token有效期为邀请链接有效时长
            String invitationToken = IdUtils.simpleUUID();
            //将Token作为值，组织Id和用户Id作为Key存储到Redis中，便于删除用户时同步清理Token
            redisService.setCacheObject(getZoneMemberInvitationKey(zoneDetail.getId(), sysUser.getUserId()), invitationToken, invitationLinkExpirationTime, TimeUnit.DAYS);
            //将生成的Token存储到Redis中，便于用户进行确认邀请操作时识别用户身份
            redisService.setCacheObject(getZoneMemberInvitationTokenKey(invitationToken),
                    String.valueOf(zoneMemberInputVo.getGitLinkUserId()),
                    invitationLinkExpirationTime,
                    TimeUnit.DAYS);
            String toUrl = gitLinkUrl + invitationPagePath + "?invitationToken=" + invitationToken + "&zoneId=" + zoneDetail.getId();
            params.put("to_url", EscapeUtil.removeExtraSlashOfUrl(toUrl));
            sendInvitationMailMessage(messageTemplate, String.valueOf(zoneMemberInputVo.getGitLinkUserId()), params, zoneDetail);
            //将会员审核状态设置为邀请中
            zoneMember.setIsAudit(ZoneConstants.MEMBER_AUDIT_INVITED);
        }
        //设置排序值为当前最大的排序值+1
        Integer maxSort = zoneMemberMapper.selectMaxSortByZoneId(zoneMember);
        if (maxSort == null) {
            maxSort = 1;
        } else {
            maxSort++;
        }
        zoneMember.setSort(maxSort);
        return zoneMemberMapper.insertZoneMember(zoneMember);
    }

    private Integer setSortByOrder(ZoneMember zoneMember, Integer order) {
        int setSort;
        Long id = zoneMember.getId();
        String name = zoneMember.getName();
        Integer maxCount = zoneMemberMapper.selectCountByZoneId(zoneMember);
        //检查用户输入顺序是否合法
        if (order < 1 || order > maxCount) {
            throw new ServiceException(String.format("顺序最小为1，最大为%d(会员[%s])", maxCount, name));
        }
        //获取文章/栏目所在行
        ZoneMember theOrderContainSelf = zoneMemberMapper.selectZoneMemberByOrderAndZoneId(zoneMember, order, true);
        //当指定序号文章/栏目为当前文章/栏目时，不修改排序
        if (theOrderContainSelf != null && theOrderContainSelf.getId().equals(id)) {
            return null;
        }

        if (order == 1 || order.equals(maxCount)) {
            int minSort = zoneMemberMapper.selectMinSortByZoneId(zoneMember);
            int maxSort = zoneMemberMapper.selectMaxSortByZoneId(zoneMember);
            //当用户输入顺序为1时，文章顺序调整为最大值+1.栏目顺序调整为最小值-1
            if (order == 1) {
                setSort = (minSort - 1);
            } else {
                //当用户输入顺序为列表总数时，文章顺序调整为最小值-1.栏目顺序调整为最大值+1
                setSort = (maxSort + 1);
            }
        } else {
            //获取指定序号的文章/栏目(不包含当前文章/栏目)
            ZoneMember theOrderData = zoneMemberMapper.selectZoneMemberByOrderAndZoneId(
                    zoneMember, order, false);
            if (theOrderData == null) {
                throw new ServiceException(String.format("指定顺序不存在(名称[%s]，顺序[%d])", name, order));
            }
            //计算用户上一个序号对应的排序值(不包含当前文章/栏目)
            ZoneMember theLastOrderData = zoneMemberMapper.selectZoneMemberByOrderAndZoneId(
                    zoneMember, order - 1, false);
            Integer theLastSort = theLastOrderData.getSort();
            if (theOrderData.getSort() - theLastSort > 1) {
                setSort = theLastSort + 1;
            } else {
                setSort = theOrderData.getSort();
                //需要将大于等于该sort的所有数据项sort+1
                Integer updateCount = zoneMemberMapper.batchUpdateSortIncreased(zoneMember, setSort);
                logger.info("批量增加大于指定排序的排序值，共计更新{}条", updateCount);
            }
        }
        return setSort;
    }

    /**
     * 修改特色专区会员
     *
     * @param id
     * @param zoneMemberUpdateVo 特色专区会员
     * @return 结果
     */
    @Override
    public int updateZoneMember(Long id, ZoneMemberUpdateVo zoneMemberUpdateVo) {
        ZoneMember oldZoneMember = selectZoneMemberById(id);
        if (zoneMemberUpdateVo.getMemberTypeId() != null) {
            zoneMemberTypeService.selectZoneMemberTypeByIdAndZoneId(zoneMemberUpdateVo.getMemberTypeId(), oldZoneMember.getZoneId());
        }
        if (zoneMemberUpdateVo.getMemberLevelId() != null) {
            zoneMemberLevelService.selectZoneMemberLevelByIdAndZoneId(zoneMemberUpdateVo.getMemberLevelId(), oldZoneMember.getZoneId());
        }
        ZoneMember zoneMember = zoneMemberUpdateVo.toZoneMember(id);
        if (zoneMemberUpdateVo.getOrder() != null) {
            Integer setSort = setSortByOrder(oldZoneMember, zoneMemberUpdateVo.getOrder());
            zoneMember.setSort(setSort);
        }
        zoneMember.setUpdateTime(DateUtils.getNowDate());
        zoneMember.setUpdateBy(SecurityUtils.getUsername());
        return zoneMemberMapper.updateZoneMember(zoneMember);
    }

    /**
     * 批量删除特色专区会员
     *
     * @param ids 需要删除的特色专区会员主键
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteZoneMemberByIds(Long[] ids) {
        int success = 0;
        for (Long id : ids) {
            success += deleteZoneMemberById(id);
        }
        return success;
    }

    /**
     * 删除特色专区会员信息
     *
     * @param id 特色专区会员主键
     * @return 结果
     */
    @Override
    public int deleteZoneMemberById(Long id) {
        ZoneMember zoneMember = selectZoneMemberById(id);
        if (ZoneConstants.MEMBER_AUDIT_INVITED.equals(zoneMember.getIsAudit())) {
            String invitationKey = getZoneMemberInvitationKey(zoneMember.getZoneId(), zoneMember.getUserId());
            String invitationToken = redisService.getCacheObject(invitationKey);
            String invitationTokenKey = getZoneMemberInvitationTokenKey(invitationToken);
            redisService.deleteObject(invitationKey);
            redisService.deleteObject(invitationTokenKey);
        }
        List<SysUserDeptRole> sysUserDeptRoleList = FeignUtils.getReturnData(
                remoteUserService.getSysUserDeptRoleListByUserName(zoneMember.getSysUser().getUserName(), SecurityConstants.INNER)
        );
        boolean isZoneMember = sysUserDeptRoleList != null
                && sysUserDeptRoleList.stream().anyMatch(
                x -> {
                    if (x.getSysDept() != null && x.getSysRole() != null) {
                        return x.getDeptId().equals(zoneMember.getDeptId())
                                && x.getSysRole().getRoleKey().equals(SystemRole.ZONE_MEMBER.getRoleKey());
                    }
                    return false;
                }
        );
        if (isZoneMember) {
            boolean deleteUserIdentify = Boolean.TRUE.equals(FeignUtils.getReturnData(
                    remoteUserService.deleteUserIdentify(zoneMember.getDeptId(), zoneMember.getUserId(), SystemRole.ZONE_MEMBER.getRoleKey(), SecurityConstants.INNER)
            ));
            if (!deleteUserIdentify) {
                throw new ServiceException("会员身份删除失败，请联系管理员");
            }

        }
        return zoneMemberMapper.deleteZoneMemberById(id);
    }

    @Override
    public GenericsTableDataInfo<JSONObject> selectGitlinkUserList(Long zoneId, GitLinkUserSearchVo gitLinkUserSearchVo) {
        ZoneMemberSearchVo zoneMemberSearchVo = new ZoneMemberSearchVo();
        zoneMemberSearchVo.setZoneId(zoneId);
        List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo);
        JSONObject result = gitLinkRequestHelper.doGet(
                GitLinkRequestUrl.USERS(gitLinkUserSearchVo.genQueryString())
        );
        List<JSONObject> list = result.getList("users", JSONObject.class);
        if(list==null){
            throw new ServiceException("Gitlink用户列表获取失败");
        }

        for (JSONObject userObj : list) {
            if (userObj.containsKey("image_url")) {
                String imagePath = userObj.getString("image_url");
                String authorImageUrl = EscapeUtil.removeExtraSlashOfUrl(String.format("%s/%s", gitLinkUrl, imagePath));
                userObj.put("image_url", authorImageUrl);
            }
            if (zoneId != null) {
                boolean isChoose = zoneMemberList.stream().anyMatch(x -> x.getSysUser() != null && x.getSysUser().getGitlinkUserId().equals(userObj.getLong("user_id")));
                if (isChoose) {
                    userObj.put("isChoose", true);
                } else {
                    userObj.put("isChoose", false);
                }
            }
        }
        Long size = result.getLong("total_count");
        return PageUtils.toPage(list, size);
    }

    @Override
    public SysUser getUserInfoByInvitationToken(String invitationToken) {
        String key = getZoneMemberInvitationTokenKey(invitationToken);
        if (!redisService.hasKey(key)) {
            throw new ServiceException("该邀请链接无效或已过期");
        }
        String gitlinkUserIdStr = redisService.getCacheObject(key);
        long gitlinkUserId;
        try {
            gitlinkUserId = Long.parseLong(gitlinkUserIdStr);
        } catch (Exception e) {
            throw new ServiceException("该邀请链接格式错误(GitLink用户Id[" + gitlinkUserIdStr + "]");
        }
        return FeignUtils.getReturnData(remoteUserService.getSysUserByGitLinkUserId(gitlinkUserId, SecurityConstants.INNER));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean confirmInvitation(Long zoneId, String invitationToken, Boolean isConfirm) {
        SysUser sysUser = getUserInfoByInvitationToken(invitationToken);
        ZoneMember zoneMember = zoneMemberMapper.selectZoneMemberByZoneIdAndUserId(zoneId, sysUser.getUserId());
        if (zoneMember == null) {
            throw new ServiceException("邀请链接无效，该会员不存在(专区Id[" + zoneId + "]，用户名[" + sysUser.getUserName() + "]");
        }
        zoneDetailService.checkZoneDataScope(zoneMember.getZoneId());
        if (isConfirm) {
            zoneMember.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
            //设置排序值为当前最大的排序值+1
            Integer maxSort = zoneMemberMapper.selectMaxSortByZoneId(zoneMember);
            if (maxSort == null) {
                maxSort = 1;
            } else {
                maxSort++;
            }
            zoneMember.setSort(maxSort);
        } else {
            zoneMember.setIsAudit(ZoneConstants.MEMBER_AUDIT_FAILED);
        }
        redisService.deleteObject(getZoneMemberInvitationTokenKey(invitationToken));
        zoneMember.setUpdateTime(DateUtils.getNowDate());
        return zoneMemberMapper.updateZoneMember(zoneMember) > 0;
    }

    @Override
    public boolean applyToJoinZone(Long zoneId, ZoneMemberApplyVo zoneMemberApplyVo) {
        Long currentUserId = SecurityUtils.getUserId();
        String currentUsername = SecurityUtils.getUsername();
        ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailByIdNotVerifiedDataScope(zoneId);
        ZoneMember zoneMember = zoneMemberMapper.selectZoneMemberByZoneIdAndUserId(zoneId, currentUserId);
        if (zoneMember != null) {
            throw new ServiceException("专区中已存在该会员(专区名称[" + zoneDetail.getName() + "]，用户名[" + SecurityUtils.getUsername() + "])");
        }
        JSONObject gitlinkUser = gitLinkRequestHelper.doGet(ZoneGitLinkRequestUrl.USER(currentUsername));
        if (gitlinkUser == null) {
            throw new ServiceException("该GitLink用户不存在(GitLink用户名[" + currentUsername + "])");
        }
        zoneMember = zoneMemberApplyVo.toZoneMember();
        zoneMember.setZoneId(zoneId);
        if (StringUtils.isEmpty(zoneMember.getName())) {
            zoneMember.setName(gitlinkUser.getString("name"));
        }
        if (StringUtils.isEmpty(zoneMember.getImageUrl())) {
            String imagePath = gitlinkUser.getString("image_url");
            String imageUrl = EscapeUtil.removeExtraSlashOfUrl(String.format("%s/%s", gitLinkUrl, imagePath));
            zoneMember.setImageUrl(imageUrl);
        }
        zoneMember.setZoneId(zoneId);
        zoneMember.setIsAudit(ZoneConstants.MEMBER_NOT_AUDIT);
        zoneMember.setUserId(currentUserId);
        zoneMember.setDeptId(zoneDetail.getDeptId());
        zoneMember.setCreateTime(DateUtils.getNowDate());
        return zoneMemberMapper.insertZoneMember(zoneMember) > 0;
    }

    @Override
    public boolean auditZoneMember(Long memberId, AuditInputVo auditInputVo) {
        ZoneMember zoneMember = selectZoneMemberById(memberId);
        ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailById(zoneMember.getZoneId());
        switch (zoneMember.getIsAudit()) {
            case ZoneConstants.MEMBER_AUDIT_PASS:
                throw new ServiceException("该会员在专区中审核已通过(专区名称[" + zoneDetail.getName() + "]，会员Id[" + memberId + "])");
            case ZoneConstants.MEMBER_AUDIT_FAILED:
                throw new ServiceException("该会员在专区中审核已拒绝(专区名称[" + zoneDetail.getName() + "]，会员Id[" + memberId + "])");
            case ZoneConstants.MEMBER_AUDIT_INVITED:
                throw new ServiceException("正在邀请该会员加入专区，无法进行审核操作(专区名称[" + zoneDetail.getName() + "]，会员Id[" + memberId + "])");
            case ZoneConstants.MEMBER_NOT_AUDIT: {
                if (auditInputVo.getIsAudit()) {
                    if (auditInputVo.getMemberTypeId() == null || auditInputVo.getMemberLevelId() == null) {
                        throw new ServiceException("审核通过会员时，需设置会员的等级和类型(专区名称[" + zoneDetail.getName() + "]，会员Id[" + memberId + "])");
                    }
                    zoneMember.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
                    zoneMemberTypeService.selectZoneMemberTypeById(auditInputVo.getMemberTypeId());
                    zoneMember.setMemberTypeId(auditInputVo.getMemberTypeId());
                    zoneMemberLevelService.selectZoneMemberLevelById(auditInputVo.getMemberLevelId());
                    zoneMember.setMemberLevelId(auditInputVo.getMemberLevelId());
                    //设置排序值为当前最大的排序值+1
                    Integer maxSort = zoneMemberMapper.selectMaxSortByZoneId(zoneMember);
                    if (maxSort == null) {
                        maxSort = 1;
                    } else {
                        maxSort++;
                    }
                    zoneMember.setSort(maxSort);
                    createMemberUserIdentify(zoneDetail, zoneMember.getSysUser());
                } else {
                    if (zoneMember.getSysUser() == null || zoneMember.getSysUser().getGitlinkUserId() == null) {
                        throw new ServiceException("该会员非GitLink用户(专区名称[" + zoneDetail.getName() + "]，会员Id[" + memberId + "])");
                    }
                    if (StringUtils.isEmpty(auditInputVo.getReason())) {
                        throw new ServiceException("拒绝会员申请时需填写审批理由(专区名称[" + zoneDetail.getName() + "]，会员Id[" + memberId + "])");
                    }
                    if (auditInputVo.getReason().length() > 300) {
                        throw new ServiceException("拒绝原因长度不能超过300");
                    }
                    String userName = zoneMember.getSysUser().getUserName();
                    JSONObject gitlinkUser = gitLinkRequestHelper.doGet(ZoneGitLinkRequestUrl.USER(userName));
                    if (gitlinkUser == null) {
                        throw new ServiceException("该GitLink用户不存在(GitLink用户名[" + userName + "])");
                    }
                    Map<String, String> params = new HashMap<>(3);
                    params.put("zoneName", zoneDetail.getName());
                    params.put("nickName", gitlinkUser.getString("name"));
                    params.put("reason", auditInputVo.getReason());
                    String template = zoneHomepagePath;
                    if (StringUtils.isNotEmpty(zoneDetail.getTemplate())) {
                        template = zoneDetail.getTemplate();
                    }
                    String toUrl = gitLinkUrl + "/" + template + "/" + zoneDetail.getKey();
                    params.put("to_url", EscapeUtil.removeExtraSlashOfUrl(toUrl));
                    params.put("baseurl", gitLinkUrl);
                    params.put("to_vip_url", EscapeUtil.removeExtraSlashOfUrl(toUrl + zoneMemberPath));
                    sendInvitationMailMessage(memberMessageTemplate, String.valueOf(zoneMember.getSysUser().getGitlinkUserId()), params, zoneDetail);
                    zoneMember.setIsAudit(ZoneConstants.MEMBER_AUDIT_FAILED);
                }
                String remark = "";
                if (StringUtils.isNotEmpty(zoneMember.getRemark())) {
                    remark = zoneMember.getRemark();
                }
                if (StringUtils.isNotEmpty(auditInputVo.getReason())) {
                    remark += "【审批理由】：" + auditInputVo.getReason();
                }

                zoneMember.setRemark(remark);
                zoneMember.setAuditTime(DateUtils.getNowDate());
                return zoneMemberMapper.updateZoneMember(zoneMember) > 0;
            }
            default:
                throw new ServiceException("错误的审核状态(审核状态[" + zoneMember.getIsAudit() + "])");
        }
    }

    @Override
    public Integer selectZoneMemberListCount(ZoneMemberSearchVo zoneMemberSearchVo) {
        zoneMemberSearchVo.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
        return zoneMemberMapper.selectZoneMemberListCount(zoneMemberSearchVo);
    }

    @Override
    public int updateZoneMemberHomePageShow(Long id) {
        ZoneMember zoneMember = selectZoneMemberById(id);
        //检查项目原本是否首页展示，若原本未展示将设置为展示，若设置了首页最大展示数量此刻需判断是否已达到最大值
        if (ZoneConstants.TRUE.equals(zoneMember.getIsHomepage())) {
            return zoneMemberMapper.updateZoneMemberHomePageShow(id, ZoneConstants.FALSE);
        } else {
            ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailById(zoneMember.getZoneId());
            Long homepageMembershipSize = zoneDetail.getHomepageMembershipSize();
            if (homepageMembershipSize != null && homepageMembershipSize > 0) {
                ZoneMemberSearchVo zoneMemberSearchVo = new ZoneMemberSearchVo();
                zoneMemberSearchVo.setZoneId(zoneDetail.getId());
                zoneMemberSearchVo.setIsHomepage(ZoneConstants.TRUE);
                zoneMemberSearchVo.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
                List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo);
                if (zoneMemberList.size() >= homepageMembershipSize) {
                    throw new ServiceException("该专区首页最多展示" + homepageMembershipSize + "个会员(专区名称[" + zoneDetail.getName() + "])");
                }
            }
            return zoneMemberMapper.updateZoneMemberHomePageShow(id, ZoneConstants.TRUE);
        }
    }

    @Override
    public List<ZoneMemberOverviewVo> selectZoneMemberOverviewList(Long zoneId, ZoneMemberOpenSearchVo zoneMemberOpenSearchVo, boolean isOpen) {
        zoneDetailService.selectZoneDetailById(zoneId);
        List<ZoneMemberOverviewVo> zoneMemberOverviewVoList = new ArrayList<>();
        ZoneMemberType zoneMemberTypeSearch = new ZoneMemberType();
        ZoneMemberSearchVo zoneMemberSearch = new ZoneMemberSearchVo();
        zoneMemberTypeSearch.setZoneId(zoneId);
        List<ZoneMemberType> zoneMemberTypeList = zoneMemberTypeService.selectZoneMemberTypeList(zoneMemberTypeSearch);
        for (ZoneMemberType zoneMemberType : zoneMemberTypeList) {
            ZoneMemberOverviewVo zoneMemberOverviewVo = zoneMemberType.toZoneMemberOverviewVo();
            zoneMemberSearch.setMemberTypeId(zoneMemberType.getId());
            zoneMemberSearch.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
            zoneMemberSearch.setIsOpen(isOpen);
            if (StringUtils.isNotEmpty(zoneMemberOpenSearchVo.getIsHomepage())) {
                zoneMemberSearch.setIsHomepage(zoneMemberOpenSearchVo.getIsHomepage());
            }
            List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearch);
            if (zoneMemberList != null && !zoneMemberList.isEmpty()) {
                zoneMemberOverviewVo.setZoneMemberList(getZoneMemberDataVoListByZoneMember(zoneMemberList));
            }
            zoneMemberOverviewVoList.add(zoneMemberOverviewVo);
        }

        return zoneMemberOverviewVoList;
    }

    @Override
    public List<ZoneMemberDataVo> selectZoneMemberHomePageMemberList(Long zoneId, boolean isOpen) {
        zoneDetailService.selectZoneDetailById(zoneId);
        ZoneMemberSearchVo zoneMemberSearchVo = new ZoneMemberSearchVo();
        zoneMemberSearchVo.setZoneId(zoneId);
        zoneMemberSearchVo.setIsHomepage(ZoneConstants.TRUE);
        zoneMemberSearchVo.setIsOpen(isOpen);
        zoneMemberSearchVo.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
        List<ZoneMember> zoneMemberList = zoneMemberMapper.selectZoneMemberList(zoneMemberSearchVo);
        if (zoneMemberList == null || zoneMemberList.isEmpty()) {
            return new ArrayList<>();
        }

        return getZoneMemberDataVoListByZoneMember(zoneMemberList);
    }

    private List<ZoneMemberDataVo> getZoneMemberDataVoListByZoneMember(List<ZoneMember> zoneMemberList) {
        List<ZoneMemberDataVo> zoneMemberDataVoList = new ArrayList<>();
        for (ZoneMember zoneMember : zoneMemberList) {
            SysUser sysUser = FeignUtils.getReturnData(
                    remoteUserService.getSysUserByUserId(zoneMember.getUserId(), SecurityConstants.INNER)
            );
            if (sysUser != null) {
                ZoneMemberDataVo zoneMemberDataVo = zoneMember.toZoneMemberDataVo(sysUser.getUserName());
                zoneMemberDataVoList.add(zoneMemberDataVo);
            }
        }
        return zoneMemberDataVoList;
    }

    @Override
    public int initZoneMember(ZoneMemberInitVo zoneMemberInitVo) {
        ZoneDetail zoneDetail = zoneDetailService.selectZoneDetailById(zoneMemberInitVo.getZoneId());
        JSONObject gitlinkUser = gitLinkRequestHelper.doGet(ZoneGitLinkRequestUrl.USER(zoneMemberInitVo.getGitLinkUserName()));
        if (gitlinkUser == null) {
            return 0;
        }

        SysUser sysUser = FeignUtils.getReturnData(
                remoteUserService.getSysUserByGitLinkUserId(gitlinkUser.getLong("user_id"), SecurityConstants.INNER));
        if (sysUser == null) {
            sysUser = FeignUtils.getReturnData(
                    remoteUserService.createUserByGitLinkUserId(gitlinkUser.getLong("user_id"), SecurityConstants.INNER));
            if (sysUser == null) {
                return 0;
            }
        }

        ZoneMember zoneMember = zoneMemberInitVo.toZoneMember();
        zoneMember.setName(gitlinkUser.getString("name"));
        String imagePath = gitlinkUser.getString("image_url");
        String imageUrl = EscapeUtil.removeExtraSlashOfUrl(String.format("%s/%s", gitLinkUrl, imagePath));
        zoneMember.setImageUrl(imageUrl);
        zoneMember.setIsAudit(ZoneConstants.MEMBER_AUDIT_PASS);
        createMemberUserIdentify(zoneDetail, sysUser);
        zoneMember.setUserId(sysUser.getUserId());
        zoneMember.setDeptId(zoneDetail.getDeptId());
        zoneMember.setCreateTime(DateUtils.getNowDate());
        zoneMember.setIsHomepage(ZoneConstants.TRUE);
        return zoneMemberMapper.insertZoneMember(zoneMember);
    }

    @Override
    @DataScope(deptAlias = "zm")
    public GenericsTableDataInfo<ZoneMemberDetailVo> selectZoneMemberAuditList(ZoneMemberSearchVo zoneMemberSearchVo) {
        List<ZoneMember> zoneMemberList = zoneMemberMapper.selectAuditZoneMemberList(zoneMemberSearchVo);
        return PageUtils.toPage(zoneMemberList, this::toZoneMemberDetailVo);
    }

    @Override
    public String selectZoneMemberAuditStatus(Long zoneId) {
        Long currentUserId = SecurityUtils.getUserId();
        ZoneMember zoneMember = zoneMemberMapper.selectZoneMemberByZoneIdAndUserId(zoneId, currentUserId);
        String auditStatus = ZoneConstants.MEMBER_AUDIT_FAILED;
        if (zoneMember != null) {
            auditStatus = zoneMember.getIsAudit();
        }
        return auditStatus;
    }

    @Override
    public Integer selectZoneMemberAuditCount(ZoneMemberSearchVo zoneMemberSearchVo) {
        return zoneMemberMapper.selectAuditZoneMemberCount(zoneMemberSearchVo);
    }

    @Override
    public GenericsTableDataInfo<JSONObject> selectGitlinkUserListByDept(Long deptId, GitLinkUserSearchVo gitLinkUserSearchVo) {
        JSONObject result = gitLinkRequestHelper.doGet(
                GitLinkRequestUrl.USERS(gitLinkUserSearchVo.genQueryString())
        );
        List<JSONObject> list = result.getList("users", JSONObject.class);
        List<SysUserDeptRole> sysUserDeptRoleList = FeignUtils.getReturnData(
                remoteDeptService.getSysUserDeptRoleListByDeptId(deptId, SecurityConstants.INNER)
        );
        if (sysUserDeptRoleList != null && !sysUserDeptRoleList.isEmpty()) {
            for (JSONObject userObj : list) {
                if (userObj.containsKey("image_url")) {
                    String imagePath = userObj.getString("image_url");
                    String authorImageUrl = EscapeUtil.removeExtraSlashOfUrl(String.format("%s/%s", gitLinkUrl, imagePath));
                    userObj.put("image_url", authorImageUrl);
                }
                boolean isChoose = sysUserDeptRoleList.stream().anyMatch(x -> {
                    if (x.getSysUser() != null
                            && x.getSysUser().getGitlinkUserId() != null
                            && x.getSysUser().getGitlinkUserId().equals(userObj.getLong("user_id"))) {
                        return x.getSysRole() == null || !SystemRole.isVirtual(x.getSysRole().getRoleKey());
                    }
                    return false;
                });
                userObj.put("isChoose", isChoose);
            }
        }
        Long size = result.getLong("total_count");
        return PageUtils.toPage(list, size);
    }

    @Override
    public List<Long> checkUsersIsMemberInDept(Long deptId, Long[] userIds) {
        if (deptId == null || userIds == null || userIds.length == 0) {
            return new ArrayList<>();
        }
        return zoneMemberMapper.checkUsersIsMemberInDept(deptId, userIds);
    }

    @Override
    public List<Long> checkUserIsMemberInDepts(Long userId, Long[] deptIds) {
        if (userId == null || deptIds == null || deptIds.length == 0) {
            return new ArrayList<>();
        }
        return zoneMemberMapper.checkUserIsMemberInDepts(userId, deptIds);
    }
}
