package com.ym.im.mq;

import com.ym.im.config.RabbitConfig;
import com.ym.im.entity.*;
import com.ym.im.entity.base.NettyConstant;
import com.ym.im.entity.enums.RoleEnum;
import com.ym.im.entity.model.IdModel;
import com.ym.im.handler.ChannelGroupHandler;
import com.ym.im.service.StaffService;
import com.ym.im.util.JsonUtils;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Set;

/**
 * @author: JJww
 * @Date:2019-05-30
 */
@Slf4j
@Component
public class Receiver {

    @Autowired
    private Queue queue;

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

    @Autowired
    private StaffService staffService;

    @Autowired
    private ChannelGroupHandler channelGroup;

    /**
     * 禁用用户 队列名称
     */
    public static final String USER_QUEUE_NAME = "disable.user";

    /**
     * 订单队列
     */
    public static final String ORDER_QUEUE_NAME = "push.order";

    @RabbitListener(queues = "#{delayQueue.name}")
    public void delayAckHandler(MsgBody msgBody) throws IOException {
        log.info("接收时间:" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "  消息内容：" + JsonUtils.obj2Json(msgBody));
        retry(msgBody);
    }


    @RabbitListener(queues = "#{staffOfflineQueue.name}")
    public void offlineHandler(StaffSocketInfo staffSocketInfo) {

        final Long staffId = staffSocketInfo.getStaffId();
        //移除用户列表
        redisTemplate.delete(NettyConstant.STAFF_USERIDS_KEY + staffId);
        //客服真离线后 才转发
        if (channelGroup.getMerchantStaff(staffId) == null) {
            final Set userIds = staffSocketInfo.getUserIds();
            log.info("客服离线队列: " + "ID: " + "UserIds:" + userIds);
            userIds.forEach(uid -> {
                Long userId = Long.valueOf(uid.toString());
                //用户在线才重新分配和转发
                if (channelGroup.USER_GROUP.get(userId) != null) {
                    final StaffSocketInfo idleStaff = staffService.getIdleStaff(staffSocketInfo.getMerchantId(), userId);
                    if (idleStaff != null) {
                        idleStaff.writeAndFlush(new MsgBody<>().setCode(MsgBody.DISTRIBUTION_STAFF).setData(new IdModel().setStaffId(staffId).setUserId(userId)));
                    }
                }
            });
        }
    }


    /**
     * 禁用用户后 关闭socket
     *
     * @param userId
     * @throws IOException
     */
    @RabbitListener(queues = USER_QUEUE_NAME)
    public void disableUserHandler(String userId) {

        final UserSocketInfo userSocketInfo = channelGroup.USER_GROUP.get(Long.valueOf(userId));
        if (userSocketInfo != null) {
            userSocketInfo.writeAndFlush(new MsgBody<>().setCode(MsgBody.LOGOUT));
            userSocketInfo.close();
            log.info("用户: " + userId + "被禁用");
        }
    }

    /**
     * 订单相关处理
     *
     * @param orderModel
     */
    @SneakyThrows
    @RabbitListener(queues = ORDER_QUEUE_NAME)
    public void orderHandler(String json) {
        final Stroke stroke = JsonUtils.json2Obj(json, Stroke.class);
        final Long mcId = stroke.getMcId();
        final Long userId = stroke.getUserId();
        final UserSocketInfo userSocketInfo = channelGroup.USER_GROUP.get(userId);
        if (userSocketInfo == null) {
            return;
        }
        final MsgBody<Stroke> orderInfo = new MsgBody<Stroke>().setCode(MsgBody.ORDER).setData(stroke);
        final StaffSocketInfo staffSocketInfo = channelGroup.getMerchantStaff(userSocketInfo.getStaffId(stroke.getMcId())) == null ? staffService.getIdleStaff(mcId, userId) : null;
        if (staffSocketInfo != null) {
            staffSocketInfo.writeAndFlush(orderInfo);
            log.info("客服订单: " + "给客服(" + staffSocketInfo.getStaffId() + ")发送订单:" + orderInfo.toString());
        }


//        /**
//         * 绑定客服不在线,给历史客服发送订单信息
//         */
//        final Long staffId = (Long) redisTemplate.opsForHash().get(NettyConstant.IM_USERS, userId);
//        if (staffId != null) {
//            log.info("客服订单: " + "尝试给历史客服(" + staffId + ")发送订单:" + orderInfo.toString());
//            staffSocketInfo = channelGroup.getMerchantStaff(staffId);
//            if (staffSocketInfo != null) {
//                staffSocketInfo.writeAndFlush(orderInfo);
//                log.info("客服订单: " + "给历史客服(" + staffId + ")发送订单:" + orderInfo.toString());
//            }
//        }
    }


    /**
     * 重发未回执的消息
     *
     * @param msgBody
     * @throws IOException
     */
    public void retry(MsgBody<ChatRecord> msgBody) throws IOException {

        final ChatRecord chatRecord = msgBody.getData();
        final Long userId = Long.valueOf(chatRecord.getUserId());
        final String recordId = String.valueOf(chatRecord.getId());

        if (msgBody != null && chatRecord.getRetryCount().intValue() < NettyConstant.RETRY_COUNT.intValue()) {

            UserSocketInfo userSocketInfo = channelGroup.USER_GROUP.get(userId);
            if (userSocketInfo == null) {
                return;
            }

            MsgBody<ChatRecord> msg = JsonUtils.json2Obj(String.valueOf(redisTemplate.opsForHash().get(NettyConstant.MSG_KEY + userId, recordId)), JsonUtils.getJavaType(MsgBody.class, ChatRecord.class));
            if (msg != null && msg.getCode().equals(MsgBody.HAVE_READ)) {
                redisTemplate.opsForHash().delete(NettyConstant.MSG_KEY + userId, recordId);
                return;
            }
            final Integer sendReceive = chatRecord.getSendReceive();
            switch (RoleEnum.get(sendReceive)) {

                case APP:
                    Long staffId = userSocketInfo.getStaffId(chatRecord.getMerchantId());
                    StaffSocketInfo staffSocketInfo = channelGroup.getMerchantStaff(staffId);
                    if (staffSocketInfo != null) {
                        staffSocketInfo.writeAndFlush(msgBody);
                    }
                    break;

                case merchant:
                    userSocketInfo.writeAndFlush(msgBody);
                    break;

                default:
            }
            //重发三次
            chatRecord.setRetryCount(chatRecord.getRetryCount() + 1);
            queue.delaysQueue(msgBody);

        } else {
            //移除失败消息
            redisTemplate.opsForHash().delete(NettyConstant.MSG_KEY + userId, recordId);
        }

    }

}