package cn.teammodel.utils;

import java.util.concurrent.atomic.AtomicLong;

public class SnowflakeIdGenerator {

    // 定义起始时间戳（Epoch）
    private static final long EPOCH = 1677609600000L; // 2023-03-01 00:00:00 UTC

    // 定义工作机器ID的位数
    private static final long WORKER_ID_BITS = 10L;

    // 定义序列号的位数
    private static final long SEQUENCE_BITS = 12L;

    // 计算最大工作机器ID
    private static final long MAX_WORKER_ID = ~(-1L << WORKER_ID_BITS);

    // 计算最大序列号
    private static final long MAX_SEQUENCE = ~(-1L << SEQUENCE_BITS);

    // 工作机器ID的左移位数
    private static final long WORKER_ID_SHIFT = SEQUENCE_BITS;

    // 时间戳的左移位数
    private static final long TIMESTAMP_LEFT_SHIFT = SEQUENCE_BITS + WORKER_ID_BITS;

    // 当前工作机器ID
    private final long workerId;

    // 序列号
    private final AtomicLong sequence = new AtomicLong(0L);

    // 上一次生成ID的时间戳
    private long lastTimestamp = -1L;

    public SnowflakeIdGenerator(long workerId) {
        if (workerId > MAX_WORKER_ID || workerId < 0) {
            throw new IllegalArgumentException(String.format("workerId must be between 0 and %d", MAX_WORKER_ID));
        }
        this.workerId = workerId;
    }

    public synchronized long nextId() {
        long timestamp = timeGen();

        // 如果时间戳回退，则抛出异常
        if (timestamp < lastTimestamp) {
            throw new RuntimeException(String.format("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
        }

        // 如果时间戳相同，则递增序列号
        if (lastTimestamp == timestamp) {
            long sequence = this.sequence.getAndIncrement();
            if (sequence > MAX_SEQUENCE) {
                // 序列号溢出，则等待下一毫秒
                timestamp = tilNextMillis(lastTimestamp);
                this.sequence.set(0L);
            }
        } else {
            // 时间戳不同，则重置序列号
            this.sequence.set(0L);
        }

        // 更新上一次生成ID的时间戳
        lastTimestamp = timestamp;

        // 构造最终的ID
        return ((timestamp - EPOCH) << TIMESTAMP_LEFT_SHIFT) |
                (workerId << WORKER_ID_SHIFT) |
                (sequence.get());
    }

    private long tilNextMillis(long lastTimestamp) {
        long timestamp = timeGen();
        while (timestamp <= lastTimestamp) {
            timestamp = timeGen();
        }
        return timestamp;
    }

    private long timeGen() {
        return System.currentTimeMillis();
    }

   /* public static void main(String[] args) {
        SnowflakeIdGenerator generator = new SnowflakeIdGenerator(1); // 设置 workerId 为 1

        for (int i = 0; i < 10; i++) {
            long id = generator.nextId();
            System.out.println(id);
        }
    }*/
}
