using System;
using System.Linq;

namespace QYZH.InteractiveMagazine.Common.Helpers
{
    /// <summary>
    /// 雪花ID生成器
    /// 基于Twitter Snowflake算法实现
    /// </summary>
    public static class SnowflakeIdHelper
    {
        private static long _sequence = 0L;
        private static long _lastTimestamp = -1L;
        private static readonly object _lock = new object();

        // 基础时间戳 (2020-01-01 00:00:00 UTC)
        private const long TwEpoch = 1577836800000L;

        // 机器ID位数
        private const int WorkerIdBits = 5;

        // 数据中心ID位数
        private const int DataCenterIdBits = 5;

        // 序列号位数
        private const int SequenceBits = 12;

        // 最大值计算
        private const long MaxWorkerId = -1L ^ (-1L << WorkerIdBits);
        private const long MaxDataCenterId = -1L ^ (-1L << DataCenterIdBits);
        private const long MaxSequence = -1L ^ (-1L << SequenceBits);

        // 位移偏移量
        private const int WorkerIdShift = SequenceBits;
        private const int DataCenterIdShift = SequenceBits + WorkerIdBits;
        private const int TimestampLeftShift = SequenceBits + WorkerIdBits + DataCenterIdBits;

        private static long _workerId;
        private static long _dataCenterId;

        /// <summary>
        /// 静态构造函数,初始化机器ID和数据中心ID
        /// </summary>
        static SnowflakeIdHelper()
        {
            _workerId = GetWorkerId();
            _dataCenterId = GetDataCenterId();
        }

        /// <summary>
        /// 初始化雪花ID生成器
        /// </summary>
        /// <param name="workerId">机器ID (0-31)</param>
        /// <param name="dataCenterId">数据中心ID (0-31)</param>
        public static void Initialize(long workerId, long dataCenterId)
        {
            if (workerId < 0 || workerId > MaxWorkerId)
            {
                throw new ArgumentException($"机器ID必须在0-{MaxWorkerId}范围内", nameof(workerId));
            }

            if (dataCenterId < 0 || dataCenterId > MaxDataCenterId)
            {
                throw new ArgumentException($"数据中心ID必须在0-{MaxDataCenterId}范围内", nameof(dataCenterId));
            }

            _workerId = workerId;
            _dataCenterId = dataCenterId;
        }

        /// <summary>
        /// 生成雪花ID
        /// </summary>
        /// <returns>唯一的雪花ID</returns>
        public static long GenerateId()
        {
            lock (_lock)
            {
                long timestamp = GetCurrentMilliseconds();

                // 时钟回拨检测
                if (timestamp < _lastTimestamp)
                {
                    throw new InvalidOperationException("时钟回拨异常,拒绝生成ID");
                }

                // 同一毫秒内,序列号递增
                if (timestamp == _lastTimestamp)
                {
                    _sequence = (_sequence + 1) & MaxSequence;

                    // 序列号溢出,等待下一毫秒
                    if (_sequence == 0)
                    {
                        timestamp = WaitNextMillis(_lastTimestamp);
                    }
                }
                else
                {
                    _sequence = 0L;
                }

                _lastTimestamp = timestamp;

                // 组装ID: 时间戳 + 数据中心ID + 机器ID + 序列号
                return ((timestamp - TwEpoch) << TimestampLeftShift) |
                       (_dataCenterId << DataCenterIdShift) |
                       (_workerId << WorkerIdShift) |
                       _sequence;
            }
        }

        /// <summary>
        /// 获取当前毫秒数
        /// </summary>
        private static long GetCurrentMilliseconds()
        {
            return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
        }

        /// <summary>
        /// 等待下一毫秒
        /// </summary>
        private static long WaitNextMillis(long lastTimestamp)
        {
            long timestamp = GetCurrentMilliseconds();
            while (timestamp <= lastTimestamp)
            {
                timestamp = GetCurrentMilliseconds();
            }
            return timestamp;
        }

        /// <summary>
        /// 获取机器ID(基于MAC地址简单计算)
        /// </summary>
        private static long GetWorkerId()
        {
            try
            {
                string macAddress = System.Net.NetworkInformation.NetworkInterface.GetAllNetworkInterfaces()
                    .FirstOrDefault(n => n.OperationalStatus == System.Net.NetworkInformation.OperationalStatus.Up &&
                                        n.NetworkInterfaceType != System.Net.NetworkInformation.NetworkInterfaceType.Loopback)?
                    .GetPhysicalAddress().ToString() ?? "0";

                long hash = 0;
                foreach (char c in macAddress)
                {
                    hash = (hash * 31 + c) & MaxWorkerId;
                }
                return hash;
            }
            catch
            {
                return 1;
            }
        }

        /// <summary>
        /// 获取数据中心ID(基于机器名简单计算)
        /// </summary>
        private static long GetDataCenterId()
        {
            try
            {
                string machineName = Environment.MachineName;
                long hash = 0;
                foreach (char c in machineName)
                {
                    hash = (hash * 31 + c) & MaxDataCenterId;
                }
                return hash;
            }
            catch
            {
                return 1;
            }
        }
    }
}
