package com.keao.edu.auth.service.impl;


import com.keao.edu.auth.api.client.SysUserFeignService;
import com.keao.edu.auth.api.entity.SysUser;
import com.keao.edu.auth.service.SysMessageConfigService;
import com.keao.edu.auth.service.SysMessageService;
import com.keao.edu.common.dal.BaseDAO;
import com.keao.edu.common.dao.SysMessageDao;
import com.keao.edu.common.entity.Mapper;
import com.keao.edu.common.entity.SysMessage;
import com.keao.edu.common.entity.SysMessageConfig;
import com.keao.edu.common.enums.MessageSendMode;
import com.keao.edu.common.enums.MessageTypeEnum;
import com.keao.edu.common.enums.SendStatusEnum;
import com.keao.edu.common.exception.BizException;
import com.keao.edu.common.redis.service.RedisCache;
import com.keao.edu.common.service.impl.BaseServiceImpl;
import com.keao.edu.im.api.client.ImFeignService;
import com.keao.edu.im.api.entity.ImPrivateMessage;
import com.keao.edu.im.api.entity.ImTxtMessage;
import com.keao.edu.thirdparty.message.MessageSenderPluginContext;
import com.keao.edu.thirdparty.message.MessageSenderPluginContext.MessageSender;
import com.keao.edu.util.string.MessageFormatter;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;

@Service
public class SysMessageServiceImpl extends BaseServiceImpl<Long, SysMessage> implements SysMessageService {

	private final static Logger LOGGER = LoggerFactory.getLogger(SysMessageServiceImpl.class);

	@Autowired
	private SysMessageDao sysMessageDao;

	@Autowired
	private SysMessageConfigService sysMessageConfigService;

	@Autowired
	private MessageSenderPluginContext messageSenderPluginContext;

	@Autowired
	private SysUserFeignService sysUserFeignService;

	@Autowired
	private ImFeignService imFeignService;

	@Autowired
	private RedisCache<String, Object> redisCache;

	// 验证码有效期
	public static final int CODE_EXPIRE = 60 * 5;

	// 发送验证码的间隔时间
	public static final int CODE_INTERVAL_TIME = 60;

	private final int DEFAULT_CODE = 888888;

	@Value("${message.debugMode}")
	private boolean debugMode;

	@Override
	public BaseDAO<Long, SysMessage> getDAO() {
		return sysMessageDao;
	}

	/**
	 * 添加消息
	 * @param subject 消息主题
	 * @param content 消息内容
	 * @param receivers 接收人，多个人用逗号分开
	 * @param triggerTime 触发时间
	 * @param mode 消息的发送模式
	 * @param status 消息的当前状态
	 * @param errorMsg 错误消息
	 * @param readStatus 阅读状态
	 * @param memo 备注
	 * @param group 消息组
	 * @return
	 */
	private int addMessage(Map<Integer, String> receivers, String subject, String content, Date triggerTime, MessageSendMode mode, SendStatusEnum status,
						   String errorMsg, Integer readStatus, String memo, String group) {
		SysMessage message = null;
		Date date = new Date();

		List<SysMessage> messages = new ArrayList<>();

		Integer userId = null;
		String receiver;
		for (Map.Entry<Integer, String> entry : receivers.entrySet()) {
			userId = entry.getKey();
			receiver = entry.getValue();

			message = new SysMessage();
			if (userId == null) {
				SysUser user = sysUserFeignService.queryUserByMobile(receiver);
				if (user != null) {
					userId = user.getId();
				}
			}
			message.setUserId(userId);
			message.setContent(content);
			message.setCreateOn(date);
			message.setModifyOn(date);
			message.setReceiver(receiver);
			if (triggerTime == null) {
				triggerTime = date;
			}
			message.setSendTime(triggerTime);
			message.setTitle(subject);
			message.setStatus(status);
			message.setType(mode);
			message.setErrorMsg(errorMsg);
			message.setReadStatus(readStatus);
			message.setMemo(memo);
			message.setGroup(group);

			messages.add(message);
		}

		return sysMessageDao.batchInsert(messages);
	}

