package com.cf.imes.framework.id.core.util;

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

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * @ClassName: SnowflakeSerialNoWorker3rd
 * @Description:snowflake算法改进
 * @author: yonnie
 * @date: 2025/09/29 16:00
 * @version V1.1
 *
 *          将产生的Id类型更改为Integer 64bit <br>
 *          把时间戳的单位改为秒，使用48bit的时间戳
 *          16bit作为自增值即 2^16 = 65535
 */
@Slf4j
@Component
public class SnowflakeSerialNoWorker3rd {
    /** 初始时间 (2025-01-01 00:00:00: 1735660800) */
    // private final long twepoch = 28927680;// 1735660800000L/1000/60;
    private final long twepoch = 1735660800;
    /** 序列在id中占位数 */
    private final long sequenceBits = 16L;
    /** 时间截向左移16bit */
    private final long timestampLeftShift = sequenceBits;
    /** 生成序列的MASK (0xFFFF) */
    private final long sequenceMask = -1 ^ (-1 << sequenceBits);
    /** 分钟内序 (0~65535) */
    private long sequence = 0;
    private long laterSequence = 0;
    /** 上次生成ID的时间戳 */
    private long lastTimestamp = -1;
    private final SerialNoMinuteCounter counter = new SerialNoMinuteCounter();
    /** 预支时间标志 */
    boolean isAdvance = false;
    /** 时间格式 */
    private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyMMddHHmmss");

    // ==============================Constructors=====================================

    public SnowflakeSerialNoWorker3rd() {
        // constructor
    }

    // ==============================Test=============================================

    /** 测试 */
    public static void main(String[] args) {
        SnowflakeSerialNoWorker3rd idWorker = new SnowflakeSerialNoWorker3rd();
        for (long i = 0; i < 1000; i++) {
            System.out.println(i + ": " + idWorker.nextSerialNo());
        }
    }

    // ==============================Methods==========================================

    /**
     * 获得下一个ID (该方法是线程安全)
     * 
     * @return SnowflakeId
     */
    public synchronized long nextId() {
        long timestamp = timeGen();
        // System.out.println("timeGen: " + Long.toString(timestamp));
        // 如果当前时间小于上一次ID生成的时间戳，说明系统时钟修改过
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format(
                    "Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        if (timestamp > counter.get()) {
            counter.set(timestamp);
            isAdvance = false;
        }

        // 如果是同时间生成的，则进行秒内序列
        if (lastTimestamp == timestamp || isAdvance) {
            if (!isAdvance) {
                sequence = (sequence + 1) & sequenceMask;
            }

            // 秒内自增列溢出
            if (sequence == 0) {
                // 预支下一秒获得新的时间戳
                isAdvance = true;
                long laterTimestamp = counter.get();
                if (laterSequence == 0) {
                    laterTimestamp = counter.incrementAndGet();
                }
                long nextId = ((laterTimestamp - twepoch) << timestampLeftShift) | laterSequence;
                laterSequence = (laterSequence + 1) & sequenceMask;
                return nextId;
            }
        } else { // 时间戳改变，秒内序列置0
            sequence = 0;
            laterSequence = 0;
        }
        // 上次生成ID的时间截
        lastTimestamp = timestamp;
        // 移位并或运算拼成64位的ID
        return ((timestamp - twepoch) << timestampLeftShift) | sequence;
    }

    public String nextSerialNo() {
        return LocalDateTime.now().format(FORMATTER) + String.valueOf(nextId()).substring(8);
    }

    /**
     * 返回以秒为单位的当前时间
     * 
     * @return 当前时间(秒)
     */
    protected long timeGen() {
        // String timestamp = String.valueOf(System.currentTimeMillis() / 1000 / 60);
        // String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
        // return Long.valueOf(timestamp);
        return System.currentTimeMillis() / 1000;
    }

}
