package com.wecloud.im.biz.module.message.service.impl;

import lombok.extern.slf4j.Slf4j;

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

import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.google.common.collect.Maps;
import com.wecloud.can.core.enums.ApiCode;
import com.wecloud.can.core.util.ApiResult;
import com.wecloud.can.datasource.mybatisplus.service.impl.BaseServiceImpl;
import com.wecloud.im.biz.enums.ReadMsgStatusEnum;
import com.wecloud.im.biz.module.message.controller.param.ImMsgReceivedStatusUpdate;
import com.wecloud.im.biz.module.message.controller.param.MsgReadStatusUpdateParam;
import com.wecloud.im.biz.module.message.controller.param.UpdateMsgReadStatusByConversationParam;
import com.wecloud.im.biz.module.message.entity.ImApplication;
import com.wecloud.im.biz.module.message.entity.ImClient;
import com.wecloud.im.biz.module.message.entity.ImConversationMembers;
import com.wecloud.im.biz.module.message.entity.ImInbox;
import com.wecloud.im.biz.module.message.entity.ImMessage;
import com.wecloud.im.biz.module.message.entity.ImMessageOnlineSend;
import com.wecloud.im.biz.module.message.mapper.ImInboxMapper;
import com.wecloud.im.biz.module.message.service.ImApplicationService;
import com.wecloud.im.biz.module.message.service.ImClientService;
import com.wecloud.im.biz.module.message.service.ImConversationMembersService;
import com.wecloud.im.biz.module.message.service.ImInboxService;
import com.wecloud.im.biz.module.message.service.ImMessageService;
import com.wecloud.im.server.enums.MsgTypeEnum;
import com.wecloud.im.server.enums.WsResponseCmdEnum;
import com.wecloud.im.server.model.WsResponse;
import com.wecloud.im.server.sender.ChannelSender;

/**
 * 消息收件箱表 服务实现类
 *
 * @author wei
 * @since 2021-05-06
 */
@Slf4j
@Service
public class ImInboxServiceImpl extends BaseServiceImpl<ImInboxMapper, ImInbox> implements ImInboxService {

    @Autowired
    private ImInboxMapper imInboxMapper;
    @Autowired
    private ImClientService imClientService;

    @Autowired
    private ImMessageService imMessageService;

    @Autowired
    private ImConversationMembersService imConversationMembersService;
    @Autowired
    private ChannelSender channelSender;

    @Autowired
    private ImApplicationService imApplicationService;


//    @Transactional(rollbackFor = Exception.class)
//    @Override
//    public boolean saveImInbox(ImInbox imInbox) throws Exception {
//        return super.save(imInbox);
//    }
//
//    @Transactional(rollbackFor = Exception.class)
//    @Override
//    public boolean updateImInbox(ImInbox imInbox) throws Exception {
//        return super.updateById(imInbox);
//    }
//
//    @Transactional(rollbackFor = Exception.class)
//    @Override
//    public boolean deleteImInbox(Long id) throws Exception {
//        return super.removeById(id);
//    }
//
//    @Override
//    public ImInboxQueryVo getImInboxById(Long id) throws Exception {
//        return imInboxMapper.getImInboxById(id);
//    }
//
//    @Override
//    public Paging<ImInboxQueryVo> getImInboxPageList(ImInboxPageParam imInboxPageParam) throws Exception {
//        Page<ImInboxQueryVo> page = new PageInfo<>(imInboxPageParam, OrderItem.desc(getLambdaColumn(ImInbox::getCreateTime)));
//        IPage<ImInboxQueryVo> iPage = imInboxMapper.getImInboxPageList(page, imInboxPageParam);
//        return new Paging<ImInboxQueryVo>(iPage);
//    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateImMsgReceived(ImMsgReceivedStatusUpdate imMsgReceivedUpdate) {
        ImClient curentClient = imClientService.getCurrentClient();

        // 修改已接收状态
        Long aLong = imInboxMapper.updateImMsgReceivedByIds(curentClient.getId(), imMsgReceivedUpdate.getMsgIds());

        //  根据appKey查询appid
        ImApplication application = imApplicationService.getCacheById(curentClient.getFkAppid());

        // 内容
        HashMap<String, String> contentMap = new HashMap<>();
        contentMap.put("receiverId", curentClient.getClientId());
        // 推送给接收方
        sendMsgStatus(curentClient, MsgTypeEnum.CLIENT_RECEIVED_MSG, contentMap, imMsgReceivedUpdate.getMsgIds());