	@Override
	public int updateMessage(SysMessage message) {
		return sysMessageDao.update(message);
	}

	@Override
	public boolean batchSeoMessage(Set<Integer> userIds, MessageTypeEnum messageType, String memo, Object... args) {
		if (userIds == null || userIds.size() == 0) {
			throw new BizException("接收地址不能为空");
		}
		SysMessageConfig messageConfig = sysMessageConfigService.queryByType(messageType);
		if (messageConfig == null) {
			throw new BizException("消息类型错误");
		}else if(messageConfig.getSendFlag() == null || messageConfig.getSendFlag() == 0){
			return true;
		}
		Date date = new Date();
		SendStatusEnum status = SendStatusEnum.SUCCESSED;
		String content = MessageFormatter.arrayFormat(messageConfig.getContent(), args);
		SysMessage message = null;

		List<SysMessage> messages = new ArrayList<>();
		for (Integer userId : userIds) {
			message = new SysMessage();
			message.setUserId(userId);
			message.setContent(content);
			message.setCreateOn(date);
			message.setModifyOn(date);
			message.setReceiver(userId.toString());
			message.setSendTime(date);
			message.setStatus(status);
			message.setType(MessageSendMode.SEO);
			message.setTitle(messageConfig.getDescription());
			message.setReadStatus(0);
			message.setMemo(memo);
			message.setGroup(messageConfig.getGroup());
			messages.add(message);
		}
		sysMessageDao.batchInsert(messages);
		return true;
	}

	@Override
	public void batchSendImMessage(MessageTypeEnum type, String senderId,String extra, String[] targetIds, String url, Object... args) {
		SysMessageConfig messageConfig = sysMessageConfigService.queryByType(type);
		if (messageConfig == null) {
			throw new BizException("消息类型错误");
		}else if(messageConfig.getSendFlag() == null || messageConfig.getSendFlag() == 0){
			return;
		}
		String content = MessageFormatter.arrayFormat(messageConfig.getContent(), args);
		if(StringUtils.isNotEmpty(url)){
			content += url;
		}
		ImPrivateMessage privateMessage = new ImPrivateMessage();
		privateMessage.setObjectName("RC:TxtMsg");
		privateMessage.setTargetId(targetIds);
		privateMessage.setSenderId(senderId);
		privateMessage.setContent(new ImTxtMessage(content,extra));
		imFeignService.privateSend(privateMessage);
	}

	/*@Override
	public void batchSendImPlayMidiMessage(String senderId,String roomId, String content) {
		ImGroupMessage groupMessage = new ImGroupMessage();
		privateMessage.setObjectName("DY:PlayMidiMessage");
		groupMessage.setTargetId(roomId.split(","));
		groupMessage.setSenderId(senderId);
		groupMessage.setContent(new ImPlayMidiMessage(content,null));
		groupMessage.setType("DY:PlayMidiMessage");
		imFeignService.privateSendCustom(groupMessage);
	}*/

	@Override
	public void sendPrivateMessage(String studentId, String content) {
		SysUser sysUser = sysUserFeignService.queryUserInfo();
		if(sysUser == null){
			throw new BizException("用户信息获取失败");
		}
		ImPrivateMessage privateMessage = new ImPrivateMessage();
		privateMessage.setObjectName("RC:TxtMsg");
		privateMessage.setTargetId(studentId.split(","));
		privateMessage.setSenderId(sysUser.getId().toString());
		privateMessage.setContent(new ImTxtMessage(content,null));
		imFeignService.privateSend(privateMessage);
	}

	@Override
	public void sendNoAuthPrivateMessage(String sender, String receiver, String content) {
		ImPrivateMessage privateMessage = new ImPrivateMessage();
		privateMessage.setObjectName("RC:TxtMsg");
		privateMessage.setTargetId(receiver.split(","));
		privateMessage.setSenderId(sender);
		privateMessage.setContent(new ImTxtMessage(content,null));
		imFeignService.privateSend(privateMessage);
	}

