package com.winsea.svc.common.mq;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.PatternTopic;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import java.util.concurrent.TimeUnit;

/**
 * 消息队列客户端
 * 
 * @author SunTianjun
 */
public class MessageQueueClient {

	@Autowired
	private RedisTemplate<String, String> redisTemplate;

	@Autowired
	private RedisMessageListenerContainer messageListenerContainer;

	/**
	 * 消息推送
	 */
	public <T> void push(String channel, T body) {
		redisTemplate.opsForList().leftPush(channel, serialize(body));
	}

	/**
	 * 消息拉取
	 * 
	 * @param channel 频道
	 * @param timeout 拉取超时时间
	 * @param unit    时间单位
	 * @param clazz   反序列化类型
	 * @return 拉取的消息内容
	 */
	public <T> T pop(String channel, long timeout, TimeUnit unit, Class<T> clazz) {
		return deserialize(redisTemplate.opsForList().rightPop(channel, timeout, unit), clazz);
	}

	/**
	 * 消息发布
	 */
	public <T> void publish(String channel, T body) {
		redisTemplate.convertAndSend(channel, serialize(body));
	}

	/**
	 * 消息订阅
	 * 
	 * @param pattern         订阅的频道（正则匹配）
	 * @param messageListener 消息监听器
	 * @param bodyClass       消息体类型
	 */
	public <T> void subscribe(String pattern, MessageListener<T> messageListener, Class<T> bodyClass) {
		messageListenerContainer.addMessageListener((message, p) -> messageListener
				.onMessage(deserialize(message.getBody(), bodyClass), new String(message.getChannel())),
				new PatternTopic(pattern));
	}

	/**
	 * 序列化
	 */
	private <T> String serialize(T body) {
		return JSONObject.toJSONString(body);
	}

	/**
	 * 反序列化
	 */
	private <T> T deserialize(String body, Class<T> clazz) {
		return JSONObject.parseObject(body, clazz);
	}

	/**
	 * 反序列化
	 */
	private <T> T deserialize(byte[] body, Class<T> clazz) {
		return JSONObject.parseObject(redisTemplate.getValueSerializer().deserialize(body).toString(), clazz);
	}
}
