package net.northking.cctp.common.sequence;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.HashMap;
import java.util.Map;

/**
 * 分布式序列服务<br>
 * 基于redis的自增技术，创建自增的序列。
 */
public class SequenceDistributedService implements SequenceService
{
  private static final Logger logger = LoggerFactory.getLogger(SequenceDistributedService.class);

  private RedisConnectionFactory factory;

  /**
   * 序列持久化服务
   */
  private SequenceStorage sequenceStorage;

  public SequenceDistributedService(RedisConnectionFactory factory, SequenceStorage sequenceStorage)
  {
    this.factory = factory;
    this.sequenceStorage = sequenceStorage;
  }

  private static final Map<String, String> SequenceMap = new HashMap<>();

  @Override
  public Long nextValue(String key)
  {
    RedisAtomicLong sequence = new RedisAtomicLong(key, factory);
    long value = sequence.incrementAndGet();
    SequenceMap.put(key, "");
    return value;
  }

  @Override
  public Long skipValue(String key, int increment)
  {
    RedisAtomicLong sequence = new RedisAtomicLong(key, factory);
    long value = sequence.addAndGet(increment);
    SequenceMap.put(key, "");
    return value;
  }

  /**
   * 服务停止前持久化序列的值
   */
  @PreDestroy
  public void destroy()
  {
    logger.warn("服务即将停止，开始持久化序列。");
    for (String key : SequenceMap.keySet())
    {
      RedisAtomicLong sequence = new RedisAtomicLong(key, factory);
      sequenceStorage.save(key, sequence.get());
    }
  }

  /**
   * 服务启动前加载持久化序列的值。<br>
   * 只有持久化序列的值 大于 已有序列值 才会被加载到redis中
   */
  @PostConstruct
  public void init()
  {
    logger.warn("服务即将启动，开始加载和校对序列。");
    Map<String, Long> map = sequenceStorage.findAll();

    for (Map.Entry<String, Long> entry : map.entrySet())
    {
      String key = entry.getKey();
      long value = entry.getValue();
      RedisAtomicLong sequence = new RedisAtomicLong(key, factory);
      long actualValue = sequence.get();
      if (actualValue < value)
      {// 如果 redis中的序列值小于持久化的数值，则更新redis中的序列值
        long currentValue = sequence.addAndGet(value - actualValue);
        logger.warn("redis中的序列key={} 的值小于持久化的数值，更新序列的值到 {}。", key, currentValue);
      }
    }

  }


}
