package cn.axzo.msg.center.notices.manager;

import cn.axzo.msg.center.dal.MNSMessageTemplateParamDao;
import cn.axzo.msg.center.domain.entity.MNSMessageTemplateParam;
import cn.axzo.msg.center.notices.common.utils.KeyUtils;
import cn.axzo.msg.center.notices.manager.api.MessageTemplateParamManager;
import cn.axzo.msg.center.notices.manager.api.dto.response.TemplateParamDto;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static cn.axzo.msg.center.notices.common.constans.CacheConstants.*;

/**
 * 消息模板参数 Manager
 *
 * @author zhaoyong
 * @see MessageTemplateParamManagerImpl
 * @since 2021-08-20 22:44
 */
@Slf4j
@Service("messageTemplateParamManager")
public class MessageTemplateParamManagerImpl implements MessageTemplateParamManager {

  @Resource
  private MNSMessageTemplateParamDao mnsMessageTemplateParamDao;

  @Resource(name = "stringRedisTemplate")
  private StringRedisTemplate stringRedisTemplate;

  @PostConstruct
  public void init() {
    List<MNSMessageTemplateParam> templateParams = mnsMessageTemplateParamDao.getAllMessageTemplateParams();

    if(CollectionUtils.isEmpty(templateParams)) {
      log.info("MessageTemplateParamManager.init message template params size is zero");
      return;
    }

    Map<String, List<TemplateParamDto>> templateParamIndex = templateParams.stream()
        .map(v -> build(v))
        .collect(Collectors.groupingBy(v -> getCacheKey(v.getTemplateNo())));

    templateParamIndex.forEach((k, v) -> {
      // 参数排序
      List<TemplateParamDto> sortedValue = v.stream().sorted(Comparator.comparing(o -> o.getParamOrder(),
              Comparator.comparingInt(o -> o))).collect(Collectors.toList());

      // 构建缓存
      buildCache(k, sortedValue);
    });

  }

  @Override
  public List<TemplateParamDto> getByCode(String templateCode) {
    // 获取缓存 key
    String cacheKey = getCacheKey(templateCode);

    // 从缓存中获取对象
    String value = stringRedisTemplate.opsForValue().get(cacheKey);

    // 不存在对象
    if(REDIS_NULL_VALUE.equals(value)){
      return null;
    }

    // 对象不为空
    List<TemplateParamDto> templateParamInCache = JSON.parseArray(value, TemplateParamDto.class);
    if(CollectionUtils.isNotEmpty(templateParamInCache)) {
      return templateParamInCache;
    }

    // 查询数据库信息
    List<MNSMessageTemplateParam> result = mnsMessageTemplateParamDao.getByTemplateNo(templateCode);
    if(result == null) {
      // 防止缓存恶意穿透
      stringRedisTemplate.opsForValue().set(cacheKey, REDIS_NULL_VALUE, NULL_VALUE_CACHE_SECONDS, TimeUnit.SECONDS);
      return null;
    }

    // 对象转换
    List<TemplateParamDto> paramDtos = result.stream().map(v -> build(v))
        .collect(Collectors.toList());

    // 构建缓存
    buildCache(cacheKey, paramDtos);

    return paramDtos;
  }

  /**
   * 获取分组 KEY
   * @param templateNo
   * @return
   */
  private String getCacheKey(String templateNo) {
    return KeyUtils.getKey(MNS, MESSAGE_TEMPLATE, PARAM, templateNo);
  }

  /**
   * 构建缓存
   * @param cacheKey
   * @param dtos
   */
  private void buildCache(String cacheKey, List<TemplateParamDto> dtos){
    stringRedisTemplate.opsForValue().set(cacheKey, JSON.toJSONString(dtos), TEMPLATE_PARAM_CACHE_SECONDS, TimeUnit.SECONDS);
  }

  /**
   * 构建参数
   * @param param
   * @return
   */
  private TemplateParamDto build(MNSMessageTemplateParam param){
    return TemplateParamDto.builder()
        .templateNo(param.getTemplateNo())
        .paramName(param.getParamName())
        .paramOrder(param.getParamOrder())
        .build();
  }

}
