package com.ylx.massage.utils;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

@Component
@Slf4j
public class OrderNumberGenerator {

    // 订单单号前缀
    public static final String KEY_PREFIX_ORDER = "YORDER";
    public static final String KEY_PREFIX_RECHAR = "RECHAR";
    public static final String KEY_PREFIX_CASH = "CASH";
    public static final String KEY_PREFIX_REFUND = "REFUND";
    public static final String KEY_PREFIX_PRODUCTORDER = "PRODUCT";

    private static final DateTimeFormatter DATE_FORMATTER2 = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");

    private static final int SEQUENCE_MAX_VALUE = 99999;

    private static final int SEQUENCE_WARN_THRESHOLD = 90000;

    /**
     * 机器ID（用于多实例部署时区分不同节点）
     * 可通过配置中心或启动参数动态获取，这里使用固定值
     */
    private static final String MACHINE_ID = "01";

    /**
     * 每个前缀的序列号缓存（key 格式：prefix + yyyyMMddHHmmss）
     */
    private final ConcurrentHashMap<String, AtomicLong> sequenceCache = new ConcurrentHashMap<>();

    /**
     * 生成并返回当天的下一个自增单号。
     * 不依赖 Redis，使用本地原子序列生成器。
     *
     * @param prefix 订单号前缀
     * @return String 订单号（格式：prefix + yyyyMMddHHmmss + machineId + 5位序列号）
     */
    public String generateNextOrderNumber(String prefix) {
        LocalDateTime now = LocalDateTime.now();
        String timeStr = now.format(DATE_FORMATTER2);
        String cacheKey = prefix + timeStr;

        // 获取或创建当前秒的序列号
        AtomicLong sequence = sequenceCache.computeIfAbsent(cacheKey, k -> {
            log.debug("创建新的序列号缓存，key：{}", cacheKey);
            return new AtomicLong(0);
        });

        // 原子递增并获取序列号
        long newSequence = sequence.incrementAndGet();

        // 容量预警：序列号超过警戒阈值时记录警告日志
        if (newSequence > SEQUENCE_WARN_THRESHOLD) {
            log.warn("订单号序列号接近上限，当前值：{}，前缀：{}，时间：{}", newSequence, prefix, timeStr);
        }

        // 序列号溢出检查
        if (newSequence > SEQUENCE_MAX_VALUE) {
            log.error("订单号序列号超过上限，当前值：{}，前缀：{}，时间：{}", newSequence, prefix, timeStr);
            throw new IllegalStateException("当前秒内订单号序列号超出系统限制，请稍后重试");
        }

        // 格式：前缀 + 时间串 + 机器ID + 5位序列号
        return prefix + timeStr + MACHINE_ID + String.format("%05d", newSequence);
    }

    public static void main(String[] args) {
        OrderNumberGenerator generator = new OrderNumberGenerator();

        // 测试生成 10 个订单号
        for (int i = 0; i < 10; i++) {
            System.out.println(generator.generateNextOrderNumber(KEY_PREFIX_PRODUCTORDER));
            if (i < 9) {
                try {
                    // 模拟不同时间的订单
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}
