package com.wecloud.im.thousandchat.service;

import io.geekidea.springbootplus.framework.common.api.ApiCode;
import io.geekidea.springbootplus.framework.common.api.ApiResult;
import io.geekidea.springbootplus.framework.common.service.impl.BaseServiceImpl;
import lombok.extern.slf4j.Slf4j;

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;

import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.wecloud.im.entity.ImClient;
import com.wecloud.im.entity.ImConversation;
import com.wecloud.im.entity.ImMessage;
import com.wecloud.im.entity.ImMessageOnlineSend;
import com.wecloud.im.service.ImClientService;
import com.wecloud.im.service.ImMessageService;
import com.wecloud.im.thousandchat.cache.ThousandChatCacheManager;
import com.wecloud.im.thousandchat.entity.ImMsgReadLastest;
import com.wecloud.im.thousandchat.mapper.ImMsgReadLastestMapper;
import com.wecloud.im.thousandchat.param.ConversationLastestReadMsg;
import com.wecloud.im.thousandchat.param.LastestReceivedMsg;
import com.wecloud.im.thousandchat.param.ThousandOffineMsgDto;
import com.wecloud.im.vo.ImMessageOfflineListVo;
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.SnowflakeUtil;

/**
 * 消息收件箱表 服务实现类
 *
 * @author wei
 * @since 2021-05-06
 */
@Slf4j
@Service
public class ThousandChatService extends BaseServiceImpl<ImMsgReadLastestMapper, ImMsgReadLastest> {

    @Autowired
    private ImClientService imClientService;

    @Autowired
    private ImMessageService imMessageService;

    @Autowired
    private ChannelSender channelSender;

    @Autowired
    private ImMsgReadLastestMapper imMsgReadLastestMapper;
    @Autowired
    private ThousandChatCacheManager thousandChatCacheManager;

    /**
     * 更新消息已接收，已接收的最新那条作为消息id
     * @param lastestReceivedMsg
     * @return
     */
    public ApiResult<Boolean> updateImMsgReceived(LastestReceivedMsg lastestReceivedMsg) {
        ImClient curentClient = imClientService.getCurrentClient();

        ImMessage lastestMsg = imMessageService.getById(lastestReceivedMsg.getLastestMsgId());

        if(lastestMsg == null) {
            return ApiResult.ok(false);
        }

        // 生成消息id
        long readLastestId = SnowflakeUtil.getId();
        ImMsgReadLastest lastest = new ImMsgReadLastest();
        lastest.setId(readLastestId);
        lastest.setFkAppid(curentClient.getFkAppid());
        lastest.setFkClientId(curentClient.getId());
        lastest.setFkConversationId(lastestMsg.getFkConversationId());
        lastest.setFkReceiveMsgId(lastestReceivedMsg.getLastestMsgId());
        if(BooleanUtils.isTrue(lastestReceivedMsg.getReadStatus())) {
            lastest.setFkReadMsgId(lastestReceivedMsg.getLastestMsgId());
        }

        // 修改已接收状态
        imMsgReadLastestMapper.upsertImMsgReceive(lastest);

        // 内容
        HashMap<String, String> contentMap = new HashMap<>();
        contentMap.put("receiverId", curentClient.getClientId());

        // 推送给接收方
        sendMsgStatus(curentClient, MsgTypeEnum.CLIENT_RECEIVED_MSG, contentMap, lastestMsg);

        return ApiResult.ok();
    }


    /**
     * 更新消息已读，读到最新的那条作为消息id
     * @param lastestMsgId 消息id
     * @return
     */
    public ApiResult<Boolean> updateImMsgRead(Long lastestMsgId) {
        ImClient curentClient = imClientService.getCurrentClient();

        ImMessage lastestMsg = imMessageService.getById(lastestMsgId);

        if(lastestMsg == null) {
            return ApiResult.ok(false);
        }

        // 生成消息id
        long readLastestId = SnowflakeUtil.getId();
        ImMsgReadLastest lastest = new ImMsgReadLastest();
        lastest.setId(readLastestId);
        lastest.setFkAppid(curentClient.getFkAppid());
        lastest.setFkClientId(curentClient.getId());
        lastest.setFkConversationId(lastestMsg.getFkConversationId());
        lastest.setFkReadMsgId(lastestMsgId);

        // 修改已读状态
        imMsgReadLastestMapper.upsertImMsgRead(lastest);

        // 内容
        HashMap<String, String> contentMap = new HashMap<>();
        contentMap.put("receiverId", curentClient.getClientId());
        sendMsgStatus(curentClient, MsgTypeEnum.CLIENT_READ_MSG, contentMap, lastestMsg);

        return ApiResult.ok();

    }

