package com.wecloud.im.service.impl;

import com.wecloud.im.core.common.exception.BusinessException;
import com.wecloud.im.core.shiro.util.SecurityUtils;
import lombok.AllArgsConstructor;

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

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
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.mapper.ImConversationMapper;
import com.wecloud.im.param.ListConversationMembersParam;
import com.wecloud.im.param.SetAdminsParam;
import com.wecloud.im.param.add.ServerImConversationCreate;
import com.wecloud.im.param.group.MutedMembersParam;
import com.wecloud.im.post.Couriers;
import com.wecloud.im.post.MessageBuilder;
import com.wecloud.im.sdk.enums.ChatTypeEnum;
import com.wecloud.im.sdk.enums.GroupRoleEnum;
import com.wecloud.im.sdk.enums.MutedEnum;
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.ImGroupService;
import com.wecloud.im.service.ImMessageService;
import com.wecloud.im.vo.ConversationMemberVo;
import com.wecloud.im.server.enums.MsgTypeEnum;
import com.wecloud.im.server.enums.WsResponseCmdEnum;
import com.wecloud.imserver.client.model.enums.DeviceTypeEnum;
import com.wecloud.im.core.util.JsonUtils;
import com.wecloud.im.core.util.SnowflakeUtil;

/**
 * 群服务
 * @Author luozh
 * @Date 2022年05月10日 15:23
 * @Version 1.0
 */
@AllArgsConstructor
@Service
public class ImGroupServiceImpl implements ImGroupService {

    /**
     * 投递员
     */
    private final Couriers couriers;

    /**
     * 应用服务
     */
    private final ImApplicationService applicationService;

    /**
     * 客户端服务
     */
    private final ImClientService clientService;

    /**
     * 会话服务
     */
    private final ImConversationService conversationService;

    /**
     * 会话成员服务
     */
    private final ImConversationMembersService conversationMembersService;

    /**
     * 会话mapper
     */
    private final ImConversationMapper imConversationMapper;

    /**
     * 消息服务
     */
    private final ImMessageService imMessageService;

    @Override
    public Long createGroup(String creatorClientId, String groupName, List<String> memberIds) {
        // 获取应用
        Long appId = SecurityUtils.getCurrentAppId();
        ImApplication application = applicationService.getCacheById(appId);

        // 获取创建人信息
        ImClient creator = clientService.getCacheImClient(appId, creatorClientId);
        if (creator == null) {
            throw new BusinessException("创建人不存在");
        }

        // 获取群成员信息
        List<ImClient> members =
                clientService.list(Wrappers.<ImClient>lambdaQuery().eq(ImClient::getFkAppid, appId).in(ImClient::getClientId, memberIds));
        if (members.isEmpty()) {
            throw new BusinessException("群成员列表为空");
        }

        ServerImConversationCreate serverImConversationCreate = new ServerImConversationCreate();
        serverImConversationCreate.setName(groupName);
        serverImConversationCreate.setApplication(application);
        serverImConversationCreate.setCreator(creator);
        serverImConversationCreate.setMembers(members);
        serverImConversationCreate.setChatType(ChatTypeEnum.NORMAL_GROUP);
        serverImConversationCreate.setPlatform(DeviceTypeEnum.IOS);

        ImConversation conversation =
                conversationService.serverCreateImConversation(serverImConversationCreate);

        return conversation.getId();
    }

    @Override
    public Boolean dismissGroup(String userId, String groupId) {
        // 获取应用
        Long appId = SecurityUtils.getCurrentAppId();
        ImApplication application = applicationService.getCacheById(appId);

        // 查询操作人
        ImClient operator = clientService.getCacheImClient(appId, userId);
        if (operator == null) {
            throw new BusinessException("操作人不存在");
        }
        // 查询会话
        ImConversation conversation =
                conversationService.getOne(Wrappers.<ImConversation>lambdaQuery().eq(ImConversation::getFkAppid,
                        appId).eq(ImConversation::getId, groupId));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }

        // 查询该会话所有成员
        List<ImConversationMembers> membersList = conversationMembersService.list(
                new QueryWrapper<ImConversationMembers>().lambda()
                        .eq(ImConversationMembers::getFkAppid, appId)
                        .eq(ImConversationMembers::getFkConversationId, conversation.getId())
        );
        if (membersList.isEmpty()) {
            throw new BusinessException("群聊成员列表为空");
        }
        // 删除所有成员
        conversationMembersService.deleteByConversationId(conversation.getId());