	@Override
	@Async
	public boolean batchSendMessage(MessageSender messageSender, String subject, String content, Map<Integer, String> receivers, Date triggerTime,
									Integer readStatus, String memo, String group, String jpushType) {

		if (receivers == null || receivers.size() == 0) {
			throw new BizException("消息接收人不能为空");
		}
		if (StringUtils.isBlank(content)) {
			throw new BizException("消息内容不能为空");
		}
		String[] tos = receivers.values().toArray(new String[receivers.size()]);
		if (tos != null && tos.length > 0) {
			Date date = new Date();
			SendStatusEnum status = SendStatusEnum.WAIT;

			String errorMsg = null;
			try {
				// 立即发送
				if (triggerTime == null || date.after(triggerTime)) {
					status = SendStatusEnum.SENDING;
					if (debugMode == true || messageSenderPluginContext.batchSend(messageSender, subject, content, tos, memo,jpushType)) {
						status = SendStatusEnum.SUCCESSED;
					} else {
						status = SendStatusEnum.FAILED;
					}
				}
			} catch (Exception e) {
				status = SendStatusEnum.FAILED;
				errorMsg = e.getMessage();
				LOGGER.warn("消息发送失败", e);
			}
			MessageSendMode mode = MessageSendMode.SMS;
			if (messageSender.getSendMode().equals("PUSH")) {
				mode = MessageSendMode.PUSH;
			} else if (messageSender.getSendMode().equals("EMAIL")) {
				mode = MessageSendMode.EMAIL;
			}
			return addMessage(receivers, subject, content, triggerTime, mode, status, errorMsg, readStatus, memo, null) > 0;
		}

		return false;
	}

	@Override
	@Async
	public void batchSendMessage(MessageSender messageSender, MessageTypeEnum type, Map<Integer, String> receivers, Date triggerTime, Integer readStatus,
								 String url, String jpushType, Object... args) {

		if (receivers == null || receivers.size() == 0) {
			throw new BizException("接收地址不能为空");
		}
		String[] tos = receivers.values().toArray(new String[receivers.size()]);
		SysMessageConfig messageConfig = sysMessageConfigService.queryByType(type);
		if (messageConfig == null) {
			throw new BizException("消息类型错误");
		}else if(messageConfig.getSendFlag() == null || messageConfig.getSendFlag() == 0){
			return;
		}
		Date date = new Date();
		SendStatusEnum status = SendStatusEnum.WAIT;
		String errorMsg = null;
		// 立即发送
		if (triggerTime == null || date.after(triggerTime)) {
			status = SendStatusEnum.SENDING;
			try {
				if (debugMode == true
						|| messageSenderPluginContext.batchSend(messageSender, messageConfig.getDescription(),
								MessageFormatter.arrayFormat(messageConfig.getContent(), args), tos, url,jpushType)) {
					status = SendStatusEnum.SUCCESSED;
				} else {
					status = SendStatusEnum.FAILED;
				}
			} catch (Exception e) {
				status = SendStatusEnum.FAILED;
				errorMsg = e.getMessage();
				LOGGER.warn("消息发送失败", e);
			}
		}
		MessageSendMode mode = MessageSendMode.SMS;
		if (messageSender.getSendMode().equals("PUSH")) {
			mode = MessageSendMode.PUSH;
		} else if (messageSender.getSendMode().equals("EMAIL")) {
			mode = MessageSendMode.EMAIL;
		}
		addMessage(receivers, messageConfig.getDescription(), MessageFormatter.arrayFormat(messageConfig.getContent(), args), triggerTime, mode, status, errorMsg, readStatus,
				url, messageConfig.getGroup());
	}

