#ifndef _JW_CORE_ID_WORKER_H_
#define _JW_CORE_ID_WORKER_H_

#include <mutex>
#include <atomic>
#include <chrono>
#include <exception>
#include <sstream>

// 如果不使用 mutex, 则开启下面这个定义, 但是我发现, 还是开启 mutex 功能, 速度比较快
// #define SNOWFLAKE_ID_WORKER_NO_LOCK

        /**
         * @brief 分布式id生成类
         * https://segmentfault.com/a/1190000011282426
         * https://github.com/twitter/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
         *
         * 64bit id: 0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000  0000
         *           ||                                                           ||     ||     |  |              |
         *           |└---------------------------时间戳---------------------------┘└-中心-┘└机器-┘  └----序列号----┘
         *         不用
         * SnowFlake的优点: 整体上按照时间自增排序, 并且整个分布式系统内不会产生ID碰撞(由数据中心ID和机器ID作区分), 并且效率较高, 经测试, SnowFlake每秒能够产生26万ID左右.
         */
class Snowflake
{
public:
    //typedef unsigned int UInt;
    //typedef unsigned long long int UInt64;

#ifdef SNOWFLAKE_ID_WORKER_NO_LOCK
    typedef std::atomic<UInt> AtomicUInt;
    typedef std::atomic<uint64_t> AtomicUInt64;
#else
    typedef unsigned int AtomicUInt;
    typedef uint64_t AtomicUInt64;
#endif

    static Snowflake& instance()
    {
        static Snowflake inst;
        return inst;
    }

    void setWorkerId(unsigned int workerId) { this->workerId = workerId; }

    void setDatacenterId(unsigned int datacenterId) { this->datacenterId = datacenterId; }

    uint64_t getId() { return nextId(); }

    std::string getIdStr() { return std::to_string(nextId()); }

    /**
     * 获得下一个ID (该方法是线程安全的)
     *
     * @return SnowflakeId
     */
    uint64_t nextId() {
#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
        std::unique_lock<std::mutex> lock {mutex};
        AtomicUInt64 timestamp {0};
#else
        static AtomicUInt64 timestamp {0};
#endif
        timestamp = timetick();

        // 如果当前时间小于上一次ID生成的时间戳，说明系统时钟回退过这个时候应当抛出异常
        if (timestamp < lastTimestamp) {
            std::ostringstream s;
            s << "clock moved backwards.  Refusing to generate id for " << lastTimestamp - timestamp << " milliseconds";
            throw std::exception(std::runtime_error(s.str()));
        }

        if (lastTimestamp == timestamp) {
            // 如果是同一时间生成的，则进行毫秒内序列
            sequence = (sequence + 1) & sequenceMask;
            if (0 == sequence) {
                // 毫秒内序列溢出, 阻塞到下一个毫秒,获得新的时间戳
                timestamp = tilNextMillis(lastTimestamp);
            }
        }
        else {
            sequence = 0;
        }

#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
        lastTimestamp = timestamp;
#else
        lastTimestamp_ = timestamp.load();
#endif
        // 移位并通过或运算拼到一起组成64位的ID
        return ((timestamp - twepoch) << timestampLeftShift)
            | (datacenterId << datacenterIdShift)
            | (workerId << workerIdShift)
            | sequence;
    }

protected:
    Snowflake() : workerId(0), datacenterId(0), sequence(0), lastTimestamp(0) {}

    /**
     * 返回以毫秒为单位的当前时间
     *
     * @return 当前时间(毫秒)
     */
    uint64_t timetick() const {
        //auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now());
        auto t = std::chrono::time_point_cast<std::chrono::milliseconds>(std::chrono::system_clock::now());
        return t.time_since_epoch().count();
    }

    /**
     * 阻塞到下一个毫秒，直到获得新的时间戳
     *
     * @param lastTimestamp 上次生成ID的时间截
     * @return 当前时间戳
     */
    uint64_t tilNextMillis(uint64_t lastTimestamp) const {
        uint64_t timestamp = timetick();
        while (timestamp <= lastTimestamp) {
            timestamp = timetick();
        }
        return timestamp;
    }

private:

#ifndef SNOWFLAKE_ID_WORKER_NO_LOCK
    std::mutex mutex;
#endif

    /**
     * 开始时间截 2025-01-01 00:00:00.000
     */
    const uint64_t twepoch = 1735660800000;

    /**
     * 机器id所占的位数
     */
    const unsigned int workerIdBits = 4;

    /**
     * 数据中心id所占的位数
     */
    const unsigned int datacenterIdBits = 1;

    /**
     * 序列所占的位数
     */
    const unsigned int sequenceBits = 12;

    /**
     * 机器ID向左移12位
     */
    const unsigned int workerIdShift = sequenceBits;

    /**
     * 数据标识id向左移16位
     */
    const unsigned int datacenterIdShift = workerIdShift + workerIdBits;

    /**
     * 时间截向左移17位
     */
    const unsigned int timestampLeftShift = datacenterIdShift + datacenterIdBits;

    /**
     * 支持的最大机器id，
     */
    const unsigned int maxWorkerId = -1 ^ (-1 << workerIdBits);

    /**
     * 支持的最大数据中心id，
     */
    const unsigned int maxDatacenterId = -1 ^ (-1 << datacenterIdBits);

    /**
     * 生成序列的掩码，这里为4095
     */
    const unsigned int sequenceMask = -1 ^ (-1 << sequenceBits);

    /**
     * 工作机器id(0~31)
     */
    unsigned int workerId;

    /**
     * 数据中心id(0~31)
     */
    unsigned int datacenterId;

    /**
     * 毫秒内序列(0~4095)
     */
    AtomicUInt sequence {0};

    /**
     * 上次生成ID的时间截
     */
    AtomicUInt64 lastTimestamp {0};
};

#endif // _JW_CORE_ID_WORKER_H_