package com.ym.im.service.impl;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.ym.im.entity.ChatRecord;
import com.ym.im.entity.MsgBody;
import com.ym.im.entity.base.ChannelAttributeKey;
import com.ym.im.entity.base.NettyConstant;
import com.ym.im.factory.SingleChatFactory;
import com.ym.im.mq.Queue;
import com.ym.im.service.ChatService;
import com.ym.im.service.MsgBodyService;
import com.ym.im.util.JsonUtils;
import com.ym.im.validation.group.MsgBodyGroup;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.socket.nio.NioSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import static com.ym.im.entity.MsgBody.CHECK_MSG;
import static com.ym.im.entity.MsgBody.SEND_MSG;

/**
 * @author 陈俊雄
 * @date 2019/5/29
 **/
@Slf4j
@Service
@Validated({MsgBodyGroup.class})
public class MsgBodyServiceImpl implements MsgBodyService {

    @Autowired
    private Queue queue;

    @Autowired
    private SingleChatFactory singleChatFactory;

    @Resource(name = "myRedisTemplate")
    private RedisTemplate redisTemplate;


    @Override
    public void msgBodyHandle(@NotNull ChannelHandlerContext ctx, @Valid MsgBody<ChatRecord> msgBody) throws JsonProcessingException {

        final ChatService chatService = singleChatFactory.getService(ctx.channel().attr(ChannelAttributeKey.ROLE_TYPE).get());

        switch (msgBody.getCode()) {

            case SEND_MSG:
                // 获取用户、客服Id
                final Long id = ctx.channel().attr(ChannelAttributeKey.ROLE_ID).get();
                // 先保存聊天消息
                chatService.save(id, msgBody);
                // 再发送回执
                ctx.channel().writeAndFlush(msgBody.setCode(CHECK_MSG)).addListener((ChannelFutureListener) future -> {
                    // 获取对应的channel
                    final NioSocketChannel channel = chatService.distribution(id, msgBody);
                    if (channel != null) {
                        // 最后发送聊天消息
                        chatService.send(channel, msgBody.setCode(SEND_MSG));
                    }
                });
                break;

            case CHECK_MSG:
                msgBody.setCode(MsgBody.HAVE_READ);//回执
                chatService.ack(msgBody);
                break;

            default:
                break;
        }

    }

    @Override
    public void sendAndAck(NioSocketChannel channel, MsgBody<ChatRecord> msgBody) throws JsonProcessingException {
        msgBody.setCode(SEND_MSG);
        // 先保存消息至Redis
        redisTemplate.opsForHash().put(NettyConstant.MSG_KEY + msgBody.getData().getUserId(), msgBody.getData().getId(), JsonUtils.obj2Json(msgBody));
        // 再默认以用户没有收到消息为前提，做循环、延迟通知
        queue.delaysQueue(msgBody);
        // 最后发送聊天信息
        channel.writeAndFlush(msgBody);
    }
}