        // 是否同时修改为已读状态
        if (imMsgReceivedUpdate.getReadStatus()) {

            MsgReadStatusUpdateParam msgReadStatusUpdateParam = new MsgReadStatusUpdateParam();
            msgReadStatusUpdateParam.setMsgIds(imMsgReceivedUpdate.getMsgIds());
            this.updateImMsgRead(msgReadStatusUpdateParam);

        }
        return true;
    }

    /**
     * 统计未读消息数量
     *
     * @param clientId
     * @return
     */
    @Override
    public Integer countMyNotReadCount(Long clientId) {


        return imInboxMapper.countMyNotReadCount(clientId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean updateImMsgRead(MsgReadStatusUpdateParam msgReadStatusUpdateParam) {
        ImClient curentClient = imClientService.getCurrentClient();

        // 修改已读状态
        Long aLong = imInboxMapper.updateImMsgReadByIds(curentClient.getId(), msgReadStatusUpdateParam.getMsgIds());

        //  根据appKey查询appid
        ImApplication application = imApplicationService.getCacheById(curentClient.getFkAppid());

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

        return true;

    }

    @Override
    public Boolean updateMsgReadStatusByConversation(UpdateMsgReadStatusByConversationParam param) {
        ImClient currentClient = imClientService.getCurrentClient();
        // 获取该用户该会话所有未读消息 msgId 列表
        List<ImInbox> imInboxList = this.list(new QueryWrapper<ImInbox>().lambda()
                .eq(ImInbox::getFkConversationId, param.getConversationId())
                .eq(ImInbox::getReadMsgStatus, ReadMsgStatusEnum.UNREAD.getCode())
                .le(ImInbox::getFkMsgId, param.getMsgIdEnd())
                .eq(ImInbox::getReceiver, currentClient.getId()));
        if (CollectionUtils.isEmpty(imInboxList)) {
            return true;
        }
        List<Long> msgIds = imInboxList.stream().map(i -> i.getFkMsgId()).collect(Collectors.toList());

        // 修改已读状态
        imInboxMapper.updateImMsgReadByIds(currentClient.getId(), msgIds);

        // 内容
        HashMap<String, String> contentMap = Maps.newHashMap();
        contentMap.put("receiverId", currentClient.getClientId());
        sendMsgStatus(currentClient, MsgTypeEnum.CLIENT_READ_MSG, contentMap, msgIds);
        return true;
    }

    /**
     * 下发状态类型消息
     *
     * @param currentClient        当前客户端
     * @param msgTypeEnum         消息类型枚举
     * @param contentMap          消息content内容
     * @param msgIds              消息id集合
     */
    private void sendMsgStatus(ImClient currentClient, MsgTypeEnum msgTypeEnum, HashMap<String, String> contentMap, List<Long> msgIds) {
        // 遍历消息id集合
        for (Long msgId : msgIds) {
            // 查询该消息
            ImMessage imMessageDb = imMessageService.getById(msgId);
            if (imMessageDb == null) {
                log.info("查无消息内容： {}", msgId);
                continue;
            }
            // 根据会话id查询该会话所有成员
            List<ImConversationMembers> membersList = imConversationMembersService.list(
                    new QueryWrapper<ImConversationMembers>().lambda()
                            .eq(ImConversationMembers::getFkConversationId, imMessageDb.getFkConversationId())
                            .notIn(ImConversationMembers::getFkClientId, currentClient.getId())
            );

            // 遍历发送给该会话的每个成员
            for (ImConversationMembers conversationMember : membersList) {
                //  消息实体
                ImMessage imMessage = new ImMessage();
                imMessage.setId(msgId);
                imMessage.setMsgType(msgTypeEnum.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(conversationMember.getFkConversationId());

                // 封装响应的实体
                ImMessageOnlineSend imMessageOnlineSend = new ImMessageOnlineSend();
                BeanUtils.copyProperties(imMessage, imMessageOnlineSend);
                imMessageOnlineSend.setType(msgTypeEnum.getUriCode());
                imMessageOnlineSend.setMsgId(imMessage.getId());
                imMessageOnlineSend.setCreateTime(new Date());
                imMessageOnlineSend.setSender(currentClient.getClientId());
                imMessageOnlineSend.setContent(contentMap);
                imMessageOnlineSend.setConversationId(conversationMember.getFkConversationId());
                // 查询接收方
                ImClient imClientReceiver = imClientService.getOne(new QueryWrapper<ImClient>().lambda()
                        .eq(ImClient::getFkAppid, currentClient.getFkAppid())
                        .eq(ImClient::getId, conversationMember.getFkClientId()));
                if (imClientReceiver == null) {
                    continue;
                }
                //  向接收方推送
                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);
                channelSender.sendMsg(responseModel, imClientReceiver.getId());
            }
        }
    }

}
