package com.wecloud.im.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.wecloud.im.entity.ImApplication;
import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.entity.ImConversationMembers;
import com.wecloud.im.entity.ImMessage;
import com.wecloud.im.entity.ImMessageOnlineSend;
import com.wecloud.im.enums.ChatTypeEnum;
import com.wecloud.im.enums.GroupRoleEnum;
import com.wecloud.im.enums.MutedEnum;
import com.wecloud.im.mapper.ImConversationMapper;
import com.wecloud.im.param.ImClientSimpleDto;
import com.wecloud.im.param.ListConversationMembersParam;
import com.wecloud.im.param.ImConversationPageParam;
import com.wecloud.im.param.ImConversationQueryParam;
import com.wecloud.im.param.ImConversationQueryVo;
import com.wecloud.im.param.MutedGroupParam;
import com.wecloud.im.param.SetAdminsParam;
import com.wecloud.im.param.TransferOwnerParam;
import com.wecloud.im.param.add.ImClientLeaveConversation;
import com.wecloud.im.param.add.ImClientToConversation;
import com.wecloud.im.param.add.ImConversationAttrUpdate;
import com.wecloud.im.param.add.ImConversationCreate;
import com.wecloud.im.param.add.ImConversationDisplayUpdate;
import com.wecloud.im.param.add.ImConversationNameUpdate;
import com.wecloud.im.service.ImApplicationService;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.service.ImConversationMembersService;
import com.wecloud.im.service.ImConversationService;
import com.wecloud.im.service.ImMessageService;
import com.wecloud.im.vo.ConversationVo;
import com.wecloud.im.vo.ImConversationCreateVo;
import com.wecloud.im.vo.ConversationMemberVo;
import com.wecloud.im.vo.OfflineMsgDto;
import com.wecloud.im.ws.enums.MsgTypeEnum;
import com.wecloud.im.ws.enums.WsResponseCmdEnum;
import com.wecloud.im.ws.model.WsResponse;
import com.wecloud.im.ws.sender.ChannelSender;
import com.wecloud.utils.JsonUtils;
import com.wecloud.utils.SnowflakeUtil;
import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.enums.BaseEnum;
import io.geekidea.springbootplus.framework.common.exception.BusinessException;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import io.geekidea.springbootplus.framework.core.pagination.PageInfo;
import io.geekidea.springbootplus.framework.core.pagination.Paging;
import io.geekidea.springbootplus.framework.shiro.jwt.JwtToken;
import io.geekidea.springbootplus.framework.shiro.util.JwtUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 会话表 服务实现类
 *
 * @author wei
 * @since 2021-05-07
 */
@Slf4j
@Service
@CacheConfig(cacheNames = "convstn")
public class ImConversationServiceImpl extends BaseServiceImpl<ImConversationMapper, ImConversation> implements ImConversationService {

    @Autowired
    private ChannelSender channelSender;

    @Autowired
    private ImConversationMapper imConversationMapper;

    @Autowired
    private ImConversationMembersService imConversationMembersService;

    @Autowired
    private ImConversationService imConversationService;

    @Autowired
    private ImClientService imClientService;

    @Autowired
    private ImApplicationService imApplicationService;

    @Autowired
    private ImMessageService imMessageService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveImConversation(ImConversation imConversation) {
        return super.save(imConversation);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<ImConversationCreateVo> createImConversation(ImConversationCreate imConversationCreate) {
        ImClient createClient = imClientService.getCurrentClient();
        if (CollectionUtils.isEmpty(imConversationCreate.getClientIds())) {
            log.info("未找到群成员信息");
            return ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, null);
        }
        if (BaseEnum.valueOf(ChatTypeEnum.class, imConversationCreate.getChatType()) == null) {
            log.info("会话类型不存在");
            return ApiResult.result(ApiCode.PARAMETER_EXCEPTION, null);
        }
        // 成员不存在,不能创建会话
        for (String clientId : imConversationCreate.getClientIds()) {
            ImClient imClient = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                    .select(ImClient::getId)
                    .eq(ImClient::getFkAppid, createClient.getFkAppid())
                    .eq(ImClient::getClientId, clientId));
            if (imClient == null) {
                log.info("成员不存在,不能创建会话 clientId:{}", clientId);
                return ApiResult.result(ApiCode.CLIENT_NOT_FOUNT, null);
            }
        }

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurrentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(curentJwtToken.getAppKey());