    public List<ImMessageOfflineListVo> findOfflineMsgs(List<ImConversation> thousandConversations) {
        if(CollectionUtils.isEmpty(thousandConversations)) {
            return new ArrayList<>();
        }

        ImClient curentClient = imClientService.getCurrentClient();

        List<ConversationLastestReadMsg> lastestReadMsgs = imMsgReadLastestMapper.findLastestReadMsgs(curentClient.getId());
        Map<Long, ConversationLastestReadMsg> conversationMsgMap = lastestReadMsgs.stream().collect(Collectors.toMap(ConversationLastestReadMsg::getConversationId, v->v,(a,b)->a));
        List<ConversationLastestReadMsg> allConversationOfLastestReadMsgs = new ArrayList<>();
        thousandConversations.forEach(conversation -> {
            ConversationLastestReadMsg conversationLastestReadMsg = conversationMsgMap.get(conversation.getId());
            if(conversationLastestReadMsg == null) {
                ConversationLastestReadMsg msg = new ConversationLastestReadMsg();
                msg.setLastestReadMsgId(0L);
                msg.setLastestReceiveMsgId(0L);
                msg.setConversationId(conversation.getId());
                allConversationOfLastestReadMsgs.add(msg);
            } else {
                allConversationOfLastestReadMsgs.add(conversationLastestReadMsg);
            }
        });

        List<ImMessageOfflineListVo> result = new ArrayList<>();
        if(CollectionUtils.isEmpty(allConversationOfLastestReadMsgs)) {
            return result;
        }
        List<ThousandOffineMsgDto> offlineMsgs = imMsgReadLastestMapper.findOfflineMsgs(allConversationOfLastestReadMsgs);
        if(CollectionUtils.isEmpty(offlineMsgs)) {
            return result;
        }
        Map<Long, List<ThousandOffineMsgDto>> longListMap = offlineMsgs.stream().collect(Collectors.groupingBy(ThousandOffineMsgDto::getConversationId));
        for (Map.Entry<Long, List<ThousandOffineMsgDto>> offlineMsg : longListMap.entrySet()) {
            ImMessageOfflineListVo msg = new ImMessageOfflineListVo();
            msg.setConversationId(offlineMsg.getKey());
            List<OfflineMsgDto> collect = offlineMsg.getValue().stream().map(p -> (OfflineMsgDto) p).collect(Collectors.toList());
            msg.setMsgList(collect);
            result.add(msg);
        }
        return result;
    }

    /**
     * 下发状态类型消息
     *
     * @param curentClient        当前客户端
     * @param contentMap          消息content内容
     * @param lastestMsg          最新一条待处理消息
     */
    private void sendMsgStatus(ImClient curentClient, MsgTypeEnum msgTypeEnum, HashMap<String, String> contentMap, ImMessage lastestMsg) {

        Map<String /** ip **/, List<String /** client的主键ID:platform **/>> onlineIpClientMap =
                thousandChatCacheManager.findOnlineHostsByThousandGroupId(lastestMsg.getFkConversationId());

        // 封装响应的实体
        ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();
        imMessageOnlineSend.setMsgId(lastestMsg.getId());
        imMessageOnlineSend.setType(msgTypeEnum.getUriCode());
        imMessageOnlineSend.setSender(curentClient.getClientId());
        imMessageOnlineSend.setContent(contentMap);
        imMessageOnlineSend.setConversationId(lastestMsg.getFkConversationId());
        imMessageOnlineSend.setCreateTime(new Date());
        imMessageOnlineSend.setWithdraw(false);
        imMessageOnlineSend.setEvent(true);
        imMessageOnlineSend.setSystemFlag(false);

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

        // 遍历发送给该会话的每个在线成员
        onlineIpClientMap.forEach((ip, clientIdAndPlatforms) -> {
            channelSender.batchSendMsg(responseModel, ip, clientIdAndPlatforms);
        });
    }

}
