package com.ruoyi.common.utils;

import cn.hutool.core.date.DateUtil;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.spring.SpringUtils;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.support.atomic.RedisAtomicLong;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class IdUtils {


  private static final StringRedisTemplate redisTemplate = SpringUtils.getBean(StringRedisTemplate.class);

  private static final String DEFAULT_GROUP_NAME = "default";

  private static final String PREFIX = "id:";
  private static final String PREFIX_GLOBAL = "id:global:";

  private static LocalDate day;

  private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd");

  private static Map<String, RedisAtomicLong> map = new ConcurrentHashMap<>();

  private static Map<String, RedisAtomicLong> mapGlobal = new ConcurrentHashMap<>();


  public static Long nextId() {
    return nextId(DEFAULT_GROUP_NAME);
  }


  public static Long nextId(Class<?> groupName) {
    return nextId(groupName.getSimpleName());
  }

  /**
   * 获取自增id
   *
   * @param groupName
   * @return
   */
  public static Long nextId(String groupName) {
    RedisAtomicLong counter = mapGlobal.get(PREFIX_GLOBAL + groupName);
    if (counter == null) {
      counter = new RedisAtomicLong(PREFIX_GLOBAL + groupName, redisTemplate.getConnectionFactory());
      mapGlobal.put(PREFIX_GLOBAL + groupName, counter);
    }
    return counter.incrementAndGet();
  }

  public static boolean nextIdInit() {
    return nextIdInit(DEFAULT_GROUP_NAME);
  }

  public static boolean nextIdInit(Class<?> groupName) {
    return nextIdInit(groupName.getSimpleName());
  }

  /**
   * 是否已经初始化了吗
   *
   * @param groupName
   * @return
   */
  public static boolean nextIdInit(String groupName) {
    return mapGlobal.containsKey(PREFIX_GLOBAL + groupName);
  }

  public static void nextIdInit(Long startId) {
    nextIdInit(DEFAULT_GROUP_NAME, startId);
  }

  public static void nextIdInit(Class<?> groupName, Long startId) {
    nextIdInit(groupName.getSimpleName(), startId);
  }

  /**
   * 设置初始化编号
   *
   * @param groupName
   * @param startId
   */
  public static void nextIdInit(String groupName, Long startId) {
    RedisAtomicLong counter = mapGlobal.get(PREFIX_GLOBAL + groupName);
    if (counter == null) {
      counter = new RedisAtomicLong(PREFIX_GLOBAL + groupName, redisTemplate.getConnectionFactory());
      mapGlobal.put(PREFIX_GLOBAL + groupName, counter);
    }
    counter.set(startId);
  }

  /**
   * 获取每天默认组的唯一自增id,每天会自动重置
   *
   * @return
   */
  public static Long nextDayId() {
    return nextDayId(DEFAULT_GROUP_NAME);
  }


  public static Long nextDayId(Class<?> groupName) {
    return nextDayId(groupName.getSimpleName());
  }

  /**
   * 获取每天某组的唯一自增id,每天会自动重置
   *
   * @param groupName 组名
   * @return
   */
  public static Long nextDayId(String groupName) {
    RedisAtomicLong counter = map.get(groupName);
    if (counter == null) {
      counter = new RedisAtomicLong(PREFIX + groupName, redisTemplate.getConnectionFactory());
      map.put(groupName, counter);
    }
    if (day == null) {
      String dayStr = redisTemplate.opsForValue().get(PREFIX);
      if (dayStr == null) {
        day = LocalDate.now();
        redisTemplate.opsForValue().set(PREFIX, day.format(formatter));
      } else {
        day = LocalDate.parse(dayStr, formatter);
      }
    }
    if (!LocalDate.now().isEqual(day)) {
      day = LocalDate.now();
      redisTemplate.opsForValue().set(PREFIX, day.format(formatter));
      map.values().forEach(c -> {
        c.set(0L);
      });
    }
    return counter.incrementAndGet();
  }

  public static String nextDateId(Class<?> groupName, int len) {
    return nextDateId(groupName.getSimpleName(), len);
  }

  /**
   * 获取yyyyMMdd%0[len]d的唯一id字符串
   *
   * @param groupName
   * @param len
   * @return
   */
  public static String nextDateId(String groupName, int len) {
    if (len < 11) {
      throw new RuntimeException("长度最少11位");
    }
    if (len > 17) {
      throw new RuntimeException("长度最多17位");
    }
    Long id = nextDayId(groupName);
    return day.format(formatter) + String.format("%0" + (len - 8) + "d", id);
  }

  public static Long nextDateIdLong(Class<?> groupName, int len) {
    return nextDateIdLong(groupName.getSimpleName(), len);
  }

  /**
   * 获取yyyyMMdd%0[len]d的唯一id
   *
   * @param groupName
   * @param len
   * @return
   */
  public static Long nextDateIdLong(String groupName, int len) {
    return Long.valueOf(nextDateId(groupName, len));
  }


  /**
   * 获取yyyyMMdd%0[len]d的唯一id字符串
   *
   * @param len
   * @return
   */
  public static String nextDateId(int len) {
    return nextDateId(DEFAULT_GROUP_NAME, len);
  }


  /**
   * 获取yyyyMMdd%0[len]d的唯一id
   *
   * @param len
   * @return
   */
  public static Long nextDateIdLong(int len) {
    return Long.valueOf(nextDateId(len));
  }

  public static LocalDate getToday() {
    return day;
  }

  public static String getTodayStr() {
    return day == null ? LocalDate.now().format(formatter) : day.format(formatter);
  }
}
