package com.yonge.cooleshow.biz.dal.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yonge.cooleshow.auth.api.entity.SysUser;
import com.yonge.cooleshow.biz.dal.dao.ImGroupMemberAuditDao;
import com.yonge.cooleshow.biz.dal.entity.ImGroup;
import com.yonge.cooleshow.biz.dal.entity.ImGroupMember;
import com.yonge.cooleshow.biz.dal.entity.ImGroupMemberAudit;
import com.yonge.cooleshow.biz.dal.entity.SysConfig;
import com.yonge.cooleshow.biz.dal.enums.AuditStatusEnum;
import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
import com.yonge.cooleshow.biz.dal.enums.ImGroupMemberRoleType;
import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
import com.yonge.cooleshow.biz.dal.queryInfo.ImGroupMemberAuditQueryInfo;
import com.yonge.cooleshow.biz.dal.service.ImGroupMemberAuditService;
import com.yonge.cooleshow.biz.dal.service.ImGroupMemberService;
import com.yonge.cooleshow.biz.dal.service.ImGroupService;
import com.yonge.cooleshow.biz.dal.service.SysConfigService;
import com.yonge.cooleshow.biz.dal.service.SysUserService;
import com.yonge.cooleshow.biz.dal.vo.AuditUserInfo;
import com.yonge.cooleshow.common.constant.SysConfigConstant;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.payment.util.DistributedLock;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * (ImGroupMemberAudit)表服务实现类
 *
 * @author zx
 * @since 2022-03-22 17:18:51
 */
@Slf4j
@Service("imGroupMemberAuditService")
public class ImGroupMemberAuditServiceImpl extends ServiceImpl<ImGroupMemberAuditDao, ImGroupMemberAudit> implements ImGroupMemberAuditService {

    @Resource
    private ImGroupService imGroupService;
    @Resource
    private SysUserService sysUserService;
    @Resource
    private ImGroupMemberService imGroupMemberService;
    @Resource
    private SysMessageServiceImpl sysMessageService;

    @Autowired
    private RedissonClient redissonClient;

    @Autowired
    private SysConfigService sysConfigService;