        // 保存事件消息

        Map<String, Object> content = new HashMap<>();
        content.put("operator", operator.getClientId());

        ImMessage imMessage = MessageBuilder.buildEventMessage(MsgTypeEnum.CONVERSATION_DISBAND, application,
                operator, conversation, JsonUtils.encodeJson(content));
        //  保存消息至消息表
        imMessageService.save(imMessage);
        conversationService.sendMsgToMembers(conversation, membersList, operator, imMessage, content);
        return true;

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Integer joinGroup(String inviterUserId, String groupId, List<String> memberClientIds) {
        Long appId = SecurityUtils.getCurrentAppId();

        ImClient inviter = clientService.getCacheImClient(appId, inviterUserId);

        ImApplication imApplication = applicationService.getCacheById(appId);
        // 查询会话
        ImConversation conversation =
                conversationService.getOne(Wrappers.<ImConversation>lambdaQuery().eq(ImConversation::getFkAppid,
                        appId).eq(ImConversation::getId, groupId));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }
        // 查询客户端信息
        List<ImClient> clientList = clientService.list(Wrappers.<ImClient>lambdaQuery().eq(ImClient::getFkAppid,
                appId).in(ImClient::getClientId, memberClientIds));

        List<ImConversationMembers> oldMembers =
                conversationMembersService.list(Wrappers.<ImConversationMembers>lambdaQuery()
                        .eq(ImConversationMembers::getFkConversationId, conversation.getId()));

        // 查找已经在群组里的客户端
        List<ImConversationMembers> existMemberList =
                conversationMembersService.list(Wrappers.<ImConversationMembers>lambdaQuery()
                        .eq(ImConversationMembers::getFkConversationId, conversation.getId())
                        .in(ImConversationMembers::getClientId, memberClientIds));
        if (!existMemberList.isEmpty()) {
            List<String> existMemberClientIds =
                    existMemberList.stream().map(ImConversationMembers::getClientId).collect(Collectors.toList());

            clientList = clientList.stream().filter(client -> !existMemberClientIds.contains(client.getClientId())).collect(Collectors.toList());
        }
        // 加入群聊
        // 将他人添加到会话
        List<ImConversationMembers> newMemberList = new ArrayList<>();
        for (ImClient client : clientList) {
            Date now = new Date();
            Long imConversationMembersId2 = SnowflakeUtil.getId();
            ImConversationMembers newMember = new ImConversationMembers();
            newMember.setUpdateTime(now);
            newMember.setId(imConversationMembersId2);
            newMember.setCreateTime(now);
            newMember.setFkAppid(imApplication.getId());
            newMember.setFkConversationId(conversation.getId());
            newMember.setFkClientId(client.getId());
            newMember.setClientId(client.getClientId());
            newMember.setMuted(MutedEnum.NO.getCode());
            newMember.setRole(GroupRoleEnum.NORMAL.getCode());
            newMemberList.add(newMember);

        }
        conversationMembersService.saveBatch(newMemberList);
        // 将群成员数量增加
        imConversationMapper.addMemberCount(imApplication.getId(), conversation.getId(), clientList.size());

        for (ImClient newMember : clientList) {
            // ws邀请事件通知给群内其他人 ----------
            // 生成消息id
            Map<String, Object> content = new HashMap<>();
            //操作的client ID
            content.put("operator", inviter.getClientId());
            //被操作的client ID
            content.put("passivityOperator", newMember.getClientId());
            ImMessage imMessage = MessageBuilder.buildEventMessage(MsgTypeEnum.INVITE_CLIENT_JOIN_CONVERSATION,
                    imApplication, inviter, conversation, JsonUtils.encodeJson(content));
            boolean save = imMessageService.save(imMessage);
            // 发送给在群内的成员
            conversationService.sendMsgToMembers(conversation, oldMembers, inviter, imMessage, content);
            // 发送给被邀请人
            couriers.deliver(imMessage, content, inviter, newMember, WsResponseCmdEnum.CONVERSATION_EVENT_MSG);
        }

