package com.yonge.cooleshow.biz.dal.service.impl;

import com.alibaba.fastjson.JSON;
import com.dayaedu.cbs.common.enums.EAppKey;
import com.dayaedu.cbs.common.enums.EClientType;
import com.dayaedu.cbs.common.enums.message.EMessageSendMode;
import com.dayaedu.cbs.common.enums.message.ESendStatus;
import com.dayaedu.cbs.openfeign.client.MessageFeignClientService;
import com.dayaedu.cbs.openfeign.wrapper.message.CbsMessageWrapper;
import com.microsvc.toolkit.common.response.paging.PageInfo;
import com.microsvc.toolkit.common.response.template.R;
import com.yonge.cooleshow.biz.dal.dao.SysMessageDao;
import com.yonge.cooleshow.biz.dal.dao.TeacherDao;
import com.yonge.cooleshow.biz.dal.dto.BasicUserInfo;
import com.yonge.cooleshow.biz.dal.dto.JumpUrlDto;
import com.yonge.cooleshow.biz.dal.dto.PageUtil;
import com.yonge.cooleshow.biz.dal.dto.search.SysMessageQueryInfo;
import com.yonge.cooleshow.biz.dal.entity.SysMessage;
import com.yonge.cooleshow.biz.dal.entity.SysMessageConfig;
import com.yonge.cooleshow.biz.dal.enums.ClientEnum;
import com.yonge.cooleshow.biz.dal.enums.MessageSendMode;
import com.yonge.cooleshow.biz.dal.enums.MessageTypeEnum;
import com.yonge.cooleshow.biz.dal.enums.SendStatusEnum;
import com.yonge.cooleshow.biz.dal.service.SysMessageConfigService;
import com.yonge.cooleshow.biz.dal.service.SysMessageService;
import com.yonge.cooleshow.biz.dal.wrapper.SysMessageWrapper;
import com.yonge.cooleshow.common.entity.Mapper;
import com.yonge.cooleshow.common.redis.service.RedisCache;
import com.yonge.toolset.base.exception.BizException;
import com.yonge.toolset.base.string.MessageFormatter;
import com.yonge.toolset.mybatis.dal.BaseDAO;
import com.yonge.toolset.mybatis.service.impl.BaseServiceImpl;
import com.yonge.toolset.thirdparty.message.MessageSenderPluginContext.MessageSender;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

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

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

	@Resource
	private SysMessageDao sysMessageDao;
	@Resource
	private TeacherDao teacherDao;
	@Resource
	private RedisCache<String, Object> redisCache;
	@Resource
	private MessageFeignClientService messageFeignClientService;
	@Resource
	private SysMessageConfigService sysMessageConfigService;
	// 验证码有效期
	public static final int CODE_EXPIRE = 60 * 10;
	// 发送验证码的间隔时间
	public static final int CODE_INTERVAL_TIME = 60;

	private final int DEFAULT_CODE = 666666;

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

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

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


	@Override
	public void batchSendMessage(MessageSender messageSender, MessageTypeEnum type, Map<Long, String> receivers, Date triggerTime, Integer readStatus,
								 String url,String jpushType, Object... args) {
		LOGGER.info("batchSendMessage type {}, receivers {} ", type, receivers);
		if (receivers == null || receivers.isEmpty()) {
			LOGGER.error("接收地址不能为空");
			return;
		}
		// 处理注册时没有用户ID
		if (receivers.containsKey(null)) {
			String phone = receivers.get(null);
			receivers.remove(null);
			if (StringUtils.isNotEmpty(phone)) {
				receivers.put(-1L, phone);
			}
		}
		List<CbsMessageWrapper.MessageParam> messageParams = new ArrayList<>();
		List<BasicUserInfo> basicUserInfo = teacherDao.findBasicUserInfo(receivers.keySet());
		Map<Long, String> userIdPhoneMap = basicUserInfo.stream().collect(Collectors.toMap(BasicUserInfo::getUserId, BasicUserInfo::getPhone));
		receivers.forEach((userId, value) -> {
			String phone = userIdPhoneMap.getOrDefault(userId, null);
			CbsMessageWrapper.MessageParam messageParam = new CbsMessageWrapper.MessageParam();
			messageParam.setUserId(userId);
			messageParam.setAppKey(EAppKey.KLX);
			messageParam.setClientType(getClientType(jpushType));
			messageParam.setClientId(messageParam.getClientType());
			messageParam.setType(type.getCode());
			messageParam.setUrl(url);
			Map<Long, String> params = new HashMap<>();
			params.put(userId, Optional.ofNullable(phone).orElse(value));
			messageParam.setReceivers(params);
			messageParam.setRealSend(!debugMode);
			if (args != null && args.length > 0) {
				String[] argsStr = new String[args.length];
				for (int i = 0; i < args.length; i++) {
					if (args[i] != null) {
						argsStr[i] = args[i].toString();
					} else {
						argsStr[i] = "";
					}
				}
				messageParam.setContentArgs(argsStr);
			}
			messageParams.add(messageParam);
		});
		messageFeignClientService.sysMessageBatchSendMessage(messageParams);
	}
	@Override
	public void batchSendMessage(MessageSender messageSender, MessageTypeEnum type, Map<Long, String> receivers,String[] urlArgs, Date triggerTime, Integer readStatus
			,String jpushType, Object... args) {
		LOGGER.info("batchSendMessage type {}, receivers {} ", type, receivers);
		if (receivers == null || receivers.isEmpty()) {
			LOGGER.error("接收地址不能为空");
			return;
		}
		// 处理注册时没有用户ID
		if (receivers.containsKey(null)) {
			String phone = receivers.get(null);
			receivers.remove(null);
			if (StringUtils.isNotEmpty(phone)) {
				receivers.put(-1L, phone);
			}
		}
		List<CbsMessageWrapper.MessageParam> messageParams = new ArrayList<>();
		List<BasicUserInfo> basicUserInfo = teacherDao.findBasicUserInfo(receivers.keySet());
		Map<Long, String> userIdPhoneMap = basicUserInfo.stream().collect(Collectors.toMap(BasicUserInfo::getUserId, BasicUserInfo::getPhone));
		receivers.forEach((userId, value) -> {
			String phone = userIdPhoneMap.getOrDefault(userId, null);
			CbsMessageWrapper.MessageParam messageParam = new CbsMessageWrapper.MessageParam();
			messageParam.setUserId(userId);
			messageParam.setAppKey(EAppKey.KLX);
			messageParam.setClientType(getClientType(jpushType));
			messageParam.setClientId(messageParam.getClientType());
			messageParam.setType(type.getCode());
			messageParam.setUrlArgs(urlArgs);
			Map<Long, String> params = new HashMap<>();
			params.put(userId, Optional.ofNullable(phone).orElse(value));
			messageParam.setReceivers(params);
			messageParam.setRealSend(!debugMode);
			if (args != null && args.length > 0) {
				String[] argsStr = new String[args.length];
				for (int i = 0; i < args.length; i++) {
					if (args[i] != null) {
						argsStr[i] = args[i].toString();
					} else {
						argsStr[i] = "";
					}
				}
				messageParam.setContentArgs(argsStr);
			}
			messageParams.add(messageParam);
		});
		messageFeignClientService.sysMessageBatchSendMessage(messageParams);
	}

	public EClientType getClientType(String jpushType){
		if(StringUtils.isEmpty(jpushType)){
			return null;
		}else if(jpushType.contains("STUDENT")){
			return EClientType.STUDENT;
		}else if(jpushType.contains("TEACHER")){
			return EClientType.TEACHER;
		}else {
			return EClientType.BACKEND;
		}
	}


	@Override
	public boolean sendSecurityCode(MessageSender messageSender, Long userId, MessageTypeEnum messageType, String receiver, ClientEnum platform) {
		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 && !authCode) {
			code = getRandomCode(messageType, receiver);
		}
		Map<Long, String> receivers = new HashMap<>(1);
		receivers.put(userId, receiver);
		batchSendMessage(messageSender, messageType, receivers, null, 1, "",
				platform ==null ? "STUDENT":platform.getCode(),platform ==null ? "":platform.getMsg(), code);
		redisCache.put(key, code + "", CODE_EXPIRE);
		redisCache.put(key1, code + "", CODE_INTERVAL_TIME);
		return true;
	}

	/**
	 * 发送验证码
	 *
	 * @param messageType 消息类型
	 * @param receiver    消息接受者
	 * @return true-发送成功  false-发送失败
	 */
	@Override
	public String sendSecurityCode(MessageTypeEnum messageType, String receiver) {

		// 生成验证码
		String code = String.valueOf(getRandomCode(messageType, receiver));

		// 验证码缓存Key
		String key = getVerificationCodeCacheKey(messageType, receiver);

		// 发送验证码缓存
		redisCache.put(key, code, CODE_EXPIRE);

		return code;
	}

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

	@Override
	public List<Mapper> queryCountOfUnread(MessageSendMode type, Long userId, String jpushType) {
		CbsMessageWrapper.SysMessageQuery query = new CbsMessageWrapper.SysMessageQuery();
		query.setUserId(userId);
		query.setClientType(getClientType(jpushType));
		query.setStatus(ESendStatus.SUCCESSED);
		query.setAppKey(EAppKey.KLX);
		query.setSendMode(type == null?null:type == MessageSendMode.SMS?EMessageSendMode.SMS:
				type == MessageSendMode.EMAIL?EMessageSendMode.EMAIL:
						type == MessageSendMode.PUSH?EMessageSendMode.PUSH:EMessageSendMode.SEO);
		query.setReadStatus(false);
		List<CbsMessageWrapper.MessageUnreadStat> messageUnreadStats = messageFeignClientService.messageUnreadStat(query).feignData();
		List<Mapper> result = new ArrayList<>();

		for (CbsMessageWrapper.MessageUnreadStat mapper : messageUnreadStats) {
			Mapper map = new Mapper();
			map.setKey(mapper.getGroup());
			map.setValue(mapper.getNumber());
			result.add(map);
		}
		return result;
	}

	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
	@Transactional(rollbackFor = Exception.class)
	public Boolean updateStatus(Long userId, int status,String jpushType,MessageTypeEnum messageType) {
		CbsMessageWrapper.MessageRead messageRead = new CbsMessageWrapper.MessageRead();
		messageRead.setUserId(userId);
		messageRead.setAppKey(EAppKey.KLX);
		messageRead.setClientType(getClientType(jpushType));
		return messageFeignClientService.batchSetRead(messageRead).feignData();
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public Boolean updateOneStatus(Long id, int status) {
		return messageFeignClientService.setRead(id).feignData();
	}

	@Override
	public List<CbsMessageWrapper.SysMessage> queryUserInRecentMinList(String mobile, int recentMin, MessageSendMode type) {
		CbsMessageWrapper.UserRecentMessageQuery query = new CbsMessageWrapper.UserRecentMessageQuery();
		query.setPhone(mobile);
		query.setRecentMin(recentMin);
		query.setSendMode(EMessageSendMode.SMS);
		query.setAppKey(EAppKey.KLX);
		return messageFeignClientService.userRecentMessageRecords(query).feignData();
	}

	@Override
	public String selectConfigUrl(String messageType,Object ...param) {
//		return selectConfigUrlJumpType(messageType,null,param);
		return null;
    }

	@Override
	public String selectConfigUrlJumpType(String messageType, String jumpType, Object... param) {
		SysMessageConfig sysMessageConfig = sysMessageConfigService.queryByType(messageType);
		if (sysMessageConfig == null) {
			throw new BizException("消息类型错误");
		}
		if(StringUtils.isEmpty(sysMessageConfig.getAction())) {
			return null;
		}
		if (sysMessageConfig.getAction().equals("sms")) {
			return sysMessageConfig.getActionUrl();
		} else if (sysMessageConfig.getAction().equals("h5")) {
			sysMessageConfig.setActionUrl(MessageFormatter.arrayFormat(sysMessageConfig.getActionUrl(), param));
		} else if (sysMessageConfig.getAction().equals("app")) {
			sysMessageConfig.setParams(MessageFormatter.arrayFormat(sysMessageConfig.getParams(), param));
		}
		JumpUrlDto jumpUrlDto = new JumpUrlDto();
		jumpUrlDto.setAction(sysMessageConfig.getAction());
		jumpUrlDto.setUrl(sysMessageConfig.getActionUrl());
		jumpUrlDto.setPageTag(sysMessageConfig.getPageTag());
		jumpUrlDto.setParams(sysMessageConfig.getParams());
		if (StringUtils.isNotBlank(jumpType) && ClientEnum.TENANT_STUDENT.getCode().equals(jumpType)) {
			jumpUrlDto.setClientType("TENANT");
		}
		return JSON.toJSONString(jumpUrlDto);
	}

	@Override
	public List<SysMessageWrapper.MessageUnreadStat> userMessageUnreadStat(SysMessageWrapper.SysMessageQuery param) {
		CbsMessageWrapper.SysMessageQuery query = new CbsMessageWrapper.SysMessageQuery();
		query.setUserId(param.getUserId());
		query.setClientType(getClientType(param.getClientType().getCode()));
		query.setStatus(ESendStatus.SUCCESSED);
		query.setAppKey(EAppKey.KLX);
		query.setSendMode(param.getType() == null?null:param.getType() == MessageSendMode.SMS?EMessageSendMode.SMS:
				param.getType() == MessageSendMode.EMAIL?EMessageSendMode.EMAIL:
						param.getType() == MessageSendMode.PUSH?EMessageSendMode.PUSH:EMessageSendMode.SEO);
		query.setReadStatus(false);
		List<CbsMessageWrapper.MessageUnreadStat> messageUnreadStats = messageFeignClientService.messageUnreadStat(query).feignData();
		List<SysMessageWrapper.MessageUnreadStat> result = new ArrayList<>();
		for (CbsMessageWrapper.MessageUnreadStat mapper : messageUnreadStats) {
			SysMessageWrapper.MessageUnreadStat stat = new SysMessageWrapper.MessageUnreadStat();
			stat.setGroup(mapper.getGroup());
			stat.setNumber(mapper.getNumber());
			result.add(stat);
		}
		return result;
	}

	@Override
	public com.yonge.toolset.base.page.PageInfo<SysMessage> queryListPage(SysMessageQueryInfo queryInfo) {
		CbsMessageWrapper.SysMessageQuery query = new CbsMessageWrapper.SysMessageQuery();
		query.setPage(queryInfo.getPage());
		query.setRows(queryInfo.getRows());
		query.setUserId(queryInfo.getUserId());
		query.setStatus(ESendStatus.SUCCESSED);
		query.setAppKey(EAppKey.KLX);
		query.setSendMode(queryInfo.getType() == null?null:queryInfo.getType() == 1? EMessageSendMode.SMS :
				queryInfo.getType() == 2?EMessageSendMode.EMAIL:
						queryInfo.getType() == 3?EMessageSendMode.PUSH:EMessageSendMode.SEO);
		query.setTitle(queryInfo.getTitle());
		query.setClientId(getClientType(queryInfo.getClientId()));
		query.setReadStatus(queryInfo.getReadStatus() == null?null:queryInfo.getReadStatus()==1);
		query.setGroup(queryInfo.getGroup());
		R<PageInfo<CbsMessageWrapper.SysMessage>> pageInfoR = messageFeignClientService.sysMessagePage(query);
		PageInfo<CbsMessageWrapper.SysMessage> pageInfo = pageInfoR.feignData();
		List<SysMessage> sysMessages = new ArrayList<>();
		if(CollectionUtils.isNotEmpty(pageInfo.getRows())){
			pageInfo.getRows().forEach(sysMessage -> {
				SysMessage message = new SysMessage();
				message.setId(sysMessage.getId());
				message.setTitle(sysMessage.getTitle());
				message.setContent(sysMessage.getContent());
				if(sysMessage.getSendMode() != null){
					message.setType(sysMessage.getSendMode() == EMessageSendMode.SMS?MessageSendMode.SMS:
							sysMessage.getSendMode() == EMessageSendMode.EMAIL?MessageSendMode.EMAIL:
									sysMessage.getSendMode() == EMessageSendMode.PUSH?MessageSendMode.PUSH:MessageSendMode.SEO);
				}
				if(sysMessage.getStatus() != null){
					message.setStatus(sysMessage.getStatus() == ESendStatus.FAILED?SendStatusEnum.FAILED:
							sysMessage.getStatus() == ESendStatus.SENDING?SendStatusEnum.SENDING:
									sysMessage.getStatus() == ESendStatus.SUCCESSED?SendStatusEnum.SUCCESSED:SendStatusEnum.WAIT);
				}
				message.setReceiver(sysMessage.getReceiver());
				message.setSendTime(sysMessage.getSendTime());
				message.setErrorMsg(sysMessage.getErrorMsg());
				message.setCreateOn(sysMessage.getCreateTime());
				message.setModifyOn(sysMessage.getUpdateTime());
				message.setUserId(sysMessage.getUserId());
				message.setMessageConfigId(sysMessage.getMessageConfigId());
				message.setSubType(sysMessage.getSubType());
				message.setMemo(sysMessage.getMemo());
				if (sysMessage.getReadStatus() != null){
					message.setReadStatus(sysMessage.getReadStatus()?1:0);
				}
				message.setGroup(sysMessage.getGroup());
				message.setClientId(sysMessage.getClientId().getCode());
				message.setImg(sysMessage.getIcon());
				sysMessages.add(message);
			});
		}
		return PageUtil.pageInfo(pageInfo,sysMessages);
	}
}