	@Override
	@Async
	public void sendMessage(MessageSender messageSender, Integer userId, String title, String content, String receiver, Date triggerTime, Integer readStatus,
			String url, String group,String jpushType) {
		if (StringUtils.isBlank(receiver)) {
			throw new BizException("接收地址不能为空");
		}
		Date date = new Date();
		SendStatusEnum status = SendStatusEnum.WAIT;
		String errorMsg = null;
		// 立即发送
		if (triggerTime == null || date.after(triggerTime)) {
			status = SendStatusEnum.SENDING;
			try {
				if (debugMode == true || messageSenderPluginContext.send(messageSender, receiver, title, content, url,jpushType)) {
					status = SendStatusEnum.SUCCESSED;
				} else {
					status = SendStatusEnum.FAILED;
				}
			} catch (Exception e) {
				status = SendStatusEnum.FAILED;
				errorMsg = e.getMessage();
				LOGGER.warn("消息发送失败", e);
			}
		}
		MessageSendMode mode = MessageSendMode.SMS;
		if (messageSender.getSendMode().equals("PUSH")) {
			mode = MessageSendMode.PUSH;
		} else if (messageSender.getSendMode().equals("EMAIL")) {
			mode = MessageSendMode.EMAIL;
		}
		Map<Integer, String> receivers = new HashMap<Integer, String>();
		receivers.put(userId, receiver);
		addMessage(receivers, title, content, triggerTime, mode, status, errorMsg, readStatus, url, null);
	}

	@Override
	public boolean sendSecurityCode(MessageSender messageSender, Integer userId, MessageTypeEnum messageType, String receiver) {
		String key1 = getVerificationCode1CacheKey(messageType, receiver);
		if (redisCache.get(key1) != null) {
			throw new BizException("请勿频繁操作，获取验证码间隔时间为60秒");
		}

		String key = getVerificationCodeCacheKey(messageType, receiver);
		int code = DEFAULT_CODE;
		if (debugMode == false) {
			code = getRandomCode(messageType, receiver);
		}
		Map<Integer, String> receivers = new HashMap<>(1);
		receivers.put(userId, receiver);
		batchSendMessage(messageSender, messageType, receivers, null, 1, "","", code);
		redisCache.put(key, code + "", CODE_EXPIRE);
		redisCache.put(key1, code + "", CODE_INTERVAL_TIME);
		return true;
	}

	@Override
	public String getSendedVerificationCode(MessageTypeEnum type, String mobileNOOrEmailAddr) {
		if (debugMode == true) {
			return DEFAULT_CODE + "";
		}
		String key = getVerificationCodeCacheKey(type, mobileNOOrEmailAddr);
		Object object = redisCache.get(key);
		return object == null ? null : object.toString();
	}

	@Override
	public void delSendedVerificationCode(MessageTypeEnum type, String mobileNOOrEmailAddr) {
		String key = getVerificationCodeCacheKey(type, mobileNOOrEmailAddr);
		if (StringUtils.isNotBlank(key)) {
			redisCache.delete(key);
		}
	}

	@Override
	public Map<String, Integer> queryCountOfUnread(MessageSendMode type, Integer userId) {
		List<Mapper> mappers = sysMessageDao.queryCountOfUnread(type, userId);

		Map<String, Integer> map = new HashMap<String, Integer>();

		for (Mapper mapper : mappers) {
			map.put(mapper.getKey().toString(), Integer.parseInt(mapper.getValue().toString()));
		}

		return map;
	}

	public void setDebugMode(boolean debugMode) {
		this.debugMode = debugMode;
	}

	private int getRandomCode(MessageTypeEnum type, String mobileNo) {
		int min = 100000;
		int max = 999999;
		Random random = new Random();

		return random.nextInt(max) % (max - min + 1) + min;
	}

	private static String getVerificationCodeCacheKey(MessageTypeEnum type, String mobileNOOrEmailAddr) {
		return "verificationCode" + type.name() + mobileNOOrEmailAddr;
	}

	private static String getVerificationCode1CacheKey(MessageTypeEnum type, String mobileNOOrEmailAddr) {
		return "verificationCode" + mobileNOOrEmailAddr;
	}

	/**
	 *
	 * @param userId 用户id数组
	 * @param status 状态/1 已读,0未读
	 * @return 修改的条数
	 */
	@Override
	public int updateStatus(Integer userId, int status) {
		return sysMessageDao.updateStatus(userId, status);
	}

	@Override
	public int updateOneStatus(Long id, int status) {
		return sysMessageDao.updateOneStatus(id, status);
	}

	@Override
	public List<SysMessage> queryUserInRecentMinList(String mobile, int recentMin, MessageSendMode type) {
		return sysMessageDao.queryUserInRecentMinList(mobile, recentMin, type);
	}
}