        return clientList.size();
    }

    @Override
    public Integer leaveGroup(String operatorUserId, String groupId, List<String> memberClientIds) {
        Long appId = SecurityUtils.getCurrentAppId();

        ImClient operator = clientService.getCacheImClient(appId, operatorUserId);

        ImApplication imApplication = applicationService.getCacheById(appId);
        // 查询会话
        ImConversation conversation =
                conversationService.getOne(Wrappers.<ImConversation>lambdaQuery().eq(ImConversation::getFkAppid,
                        appId).eq(ImConversation::getId, groupId));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }

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

        // 查找在群组里的客户端
        List<ImConversationMembers> existMemberList =
                conversationMembersService.list(Wrappers.<ImConversationMembers>lambdaQuery()
                        .eq(ImConversationMembers::getFkConversationId, conversation.getId())
                        .in(ImConversationMembers::getClientId, memberClientIds));
        if (!existMemberList.isEmpty()) {
            List<Long> conversationMemberIds =
                    existMemberList.stream().map(ImConversationMembers::getId).collect(Collectors.toList());
            conversationMembersService.removeByIds(conversationMemberIds);
            // 将群成员数量减
            imConversationMapper.addMemberCount(imApplication.getId(), conversation.getId(), -existMemberList.size());
        }

        for (ImConversationMembers members : existMemberList) {
            // 操作的client ID
            Map<String, Object> content = new HashMap<>();
            if (members.getClientId().equals(operator.getClientId())) {
                content.put("operator", operator.getClientId());
                // 自己主动退出
                ImMessage imMessage = MessageBuilder.buildEventMessage(MsgTypeEnum.LEAVE_CONVERSATION, imApplication, operator, conversation, JsonUtils.encodeJson(content));
                imMessageService.save(imMessage);
                // 发送给在群内的成员
                conversationService.sendMsgToMembers(conversation, membersList, operator, imMessage, content);
            } else {
                content.put("operator", operator.getClientId());
                // 被操作的client ID
                content.put("passivityOperator", members.getClientId());
                ImMessage imMessage = MessageBuilder.buildEventMessage(MsgTypeEnum.REMOVE_CLIENT_CONVERSATION, imApplication, operator, conversation, JsonUtils.encodeJson(content));
                imMessageService.save(imMessage);
                // 发送给在群内的成员
                conversationService.sendMsgToMembers(conversation, membersList, operator, imMessage, content);
            }


        }

        return existMemberList.size();
    }

    @Override
    public List<String> listGroupMembers(String groupId) {
        Long appId = SecurityUtils.getCurrentAppId();
        // 获取会话
        ImConversation conversation =
                conversationService.getOne(Wrappers.<ImConversation>lambdaQuery()
                        .eq(ImConversation::getFkAppid, appId)
                        .eq(ImConversation::getId, groupId));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }
        // 获取群成员
        List<ImConversationMembers> membersList =
                conversationMembersService.list(Wrappers.<ImConversationMembers>lambdaQuery().eq(ImConversationMembers::getFkConversationId, groupId));

        return membersList.stream().map(ImConversationMembers::getClientId).collect(Collectors.toList());
    }

    @Override
    public Boolean mutedMembers(MutedMembersParam param) {
        Long appId = SecurityUtils.getCurrentAppId();
        ImConversation conversation =
                imConversationMapper.selectOne(Wrappers.<ImConversation>lambdaQuery().eq(ImConversation::getFkAppid,
                        appId).eq(ImConversation::getId, param.getGroupId()));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }
        ListConversationMembersParam getMutedMemberParam = new ListConversationMembersParam();
        getMutedMemberParam.setConversationId(conversation.getId());
        getMutedMemberParam.setClientIds(Arrays.asList(param.getUserIds().split(",")));
        List<ConversationMemberVo> mutedMembers = conversationMembersService.getImConversationMembersList(getMutedMemberParam);
        List<ImConversationMembers> mutedMemberList = Lists.newArrayList();
        for (ConversationMemberVo mutedMember : mutedMembers) {
            ImConversationMembers saveMutedMember = new ImConversationMembers();
            saveMutedMember.setId(mutedMember.getId());
            saveMutedMember.setUpdateTime(new Date());
            Integer mutedType = 1;
            if (param.getMuted()) {
                mutedType = 2;
            }
            saveMutedMember.setMuted(mutedType);
            mutedMemberList.add(saveMutedMember);
        }
        conversationMembersService.updateBatchById(mutedMemberList);
        return true;
    }

    @Override
    public Boolean groupOwnerTransfer(String groupId, String newGroupOwnerUserId) {
        Long appId = SecurityUtils.getCurrentAppId();

        ImApplication imApplication = applicationService.getCacheById(appId);
        ImConversation conversation = imConversationMapper.selectOne(Wrappers.<ImConversation>lambdaQuery().eq(ImConversation::getFkAppid,
                SecurityUtils.getCurrentAppId()).eq(ImConversation::getId, groupId));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }
        // 获取旧群主
        ImConversationMembers oldGroupOwner =
                conversationMembersService.getOne(Wrappers.<ImConversationMembers>lambdaQuery().eq(ImConversationMembers::getFkConversationId,
                        conversation.getId()).eq(ImConversationMembers::getRole, GroupRoleEnum.OWNER.getCode()));

        // 获取新群主
        ImConversationMembers newGroupOwner =
                conversationMembersService.getOne(Wrappers.<ImConversationMembers>lambdaQuery().eq(ImConversationMembers::getFkConversationId,
                        conversation.getId()).eq(ImConversationMembers::getClientId, newGroupOwnerUserId));
        if (newGroupOwner == null) {
            throw new BusinessException("新群主不在该群中");
        }
        ImClient newGroupOwnerClient = clientService.getById(newGroupOwner.getFkClientId());

        if (oldGroupOwner != null) {
            if (oldGroupOwner.getClientId().equals(newGroupOwner.getClientId())) {
                // 新旧群主一致
                return true;
            }
            oldGroupOwner.setRole(GroupRoleEnum.NORMAL.getCode());
            newGroupOwner.setRole(GroupRoleEnum.OWNER.getCode());
            conversationMembersService.updateById(oldGroupOwner);
            conversationMembersService.updateById(newGroupOwner);
        } else {
            newGroupOwner.setRole(GroupRoleEnum.OWNER.getCode());
            conversationMembersService.updateById(newGroupOwner);
        }

        // 操作的client ID
        Map<String, Object> content = new HashMap<>();
        content.put("operator", newGroupOwner.getClientId());
        ImMessage imMessage = MessageBuilder.buildEventMessage(MsgTypeEnum.CONVERSATION_NEW_CREATOR, imApplication, newGroupOwnerClient, conversation, JsonUtils.encodeJson(content));
        imMessageService.save(imMessage);
        // 发送给在群内的成员
        List<ImConversationMembers> existMemberList =
                conversationMembersService.list(Wrappers.<ImConversationMembers>lambdaQuery()
                        .eq(ImConversationMembers::getFkConversationId, conversation.getId()));
        conversationService.sendMsgToMembers(conversation, existMemberList, newGroupOwnerClient, imMessage, content);

        return true;
    }

    @Override
    public Boolean addGroupAdmin(String groupId, String adminUserIds) {
        // 获取到群信息
        ImConversation conversation = imConversationMapper.selectOne(Wrappers.<ImConversation>lambdaQuery().eq(ImConversation::getFkAppid,
                SecurityUtils.getCurrentAppId()).eq(ImConversation::getId, groupId));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }
        List<ImClient> clients = clientService.list(Wrappers.<ImClient>lambdaQuery().in(ImClient::getClientId,
                Arrays.asList(adminUserIds.split(","))).eq(ImClient::getFkAppid, SecurityUtils.getCurrentAppId()));

        SetAdminsParam param = new SetAdminsParam();
        param.setConversationId(conversation.getId());
        param.setOperateType(1);

        conversationMembersService.setAdminsForConversation(param, clients.stream().map(ImClient::getId).collect(Collectors.toList()));
        return true;
    }

    @Override
    public Boolean removeGroupAdmin(String groupId, String adminUserIds) {
        ImConversation conversation = imConversationMapper.selectOne(Wrappers.<ImConversation>lambdaQuery().eq(ImConversation::getFkAppid,
                SecurityUtils.getCurrentAppId()).eq(ImConversation::getId, groupId));
        if (conversation == null) {
            throw new BusinessException("群组不存在");
        }

        List<ImClient> clients = clientService.list(Wrappers.<ImClient>lambdaQuery().in(ImClient::getClientId,
                Arrays.asList(adminUserIds.split(","))).eq(ImClient::getFkAppid, SecurityUtils.getCurrentAppId()));

        SetAdminsParam param = new SetAdminsParam();
        param.setConversationId(conversation.getId());
        param.setOperateType(2);

        conversationMembersService.setAdminsForConversation(param, clients.stream().map(ImClient::getId).collect(Collectors.toList()));
        return true;
    }
}
