using System;
using System.Threading;

namespace StandardScene.CommonTools
{
    public sealed class SnowflakeIdGenerator
    {
        // 默认起始时间戳：2026-01-01T00:00:00.000Z（Unix 毫秒）
        // 如果你希望生成的数字更短，可以在构造函数里传入更“近”的 _epochMs（建议全系统统一）。
        private const long DefaultEpochMs = 1767225600000L;
        private const int WorkerIdBits = 5; // 机器ID所占的位数
        private const int DatacenterIdBits = 5; // 数据中心ID所占的位数
        private const int MaxWorkerId = -1 ^ (-1 << WorkerIdBits); // 最大机器ID
        private const int MaxDatacenterId = -1 ^ (-1 << DatacenterIdBits); // 最大数据中心ID
        private const int SequenceBits = 12; // 序列号所占的位数
        private const int WorkerIdShift = SequenceBits; // 机器ID左移的位数
        private const int DatacenterIdShift = SequenceBits + WorkerIdBits; // 数据中心ID左移的位数
        private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits; // 时间戳左移的位数
        private const long SequenceMask = -1L ^ (-1L << SequenceBits); // 序列号的最大值

        private const string Base62Alphabet = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";

        private readonly object _syncRoot = new object();
        private readonly long _epochMs;
        private readonly long _workerId; // 机器ID
        private readonly long _datacenterId; // 数据中心ID
        private long _sequence; // 序列号
        private long _lastTimestamp = -1L; // 上次生成ID的时间戳

        public SnowflakeIdGenerator(long workerId, long datacenterId, long? epochMs = null)
        {
            this._epochMs = epochMs ?? DefaultEpochMs;
            if (this._epochMs > TimeGen())
            {
                throw new ArgumentException("_epochMs cannot be in the future.");
            }
            if (workerId is > MaxWorkerId or < 0)
            {
                throw new ArgumentException($"worker Id can't be greater than {MaxWorkerId} or less than 0");
            }
            if (datacenterId is > MaxDatacenterId or < 0)
            {
                throw new ArgumentException($"{datacenterId} can't be greater than {MaxDatacenterId} or less than 0");
            }
            this._workerId = workerId;
            this._datacenterId = datacenterId;
        }

        public long NextId()
        {
            lock (_syncRoot)
            {
                long timestamp = TimeGen();
                if (timestamp < _lastTimestamp)
                {
                    // 容忍系统时钟回拨：等待到追上 _lastTimestamp，避免直接抛异常把业务打崩。
                    timestamp = TilNextMillis(_lastTimestamp);
                }
                if (_lastTimestamp == timestamp)
                {
                    _sequence = (_sequence + 1) & SequenceMask;
                    if (_sequence == 0)
                    {
                        timestamp = TilNextMillis(_lastTimestamp);
                    }
                }
                else
                {
                    _sequence = 0;
                }
                _lastTimestamp = timestamp;
                long id = ((timestamp - _epochMs) << TimestampLeftShift)
                          | (_datacenterId << DatacenterIdShift)
                          | (_workerId << WorkerIdShift)
                          | _sequence;
                return id;
            }
        }

        /// <summary>
        /// 生成更短的字符串形式 ID（Base62 编码），便于显示/存储。
        /// </summary>
        public string NextIdBase62()
        {
            ulong value = unchecked((ulong)NextId());
            return ToBase62(value);
        }

        private static long TilNextMillis(long lastTimestamp)
        {
            var spin = new SpinWait();
            long timestamp;
            do
            {
                spin.SpinOnce();
                timestamp = TimeGen();
            }
            while (timestamp <= lastTimestamp);

            return timestamp;
        }

        private static long TimeGen()
        {
            return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        }

        private static string ToBase62(ulong value)
        {
            if (value == 0)
            {
                return "0";
            }

            // 2^64-1 的 base62 最大长度为 11（因为 62^11 > 2^64）。
            char[] buffer = new char[11];
            int pos = buffer.Length;
            while (value > 0)
            {
                ulong rem = value % 62;
                value /= 62;
                buffer[--pos] = Base62Alphabet[(int)rem];
            }

            return new string(buffer, pos, buffer.Length - pos);
        }
    }
}
