package com.softwarebr.nunu.service.user.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.brframework.commondb.core.AbstractEntityService;
import com.brframework.commondb.core.CommonRepository;
import com.brframework.commonmq.annotation.MQConfig;
import com.brframework.commonmq.annotation.MQListener;
import com.brframework.commonweb.json.PageParam;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.softwarebr.nunu.dao.user.MessageDao;
import com.softwarebr.nunu.domain.SendMessage;
import com.softwarebr.nunu.entity.user.Message;
import com.softwarebr.nunu.globals.MQTopics;
import com.softwarebr.nunu.json.api.user.MessageReadLog;
import com.softwarebr.nunu.json.api.user.MessageResult;
import com.softwarebr.nunu.service.user.MessageService;
import com.softwarebr.nunu.service.user.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

/**
 * @date 2020/03/17 15:40:01
 * @author lilin
 */

@Slf4j
@Service
@MQConfig
public class MessageServiceImpl extends AbstractEntityService<Message, Long, Object> implements MessageService {

	private static final String KEY_MESSAGE = "USER_MESSAGE";
	@Autowired
	private MessageDao messageDao;
	@Autowired
	private StringRedisTemplate redisTemplate;

	@Override
	public CommonRepository<Long, Message> getRepository() {
		return messageDao;
	}


    public MessageService getProxy() {
        if (AopContext.currentProxy() instanceof MessageService) {
            return (MessageService) AopContext.currentProxy();
        } else {
            return this;
        }
    }

    /**
     * 发送消息
     *
     * @param topic
     * @param message JSONObject内容
     */
    @MQListener(topic = MQTopics.MEMBER_SEND_MESSAGE)
    public void sendMessageListener(String topic, String message) {
        SendMessage sendMessage = JSON.parseObject(message, SendMessage.class);
        getProxy().sendMessage(sendMessage.getMemberId(), sendMessage.getType(), sendMessage.getTitle(), sendMessage.getDescription(),
                messageMap(sendMessage.getTargetType(), sendMessage.getTargetId()));
    }

    @Override
    public String sendMessageJSON(Long memberId, Integer type, String title, String description, Integer targetType, String targetId){
        SendMessage sendMessage = new SendMessage();
        sendMessage.setMemberId(memberId);
        sendMessage.setType(type);
        sendMessage.setTitle(title);
        sendMessage.setDescription(description);
        sendMessage.setTargetType(targetType);
        sendMessage.setTargetId(targetId);
        return JSON.toJSONString(sendMessage);
    }

    @Override
	public List<Message> findByMemberId(Long memberId, Long id) {
		if (null != id) {
			return messageDao.findByMemberId(memberId, id);
		} else {
			return messageDao.findByMemberId(memberId);
		}
	}

	@Override
	public Page<Message> findPage(PageParam page, Long memberId){
		Pageable pageable = PageRequest.of(page.getPageIndex(), page.getPageSize(), new Sort(Sort.Direction.DESC, "createDate"));
		return messageDao.findByMemberId(memberId, pageable);
	}


	@Override
	@Transactional(rollbackFor = Exception.class)
	public void sendMessage(Long memberId, Integer type, String title, String description, Map<String, String> ext) {
		JSONObject json = new JSONObject();
		json.put("title", title);
		json.put("message", description);
		if (null !=ext) {
			for (String key : ext.keySet()) {
				json.put(key, ext.get(key));
			}
		}
		Message message = new Message();
		message.setCreateDate(LocalDateTime.now());
		message.setMemberId(memberId);
		message.setType(type);
		message.setContent(json.toJSONString());
		messageDao.save(message);
	}

	private Map<String, String> messageMap(Integer targetType, String targetId){
		Map<String, String> map = Maps.newHashMap();
		map.put("targetType", targetType.toString());
		map.put("targetId", targetId);
		return map;
	}

	@Override
	public int unreadCount(Long memberId) {
		Object object = redisTemplate.opsForHash().get(KEY_MESSAGE, memberId.toString());
		MessageReadLog messageReadLog = null;
		if (null != object) {
			messageReadLog = JSONObject.parseObject(object.toString(), MessageReadLog.class);
		}
		if (messageReadLog == null) {
			messageReadLog = new MessageReadLog();
		} else {
			List<Message> list = messageDao.findByCreateDateGreaterThanAndMemberIdIn(messageReadLog.getLastUnreadCountDate(), Lists.newArrayList(memberId, Long.parseLong("0")));
			for (Message message : list) {
				messageReadLog.getUnreadIds().put(message.getId().toString(), JSON.toJSONString(message));
			}
		}
		messageReadLog.setLastUnreadCountDate(LocalDateTime.now());
		redisTemplate.opsForHash().put(KEY_MESSAGE, memberId.toString(), JSON.toJSONString(messageReadLog));

		return messageReadLog.getUnreadIds().size();
	}

	@Override
	public void readMessage(Long memberId, Long messageId) {
		Object object = redisTemplate.opsForHash().get(KEY_MESSAGE, memberId.toString());
		MessageReadLog messageReadLog = null;
		if (null != object) {
			messageReadLog = JSONObject.parseObject(object.toString(), MessageReadLog.class);
		}

		if (messageReadLog == null) {
			unreadCount(memberId);
			object = redisTemplate.opsForHash().get(KEY_MESSAGE, memberId.toString());
			if (null != object) {
				messageReadLog = JSONObject.parseObject(object.toString(), MessageReadLog.class);
			}
		}

		messageReadLog.getUnreadIds().remove(messageId.toString());
		redisTemplate.opsForHash().put(KEY_MESSAGE, memberId.toString(), JSON.toJSONString(messageReadLog));
	}

	@Override
	public void handleUnreadMessage(List<MessageResult> list, Long memberId) {
		Object object = redisTemplate.opsForHash().get(KEY_MESSAGE, memberId.toString());
		MessageReadLog messageReadLog = null;
		if (null != object) {
			messageReadLog = JSONObject.parseObject(object.toString(), MessageReadLog.class);
		}

		if (messageReadLog == null) {
			unreadCount(memberId);
			object =  redisTemplate.opsForHash().get(KEY_MESSAGE, memberId.toString());
			if (null != object) {
				messageReadLog = JSONObject.parseObject(object.toString(), MessageReadLog.class);
			}
		}

		for (MessageResult m : list) {
			//已存在即表示消息已读
			if (!messageReadLog.getUnreadIds().containsKey(m.getId().toString())) {
				m.setRead(true);
			}
			messageReadLog.getUnreadIds().remove(m.getId().toString());
		}
		redisTemplate.opsForHash().put(KEY_MESSAGE, memberId.toString(), JSON.toJSONString(messageReadLog));
	}


	@Override
	public Message findTopByUserId(Long memberId) {
		return messageDao.findTopByMemberIdOrderByCreateDateDesc(memberId);
	}


}