        // 该应用 是否允许创建重复单聊类型会话 0不允许 1允许
        if (imApplication.getRepeatSessionStatus() != null && imApplication.getRepeatSessionStatus() == 0) {
            // 判断是否已经存在单聊类型会话
            // size() == 1 为单聊不允许重复创建 两个用户如果已经创建过会话,不能重复创建会话
            if (imConversationCreate.getClientIds().size() == 1) {
                ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                        .eq(ImClient::getFkAppid, createClient.getFkAppid())
                        .eq(ImClient::getClientId, imConversationCreate.getClientIds().get(0)));

                // 如果存在重复单聊类型会话，则不会为空
                ImConversation repetitionConversationInfo = imConversationMapper.getRepetitionConversationSingle(createClient.getId(), client2.getId());
                if (repetitionConversationInfo != null) {
                    log.info("存在重复的单聊会话，返回已存在的单聊类型会话id: {}", repetitionConversationInfo.getId());
                    // 返回已存在的单聊类型会话id
                    ImConversationCreateVo imConversationCreateVo = new ImConversationCreateVo();
                    imConversationCreateVo.setId(repetitionConversationInfo.getId());
                    return ApiResult.ok(imConversationCreateVo);
                }
            }
        } else {
            //创建重复一对一会话时对比扩展字段  1是
            if (imApplication.getContrastExtendedFieldStatus() == 1) {

                // 被邀请client
                ImClient inviteClient = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                        .eq(ImClient::getFkAppid, createClient.getFkAppid())
                        .eq(ImClient::getClientId, imConversationCreate.getClientIds().get(0)));
                String asString = JsonUtils.encodeJson(imConversationCreate.getAttributes());
                log.info("RequestAttributes:" + asString);


                Long repetitionConversation = getRepetitionConversationAttributes(createClient.getId(), inviteClient.getId(), asString);

                // 存在重复会话
                if (repetitionConversation != null) {
                    log.info("出现Attributes重复");
                    ImConversationCreateVo imConversationCreateVo = new ImConversationCreateVo();
                    imConversationCreateVo.setId(repetitionConversation);
                    // 为重复
                    return ApiResult.ok(imConversationCreateVo);
                }
            }
        }

        // 会话id
        Long imConversationId = SnowflakeUtil.getId();

        // 创建者
        Long creator = createClient.getId();

        // 创建会话
        ImConversation imConversation = new ImConversation();
        imConversation.setId(imConversationId);
        imConversation.setCreateTime(new Date());
        imConversation.setLastMessage(null);
        imConversation.setFkAppid(createClient.getFkAppid());
        imConversation.setCreator(creator);
        imConversation.setMemberCount(imConversationCreate.getClientIds().size() + 1);
        imConversation.setChatType(imConversationCreate.getChatType());
        imConversation.setName(imConversationCreate.getName());
        imConversation.setSystemFlag(false);
        // 拓展数据
        String attributesStr = JsonUtils.encodeJson(imConversationCreate.getAttributes());

        imConversation.setAttributes(attributesStr);
        imConversationService.save(imConversation);

        // 将创建者自己添加到会话
        Long imConversationMembersId = SnowflakeUtil.getId();
        ImConversationMembers imConversationMembers = new ImConversationMembers();
        imConversationMembers.setId(imConversationMembersId);
        imConversationMembers.setCreateTime(new Date());
        imConversationMembers.setUpdateTime(new Date());
        imConversationMembers.setFkAppid(createClient.getFkAppid());
        imConversationMembers.setFkConversationId(imConversationId);
        imConversationMembers.setFkClientId(creator);
        imConversationMembers.setClientId(createClient.getClientId());
        imConversationMembers.setRole(GroupRoleEnum.OWNER.getCode());
        imConversationMembersService.save(imConversationMembers);

        // 将他人添加到会话
        for (String id : imConversationCreate.getClientIds()) {
            ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                    .eq(ImClient::getFkAppid, createClient.getFkAppid())
                    .eq(ImClient::getClientId, id));
            ImConversationMembers imConversationMembers2 = new ImConversationMembers();
            imConversationMembers2.setId(SnowflakeUtil.getId());
            imConversationMembers2.setCreateTime(new Date());
            imConversationMembers2.setUpdateTime(new Date());
            imConversationMembers2.setFkAppid(createClient.getFkAppid());
            imConversationMembers2.setFkConversationId(imConversationId);
            imConversationMembers2.setFkClientId(client2.getId());
            imConversationMembers2.setClientId(client2.getClientId());
            imConversationMembers2.setRole(GroupRoleEnum.NORMAL.getCode());
            imConversationMembersService.save(imConversationMembers2);
            if (imConversationCreate.getClientIds().size() > 1) {
                // 给被拉入群的成员下发事件消息 -- 单聊则不下发
                ImMessage imMessage = new ImMessage();
                Map<String, Object> content = Maps.newHashMap();
                content.put("operator", createClient.getClientId()); //操作的client ID
                content.put("passivityOperator", client2.getClientId()); //被操作的client ID
                imMessage.setContent(JsonUtils.encodeJson(content));

                //  保存消息至消息表
                imMessage.setId(SnowflakeUtil.getId());
                imMessage.setMsgType(MsgTypeEnum.CLIENT_JOIN_NEW_CONVERSATION.getUriCode());
                imMessage.setCreateTime(new Date());
                imMessage.setFkAppid(imApplication.getId());
                imMessage.setSender(createClient.getId());
                imMessage.setWithdraw(false);
                imMessage.setEvent(true);
                imMessage.setSystemFlag(false);
                imMessage.setSendStatus(2);
                imMessage.setFkConversationId(imConversation.getId());
                imMessageService.save(imMessage);
                sendEventMsgToMember(imApplication, client2.getId(), imMessage, createClient);
            }
        }
        ImConversationCreateVo imConversationCreateVo = new ImConversationCreateVo();
        imConversationCreateVo.setId(imConversationId);

        return ApiResult.ok(imConversationCreateVo);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> addClientToConversation(ImClientToConversation imClientToConversation) {

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurrentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(curentJwtToken.getAppKey());

        ImClient imClientSender = imClientService.getCurrentClient();

        // 查询该会话所有成员
        List<ImConversationMembers> membersList = imConversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())

                        .eq(ImConversationMembers::getFkConversationId, imClientToConversation.getConversationId())
                        .notIn(ImConversationMembers::getId, imClientSender.getId())
        );
        if (membersList.isEmpty()) {
            log.info("membersList为空,toConversationId:" + imClientToConversation.getConversationId());
            return ApiResult.fail();
        }

        int needAddCount = 0;

        // 将他人添加到会话
        for (String id : imClientToConversation.getClientIds()) {
            ImClient clientToConversation = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                    .eq(ImClient::getFkAppid, imApplication.getId())
                    .eq(ImClient::getClientId, id));
            if (clientToConversation == null) {
                return ApiResult.fail(ApiCode.CLIENT_NOT_FOUNT, null);
            }
            //   判断用户是否已经在该会话
            ImConversationMembers members = imConversationMembersService.getOne(new QueryWrapper<ImConversationMembers>().lambda()
                    .eq(ImConversationMembers::getFkAppid, imApplication.getId())
                    .eq(ImConversationMembers::getFkConversationId, imClientToConversation.getConversationId())
                    .eq(ImConversationMembers::getFkClientId, clientToConversation.getId())
            );

            // 已经在该会话 则跳过
            if (members != null) {
                continue;
            }

            Long imConversationMembersId2 = SnowflakeUtil.getId();
            ImConversationMembers imConversationMembers2 = new ImConversationMembers();
            imConversationMembers2.setUpdateTime(new Date());
            imConversationMembers2.setId(imConversationMembersId2);
            imConversationMembers2.setCreateTime(new Date());
            imConversationMembers2.setFkAppid(imApplication.getId());
            imConversationMembers2.setFkConversationId(imClientToConversation.getConversationId());
            imConversationMembers2.setFkClientId(clientToConversation.getId());
            imConversationMembers2.setClientId(clientToConversation.getClientId());
            imConversationMembers2.setMuted(MutedEnum.NO.getCode());
            imConversationMembers2.setRole(GroupRoleEnum.NORMAL.getCode());
            imConversationMembersService.save(imConversationMembers2);

            needAddCount++;

            // ws邀请事件通知给群内其他人 ----------


            // 生成消息id
            long messageId = SnowflakeUtil.getId();
            ImMessage imMessage = new ImMessage();

            Map<String, Object> content = new HashMap<>();
            content.put("operator", imClientSender.getClientId()); //操作的client ID
            content.put("passivityOperator", clientToConversation.getClientId()); //被操作的client ID
            imMessage.setContent(JsonUtils.encodeJson(content));

            //  保存消息至消息表
            imMessage.setId(messageId);
            imMessage.setMsgType(MsgTypeEnum.INVITE_CLIENT_JOIN_CONVERSATION.getUriCode());
            imMessage.setCreateTime(new Date());
            imMessage.setFkAppid(imApplication.getId());
            imMessage.setSender(imClientSender.getId());
            imMessage.setWithdraw(false);
            imMessage.setEvent(true);
            imMessage.setSystemFlag(false);
            imMessage.setSendStatus(2);
            imMessage.setFkConversationId(imClientToConversation.getConversationId());
            boolean save = imMessageService.save(imMessage);

            // 遍历发送给已在群内的成员
            for (ImConversationMembers conversationMember : membersList) {
                sendEventMsgToMember(imApplication, conversationMember.getFkClientId(), imMessage, imClientSender);
            }
            // 发送给刚被拉入群的成员
            sendEventMsgToMember(imApplication, clientToConversation.getId(), imMessage, imClientSender);
        }

        // 将群成员数量减
        imConversationMapper.addMemberCount(imApplication.getId(), imClientToConversation.getConversationId(), needAddCount);
        ImConversationQueryVo conversation = imConversationMapper.getImConversationById(imClientToConversation.getConversationId());
        if (conversation.getMemberCount() > 2000) {
            // 升级为万人群
            imConversationMapper.upgradeToThousandChat(imApplication.getId(), imClientToConversation.getConversationId());
        }

        return ApiResult.ok();

    }

    private void sendEventMsgToMember(ImApplication imApplication, Long conversationMemberClientId, ImMessage imMessage,
                                      ImClient clientSender) {
        // 查询接收方
        ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                .eq(ImClient::getFkAppid, imApplication.getId())
                .eq(ImClient::getId, conversationMemberClientId));
        if (imClientReceiver == null) {
            return;
        }
        // 封装响应的实体
        ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();

        imMessageOnlineSend.setMsgId(imMessage.getId());
        imMessageOnlineSend.setCreateTime(new Date());
        imMessageOnlineSend.setType(imMessage.getMsgType());
        imMessageOnlineSend.setSender(clientSender.getClientId());
        imMessageOnlineSend.setContent(JsonUtils.decodeJson2Map(imMessage.getContent()));
        imMessageOnlineSend.setConversationId(imMessage.getFkConversationId());
        imMessageOnlineSend.setWithdraw(Boolean.FALSE);
        imMessageOnlineSend.setEvent(Boolean.TRUE);

        //  向接收方推送
        WsResponse<ImMessageOnlineSend> responseModel = new WsResponse<>();
        responseModel.setCmd(WsResponseCmdEnum.CONVERSATION_EVENT_MSG.getCmdCode());
        ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
        responseModel.setCode(result.getCode());
        responseModel.setMsg(result.getMessage());
        responseModel.setData(imMessageOnlineSend);
        responseModel.setReqId(null);
        channelSender.sendMsg(responseModel, imClientReceiver.getId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> delClientToConversation(ImClientToConversation imClientToConversation) throws Exception {

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurrentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(curentJwtToken.getAppKey());

        ImClient imClientSender = imClientService.getCurrentClient();

        // 判断是否为群主
        ImConversationMembers conversationMember = imConversationMembersService.getOne(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkConversationId, imClientToConversation.getConversationId())
                        .eq(ImConversationMembers::getFkClientId, imClientSender.getId())
        );
        if (conversationMember == null || !GroupRoleEnum.OWNER.getCode().equals(conversationMember.getRole())) {
            return ApiResult.result(false);
        }
        // 查询该会话所有成员
        List<ImConversationMembers> membersList = imConversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())
                        .eq(ImConversationMembers::getFkConversationId, imClientToConversation.getConversationId())
                        .notIn(ImConversationMembers::getId, imClientSender.getId())
        );
        if (membersList.isEmpty()) {
            log.info("membersList为空,toConversationId:" + imClientToConversation.getConversationId());
            return ApiResult.fail();
        }

        int needAddCount = 0;

        // 将client从会话移除
        for (String clientId : imClientToConversation.getClientIds()) {
            ImClient client2 = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                    .eq(ImClient::getFkAppid, imApplication.getId())
                    .eq(ImClient::getClientId, clientId));

            //   判断用户是否已经在该会话
            ImConversationMembers members = imConversationMembersService.getOne(new QueryWrapper<ImConversationMembers>().lambda()
                    .eq(ImConversationMembers::getFkAppid, imApplication.getId())
                    .eq(ImConversationMembers::getFkConversationId, imClientToConversation.getConversationId())
                    .eq(ImConversationMembers::getFkClientId, client2.getId())
            );

            // 则跳过
            imConversationMembersService.deleteImConversationMembers(members.getId());

            // ws移除事件通知给群内其他人 ----------

            needAddCount--;


            // 生成消息id
            long messageId = SnowflakeUtil.getId();
            ImMessage imMessage = new ImMessage();

            Map<String, Object> content = new HashMap<>();
            content.put("operator", imClientSender.getClientId()); //操作的client ID
            content.put("passivityOperator", client2.getClientId()); //被操作的client ID
            imMessage.setContent(JsonUtils.encodeJson(content));

            //  保存消息至消息表
            imMessage.setId(messageId);
            imMessage.setMsgType(MsgTypeEnum.REMOVE_CLIENT_CONVERSATION.getUriCode());
            imMessage.setCreateTime(new Date());
            imMessage.setFkAppid(imApplication.getId());
            imMessage.setSender(imClientSender.getId());
            imMessage.setWithdraw(false);
            imMessage.setEvent(true);
            imMessage.setSystemFlag(false);
            imMessage.setSendStatus(2);
            imMessage.setFkConversationId(imClientToConversation.getConversationId());
            imMessageService.save(imMessage);

            // 遍历发送
            for (ImConversationMembers conversationMembers : membersList) {

                // 查询接收方
                ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                        .eq(ImClient::getFkAppid, imApplication.getId())
                        .eq(ImClient::getId, conversationMembers.getFkClientId()));
                if (imClientReceiver == null) {
                    continue;
                }

                // 封装响应的实体
                ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();

                imMessageOnlineSend.setMsgId(messageId);
                imMessageOnlineSend.setCreateTime(new Date());
                imMessageOnlineSend.setType(imMessage.getMsgType());
                imMessageOnlineSend.setSender(imClientSender.getClientId());
                imMessageOnlineSend.setContent(content);
                imMessageOnlineSend.setConversationId(conversationMembers.getFkConversationId());
                imMessageOnlineSend.setWithdraw(Boolean.FALSE);
                imMessageOnlineSend.setEvent(Boolean.TRUE);

                //  向接收方推送
                WsResponse<ImMessageOnlineSend> responseModel = new WsResponse<>();
                responseModel.setCmd(WsResponseCmdEnum.CONVERSATION_EVENT_MSG.getCmdCode());
                ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
                responseModel.setCode(result.getCode());
                responseModel.setMsg(result.getMessage());
                responseModel.setData(imMessageOnlineSend);
                responseModel.setReqId(null);
                channelSender.sendMsg(responseModel, imClientReceiver.getId());
            }
        }

        // 将群成员数量减
        imConversationMapper.addMemberCount(imApplication.getId(), imClientToConversation.getConversationId(), needAddCount);

        return ApiResult.ok();

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> leaveConversation(ImClientLeaveConversation imClientToConversation) throws Exception {
        ImClient currentClient = imClientService.getCurrentClient();

        ImConversation imConversation = imConversationService.getById(imClientToConversation.getConversationId());
        if (imConversation == null) {
            throw new BusinessException("查无会话消息");
        }

        // 查询该会话所有成员
        List<ImConversationMembers> membersList = imConversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkConversationId, imClientToConversation.getConversationId())
                        .orderByAsc(ImConversationMembers::getCreateTime)
                        .notIn(ImConversationMembers::getFkClientId, currentClient.getId())
        );

        if (membersList.isEmpty()) {
            log.info("membersList为空,toConversationId:" + imClientToConversation.getConversationId());
            throw new BusinessException("会话中查无群人员");
        }

        //   判断用户是否在该会话
        ImConversationMembers members = imConversationMembersService.getOne(new QueryWrapper<ImConversationMembers>().lambda()
                .eq(ImConversationMembers::getFkAppid, currentClient.getFkAppid())
                .eq(ImConversationMembers::getFkConversationId, imClientToConversation.getConversationId())
                .eq(ImConversationMembers::getFkClientId, currentClient.getId())
        );

        // 将client从会话移除
        boolean b = imConversationMembersService.deleteImConversationMembers(members.getId());
        if (!b) {
            throw new Exception("deleteImConversationMembers");
        }

        // 将群成员数量减1
        imConversationMapper.addMemberCount(currentClient.getFkAppid(), imClientToConversation.getConversationId(), -1);

        // ws 退出事件通知给群内其他人 ----------


        // 生成消息id
        long messageId = SnowflakeUtil.getId();
        ImMessage imMessage = new ImMessage();

        //  保存消息至消息表
        imMessage.setId(messageId);
        imMessage.setMsgType(MsgTypeEnum.LEAVE_CONVERSATION.getUriCode());
        imMessage.setCreateTime(new Date());
        imMessage.setFkAppid(currentClient.getFkAppid());
        imMessage.setSender(currentClient.getId());
        imMessage.setWithdraw(false);
        imMessage.setEvent(true);
        imMessage.setSystemFlag(false);
        imMessage.setSendStatus(2);
        imMessage.setFkConversationId(imClientToConversation.getConversationId());
        boolean save = imMessageService.save(imMessage);
        if (!save) {
            throw new Exception("deleteImConversationMembers");
        }

        // 遍历发送
        for (ImConversationMembers conversationMembers : membersList) {

            // 查询接收方
            ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                    .eq(ImClient::getFkAppid, currentClient.getFkAppid())
                    .eq(ImClient::getId, conversationMembers.getFkClientId()));
            if (imClientReceiver == null) {
                continue;
            }

            // 封装响应的实体
            ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();

            imMessageOnlineSend.setMsgId(messageId);
            imMessageOnlineSend.setCreateTime(new Date());
            imMessageOnlineSend.setType(MsgTypeEnum.LEAVE_CONVERSATION.getUriCode());
            imMessageOnlineSend.setSender(currentClient.getClientId());
            imMessageOnlineSend.setConversationId(conversationMembers.getFkConversationId());
            imMessageOnlineSend.setWithdraw(Boolean.FALSE);
            imMessageOnlineSend.setEvent(Boolean.TRUE);

            //  向接收方推送
            WsResponse<ImMessageOnlineSend> responseModel = new WsResponse<>();
            responseModel.setCmd(WsResponseCmdEnum.CONVERSATION_EVENT_MSG.getCmdCode());
            ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
            responseModel.setCode(result.getCode());
            responseModel.setMsg(result.getMessage());
            responseModel.setData(imMessageOnlineSend);
            responseModel.setReqId(null);
            channelSender.sendMsg(responseModel, imClientReceiver.getId());

        }
        // 群主退出 转移给下一个人
        if (GroupRoleEnum.OWNER.getCode().equals(members.getRole())) {
            ImConversationMembers conversationMember = membersList.get(0);
            conversationMember.setRole(GroupRoleEnum.OWNER.getCode());
            // 群主转移给下一个人
            imConversationMembersService.updateById(conversationMember);
        }
        return ApiResult.ok();
    }


    /**
     * 群主转让
     *
     * @param param
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean transferOwner(TransferOwnerParam param) {
        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurrentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(curentJwtToken.getAppKey());
        ImClient imClientSender = imClientService.getCurrentClient();

        // 判断操作人是否为群主
        ImConversationMembers currentMember = imConversationMembersService.getOne(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkConversationId, param.getConversationId())
                        .eq(ImConversationMembers::getFkClientId, imClientSender.getId())
        );
        if (currentMember == null || !GroupRoleEnum.OWNER.getCode().equals(currentMember.getRole())) {
            throw new BusinessException("非群主无权操作");
        }
        // 将自己设置为普通群成员
        currentMember.setRole(GroupRoleEnum.NORMAL.getCode());
        imConversationMembersService.updateById(currentMember);
        // 将入参成员设置为群主
        ImClient transferClient = imClientService.getCacheImClient(imApplication.getId(), param.getClientId());
        ImConversationMembers transferMember = imConversationMembersService.getOne(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkConversationId, param.getConversationId())
                        .eq(ImConversationMembers::getFkClientId, transferClient.getId())
        );
        transferMember.setRole(GroupRoleEnum.OWNER.getCode());
        imConversationMembersService.updateById(transferMember);
        return true;
    }

    /**
     * 设置管理员
     * @param param
     * @return
     */
    @Override
    public Boolean setAdmins(SetAdminsParam param) {
        ImClient currentClient = imClientService.getCurrentClient();
        // 判断操作人是否为群主
        ImConversationMembers currentMember = imConversationMembersService.getOne(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkConversationId, param.getConversationId())
                        .eq(ImConversationMembers::getFkClientId, currentClient.getId())
        );
        if (currentMember == null || !GroupRoleEnum.OWNER.getCode().equals(currentMember.getRole())) {
            throw new BusinessException("非群主无权操作");
        }
        List<ImClientSimpleDto> simpleClients = imClientService.getSimpleClients(currentClient.getFkAppid(), param.getClientIds());
        if (CollectionUtils.isEmpty(simpleClients)) {
            throw new BusinessException("未查询得到真实管理员信息");
        }
        List<Long> fkClientIds = simpleClients.stream()
                .filter(s -> !currentMember.getId().equals(s.getId()))
                .map(s -> s.getId()).collect(Collectors.toList());
        imConversationMembersService.setAdminsForConversation(param, fkClientIds);
        return true;
    }

    /**
     * 群禁言
     * @param param
     * @return
     */
    @Override
    public Boolean mutedGroup(MutedGroupParam param) {
        ImClient currentClient = imClientService.getCurrentClient();
        if (!imConversationService.isBelongToRole(currentClient.getClientId(), param.getConversationId(),
                Lists.newArrayList(GroupRoleEnum.OWNER.getCode(), GroupRoleEnum.ADMIN.getCode()))) {
            // 当前操作人不属于群主或管理人员
            throw new BusinessException("操作人既不是群主也不是群管理员，无权限操作");
        }
        ImConversation muteGroupParam = new ImConversation();
        muteGroupParam.setId(param.getConversationId());
        muteGroupParam.setUpdateTime(new Date());
        muteGroupParam.setMuted(param.getMutedType());
        imConversationMapper.updateById(muteGroupParam);
        deleteCacheImConversationById(param.getConversationId());
        return true;
    }

    @Override
    public Boolean mutedGroupMember(MutedGroupParam param) {
        ImClient currentClient = imClientService.getCurrentClient();
        if (!imConversationService.isBelongToRole(currentClient.getClientId(), param.getConversationId(),
                Lists.newArrayList(GroupRoleEnum.OWNER.getCode(), GroupRoleEnum.ADMIN.getCode()))) {
            // 当前操作人不属于群主或管理人员
            throw new BusinessException("操作人既不是群主也不是群管理员，无权限操作");
        }
        ListConversationMembersParam getMutedMemberParam = new ListConversationMembersParam();
        getMutedMemberParam.setConversationId(param.getConversationId());
        getMutedMemberParam.setClientIds(param.getClientIds());
        List<ConversationMemberVo> mutedMembers = imConversationMembersService.getImConversationMembersList(getMutedMemberParam);
        List<ImConversationMembers> mutedMemberList = Lists.newArrayList();
        for (ConversationMemberVo mutedMember : mutedMembers) {
            ImConversationMembers saveMutedMember = new ImConversationMembers();
            saveMutedMember.setId(mutedMember.getId());
            saveMutedMember.setUpdateTime(new Date());
            saveMutedMember.setMuted(param.getMutedType());
            mutedMemberList.add(saveMutedMember);
        }
        imConversationMembersService.updateBatchById(mutedMemberList);
        return true;
    }

    /**
     * 判断当前操作人是否为指定角色成员
     * @param currentClientId
     * @param conversationId
     * @return
     */
    @Override
    public Boolean isBelongToRole(String currentClientId, Long conversationId, List<Integer> roles) {
        // 获取 群主和群管理员列表
        ListConversationMembersParam getMemberParam = new ListConversationMembersParam();
        getMemberParam.setConversationId(conversationId);
        getMemberParam.setRoles(roles);
        List<ConversationMemberVo> members = imConversationMembersService.getImConversationMembersList(getMemberParam);
        if (CollectionUtils.isEmpty(members)) {
            return false;
        }
        for (ConversationMemberVo member : members) {
            if (currentClientId.equals(member.getClientId())) {
                return true;
            }
        }
        return false;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> saveOrUpdateName(ImConversationNameUpdate imConversationNameUpdate) throws Exception {

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurrentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(curentJwtToken.getAppKey());

        ImClient imClientSender = imClientService.getCurrentClient();

        ImConversation imConversationById = imConversationService.getById(imConversationNameUpdate.getConversationId());

        // 判断是否为群主
        if (imConversationById == null || !imConversationById.getCreator().equals(imClientSender.getId())) {
            return ApiResult.result(false);
        }

        // 查询该会话所有成员
        List<ImConversationMembers> membersList = imConversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkConversationId, imConversationNameUpdate.getConversationId())
                        .notIn(ImConversationMembers::getId, imClientSender.getId())
        );

        imConversationById.setName(imConversationNameUpdate.getName());
        boolean b = imConversationService.updateById(imConversationById);
        // 删除redis中该会话的缓存
        deleteCacheImConversationById(imConversationNameUpdate.getConversationId());

        if (b) {
            // 下发群名称变动事件


            // ws下发群属性变动事件

            // 内容
            HashMap<String, String> content = new HashMap<>();
            content.put("name", imConversationById.getName());

            // 遍历发送
            for (ImConversationMembers conversationMembers : membersList) {

                // 查询接收方
                ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                        .eq(ImClient::getFkAppid, imApplication.getId())
                        .eq(ImClient::getId, conversationMembers.getFkClientId()));
                if (imClientReceiver == null) {
                    continue;
                }

                // 封装响应的实体
                ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();

//                imMessageOnlineSend.setMsgId(null);
//                imMessageOnlineSend.setSender(imClientSender.getClientId());
                imMessageOnlineSend.setType(MsgTypeEnum.CONVERSATION_NAME_CHANGE.getUriCode());
                imMessageOnlineSend.setCreateTime(new Date());
                imMessageOnlineSend.setContent(content);
                imMessageOnlineSend.setConversationId(conversationMembers.getFkConversationId());
//                imMessageOnlineSend.setWithdraw(Boolean.FALSE);
                imMessageOnlineSend.setEvent(Boolean.TRUE);

                //  向接收方推送
                WsResponse<ImMessageOnlineSend> responseModel = new WsResponse<>();
                responseModel.setCmd(WsResponseCmdEnum.CONVERSATION_EVENT_MSG.getCmdCode());
                ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
                responseModel.setCode(result.getCode());
                responseModel.setMsg(result.getMessage());
                responseModel.setData(imMessageOnlineSend);
                responseModel.setReqId(null);
                channelSender.sendMsg(responseModel, imClientReceiver.getId());
            }

            return ApiResult.ok();

        } else {
            return ApiResult.fail();
        }


    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ApiResult<Boolean> saveOrUpdateAttr(ImConversationAttrUpdate imConversationAttrUpdate) throws Exception {

        // shiro线程中获取当前token
        JwtToken curentJwtToken = JwtUtil.getCurrentJwtToken();
        //  根据appKey查询application
        ImApplication imApplication = imApplicationService.getCacheAppByAppKey(curentJwtToken.getAppKey());

        ImClient imClientSender = imClientService.getCurrentClient();

        ImConversation imConversationById = imConversationService.getById(imConversationAttrUpdate.getConversationId());
//         判断是否为群主
//        if (imConversationById == null || !imConversationById.getCreator().equals(imClientSender.getId())) {
//            return ApiResult.result(false);
//        }

        // 查询该会话所有成员
        List<ImConversationMembers> membersList = imConversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, imApplication.getId())
                        .eq(ImConversationMembers::getFkConversationId, imConversationAttrUpdate.getConversationId())
                        .notIn(ImConversationMembers::getId, imClientSender.getId())
        );

        String attributes = JsonUtils.encodeJson(imConversationAttrUpdate.getAttributes());
        imConversationById.setAttributes(attributes);

        boolean b = imConversationService.updateById(imConversationById);

        // 删除redis中该会话的缓存
        deleteCacheImConversationById(imConversationAttrUpdate.getConversationId());

        if (b) {


            // ws下发拓展字段变动事件

            // 内容
            HashMap<String, String> content = new HashMap<>();
            content.put("attributes", imConversationById.getAttributes());


            // 遍历发送
            for (ImConversationMembers conversationMembers : membersList) {

                // 查询接收方
                ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                        .eq(ImClient::getFkAppid, imApplication.getId())
                        .eq(ImClient::getId, conversationMembers.getFkClientId()));
                if (imClientReceiver == null) {
                    continue;
                }

                // 封装响应的实体
                ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();

//                imMessageOnlineSend.setMsgId(null);
//                imMessageOnlineSend.setSender(imClientSender.getClientId());
                imMessageOnlineSend.setType(MsgTypeEnum.CONVERSATION_EXPAND_FIELD_CHANGE.getUriCode());
                imMessageOnlineSend.setContent(content);
                imMessageOnlineSend.setCreateTime(new Date());
                imMessageOnlineSend.setConversationId(conversationMembers.getFkConversationId());
//                imMessageOnlineSend.setWithdraw(Boolean.FALSE);
                imMessageOnlineSend.setEvent(Boolean.TRUE);

                //  向接收方推送
                WsResponse<ImMessageOnlineSend> responseModel = new WsResponse<>();
                responseModel.setCmd(WsResponseCmdEnum.CONVERSATION_EVENT_MSG.getCmdCode());
                ApiResult<Boolean> result = ApiResult.result(ApiCode.SUCCESS);
                responseModel.setCode(result.getCode());
                responseModel.setMsg(result.getMessage());
                responseModel.setData(imMessageOnlineSend);
                responseModel.setReqId(null);
                channelSender.sendMsg(responseModel, imClientReceiver.getId());

            }


            return ApiResult.ok();

        } else {
            return ApiResult.fail();
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateImConversation(ImConversation imConversation) throws Exception {
        return super.updateById(imConversation);
    }


    /**
     * 是否单向隐藏会话","云端聊天记录不删除;假设有A和B两个用户,A删会话,B还能发; 如果B发了消息,A这边要重新把会话显示出来,并能显示之前的聊天记录"
     *
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateDisplayConversation(ImConversationDisplayUpdate imConversationDisplayUpdate) {
        ImClient curentClient = imClientService.getCurrentClient();
        for (Long id : imConversationDisplayUpdate.getConversationIds()) {
            // 修改为删除隐藏状态
            boolean update = imConversationMembersService.update(new UpdateWrapper<ImConversationMembers>()
                    .set("display_status", imConversationDisplayUpdate.getDisplayStatus())
                    .eq("fk_client_id", curentClient.getId())
                    .eq("fk_conversation_id", id)
                    .eq("fk_appid", curentClient.getFkAppid())
            );
        }
        return true;
    }

    @Override
//    @Cacheable(key = "#p0")
    public ImConversationQueryVo getCacheImConversationById(Long id) {
        return imConversationMapper.getImConversationById(id);
    }

    @Override
    @CacheEvict(key = "#p0")
    public void deleteCacheImConversationById(Long id) {
    }

    @Override
    public Paging<ImConversationQueryVo> getImConversationPageList(ImConversationPageParam imConversationPageParam) throws Exception {
        Page<ImConversationQueryVo> page = new PageInfo<>(imConversationPageParam, OrderItem.desc(getLambdaColumn(ImConversation::getCreateTime)));
        IPage<ImConversationQueryVo> iPage = imConversationMapper.getImConversationPageList(page, imConversationPageParam);
        return new Paging<ImConversationQueryVo>(iPage);
    }

    @Override
    public List<ConversationVo> getMyImConversationListAndMsgCount() throws Exception {

        ImClient currentClient = imClientService.getCurrentClient();

        // 查询用户加入的所有会话 与每个会话的未读条数 成员
        List<ConversationVo> myImConversationListAndMsgCount = imConversationMapper.getMyImConversationListAndMsgCount(currentClient.getId(), null);

        // 返回的
        List<ConversationVo> myImConversationListAndMsgCountNew = new ArrayList<>();

        // 转换json格式
        for (ConversationVo myconversationlistvo : myImConversationListAndMsgCount) {
            HashMap attributess = JsonUtils.json2Map(myconversationlistvo.getAttribute());
            myconversationlistvo.setAttributes(attributess);

            // 查询会话的最后一条消息
            OfflineMsgDto lastMsg = imMessageService.getLastMsgByConversationId(myconversationlistvo.getId());
            myconversationlistvo.setLastMsg(lastMsg);

            myImConversationListAndMsgCountNew.add(myconversationlistvo);

        }
        return myImConversationListAndMsgCountNew;

    }

    @Override
    public ConversationVo infoImConversationAndMsgCount(ImConversationQueryParam param) throws Exception {
        ImClient client = imClientService.getCurrentClient();
        // 查询用户加入的所有会话 与每个会话的未读条数 成员
        List<ConversationVo> conversationList = imConversationMapper.getMyImConversationListAndMsgCount(client.getId(), param.getId());
        if (CollectionUtils.isEmpty(conversationList)) {
            return null;
        }
        ConversationVo conversationVo = conversationList.get(0);
        HashMap attributess = JsonUtils.json2Map(conversationVo.getAttribute());
        conversationVo.setAttributes(attributess);
        // 查询会话的最后一条消息
        OfflineMsgDto lastMsg = imMessageService.getLastMsgByConversationId(conversationVo.getId());
        conversationVo.setLastMsg(lastMsg);
        return conversationVo;
    }


    @Override
    public List<ImConversation> getMyImConversationList() throws Exception {
        ImClient client = imClientService.getCurrentClient();
        return imConversationMapper.getMyImConversationList(client.getId());
    }

    @Override
    public Long getRepetitionConversationAttributes(Long clientId1, Long clientId2, String attributes) {
        return imConversationMapper.getRepetitionConversationAttributes(clientId1, clientId2, attributes);
    }

}