    @Override
    public ImGroupMemberAuditDao getDao() {
        return this.baseMapper;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void apply(ImGroupMemberAudit imGroupMemberAudit, Boolean autoJoin) throws Exception {
        String groupId = imGroupMemberAudit.getGroupId();
        ImGroup imGroup = imGroupService.getById(groupId);
        if(Objects.isNull(imGroup)){
            throw new BizException("群组信息不存在");
        }
        //是否在群
        Map<String,Object> groupMemberParams = new HashMap<>(2);
        groupMemberParams.put("groupId",groupId);
        groupMemberParams.put("userId",imGroupMemberAudit.getUserId());
        groupMemberParams.put("roleType",imGroupMemberAudit.getRoleType().getCode());
        if(Objects.nonNull(imGroupMemberService.getDao().findOne(groupMemberParams))){
            throw new BizException("您已经在群聊中，请勿重复添加");
        }
        //是否有待审核的申请
        Map<String,Object> auditParams = new HashMap<>(3);
        auditParams.put("groupId",groupId);
        auditParams.put("userId",imGroupMemberAudit.getUserId());
        groupMemberParams.put("roleType",imGroupMemberAudit.getRoleType().getCode());
        auditParams.put("auditStatus",AuditStatusEnum.AUDITING.getCode());
        if(Objects.nonNull(baseMapper.findOne(auditParams))){
            throw new BizException("您有待审核的申请，请勿重复提交");
        }

        // 增加群成员校验锁，当群成员人数达到限制时，不允许再次加入
        String lockName = "klx:group_member_apply_lock:" + groupId;
        DistributedLock.of(redissonClient).runIfLockToFunction(lockName, (x)-> {

            // 统计群成员数量，大于等于群组最大人数时，不允许加入
            if (!verifyGroupMemberJoinLimit(groupId, 1)) {
                SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
                throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
            }

            try {
                Date date = new Date();
                //是否自动通过审核
                imGroupMemberAudit.setAuditStatus(imGroup.getAutoPassFlag() && autoJoin?AuditStatusEnum.OPEN:AuditStatusEnum.AUDITING);
                imGroupMemberAudit.setUpdateTime(date);
                imGroupMemberAudit.setCreateTime(date);
                baseMapper.insert(imGroupMemberAudit);
                if(imGroup.getAutoPassFlag() && Optional.ofNullable(autoJoin).orElse(false)){
                    //处理本地群成员
                    List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMember(imGroup.getId(),
                        imGroupMemberAudit.getUserId(), false,
                        imGroupMemberAudit.getRoleType());
                    //同步群成员数量
                    imGroupService.getDao().updateMemberNum(imGroup.getId());
                    //加入融云群
                    imGroupMemberService.join(groupMembers,groupId);
                } else {
                    Map<Long,String> receivers = new HashMap<>(1);
                    // 群创建人
                    SysUser user = sysUserService.findUserById(imGroup.getCreateBy());
                    // 申请人
                    SysUser auditUser = sysUserService.findUserById(imGroupMemberAudit.getUserId());

                    receivers.put(user.getId(), user.getPhone());
                    try {
                        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.STUDENT_JOIN_FANSGROUP,
                            receivers, null, 0, null, ClientEnum.TEACHER.getCode(), auditUser.getUsername(),imGroup.getName());
                    } catch (Exception e) {
                        log.warn("学生入群消息发送失败，{}",e.getMessage());
                    }
                }
            } catch (Exception e) {
                log.error("加入群组申请失败，{}", e.getMessage(), e);
                throw new BizException("加入群组申请失败");
            }
            return true;
        }, null, 10L);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void applyAudit(String auditIds, AuditStatusEnum auditStatus,String groupId) throws Exception {
        Optional.of(auditStatus).filter(e->e != AuditStatusEnum.AUDITING).orElseThrow(()->new BizException("操作失败：审核状态异常"));
        ImGroup imGroup = Optional.ofNullable(imGroupService.getById(groupId)).orElseThrow(() ->new BizException("群组信息不存在"));
        Optional.of(sysUserService.getUserId()).filter(imGroup.getCreateBy()::equals).orElseThrow(()->new BizException("操作失败：您没有审核权限"));

        // 增加群成员校验锁，当群成员人数达到限制时，不允许再次加入
        String lockName = "klx:group_member_audit_lock:" + groupId;
        DistributedLock.of(redissonClient).runIfLockToFunction(lockName, (x)-> {

            // 校验群成员加入限制
            String[] split = auditIds.split(",");
            if (AuditStatusEnum.OPEN.equals(auditStatus) && !verifyGroupMemberJoinLimit(groupId, split.length)) {
                SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
                throw new BizException("群成员人数上限为:" + config.getParamValue() + "人");
            }
            try {
                //修改审核状态
                baseMapper.batchUpdateAuditStatus(auditIds,auditStatus.getCode());
                if(auditStatus == AuditStatusEnum.OPEN){
                    List<ImGroupMemberAudit> imGroupMemberAudit = baseMapper.findByIds(auditIds);
                    Set<Long> userIds = imGroupMemberAudit.stream().map(ImGroupMemberAudit::getUserId).collect(Collectors.toSet());
                    List<ImGroupMember> groupMembers = imGroupMemberService.initGroupMembers(groupId,userIds, ImGroupMemberRoleType.STUDENT);
                    //同步群成员数量
                    imGroupService.getDao().updateMemberNum(imGroup.getId());
                    //加入融云群
                    imGroupMemberService.join(groupMembers,imGroup.getId());
                    sendMessage(auditIds);
                }
            } catch (Exception e) {
                log.error("加入群组审核失败，{}", e.getMessage(), e);
                throw new BizException("加入群组审核失败");
            }
            return true;
        }, null, 10L);

    }

    /**
     * 校验群成员加入限制
     * @param groupId 群组ID
     */
    private Boolean verifyGroupMemberJoinLimit(String groupId, int addNum) {
        // 统计群成员数量，大于等于群组最大人数时，不允许加入
        int memberCount = imGroupMemberService.countGroupMember(groupId);
        // 查询群成员人数限制
        SysConfig config = sysConfigService.findByParamName(SysConfigConstant.GROUP_MEMBER_LIMIT);
        if (Objects.nonNull(config) && Integer.parseInt(config.getParamValue()) > 0
            && (memberCount + addNum) > Integer.parseInt(config.getParamValue())) {
            return false;
        }
        return true;
    }

    /**
     * 发送通过消息
     *
     * @param auditIds
     */
    private void sendMessage(String auditIds) {
        List<AuditUserInfo> auditUserInfoList = baseMapper.selectAuditUserInfo(auditIds);
        if (CollectionUtils.isEmpty(auditUserInfoList)) {
            return;
        }
        auditUserInfoList.stream().forEach(this::sendMessage);
    }

    private void sendMessage(AuditUserInfo auditUserInfo){
        Map<Long,String> receivers = new HashMap<>(1);
        receivers.put(auditUserInfo.getAuditUserId(), auditUserInfo.getAuditUserPhone());
        try {
            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.FANSGROUP_APPLY_SUCCESS,
                    receivers, null, 0, null, ClientEnum.STUDENT.getCode(), auditUserInfo.getGroupUsername(),
                    auditUserInfo.getGroupName());
        } catch (Exception e) {
            log.warn("学生入群申请通过消息发送失败，{}",e.getMessage());
        }
    }

    @Override
    public List<ImGroupMemberAudit> queryAll(ImGroupMemberAuditQueryInfo queryInfo) {
        return baseMapper.queryAll(queryInfo);
    }
}

