//using CSRedis;
//using Microsoft.AspNetCore.Http;
//using System;
//using System.Collections.Concurrent;
//using System.Collections.Generic;
//using System.Diagnostics;
//using System.Linq;
//using System.Reflection;
//using System.Threading;
//using System.Threading.Tasks;

//public static class LogHelper
//{
//    private static AsyncLocal<string> _asyncLocal;
//    private static BlockingCollection<Log> _queue;
//    private static object _lockObject;
//    private static string _secretKey;
//    private static IHttpContextAccessor _contextAccessor;

//    public static void Initialize(string redisConnectionString, string secretKey)
//    {
//        _secretKey = secretKey;
//        var client = new CSRedisClient(redisConnectionString);
//        _queue = new BlockingCollection<Log>();
//        _asyncLocal = new AsyncLocal<string>();
//        _lockObject = new object();
//        _contextAccessor = new HttpContextAccessor();

//        Task.Factory.StartNew(() =>
//        {
//            while (!_queue.IsCompleted)
//            {
//                var log = _queue.Take();
//                client.LPush("log.queue", log);
//            }
//        });
//    }

//    public static void Trace(string message, params string[] tag)
//    {
//        WriteLog(message, tag, LogLevel.Trace);
//    }
//    public static void Debug(string message, params string[] tag)
//    {
//        WriteLog(message, tag, LogLevel.Debug);
//    }
//    public static void Information(string message, params string[] tag)
//    {
//        WriteLog(message, tag, LogLevel.Information);
//    }
//    public static void Warning(string message, params string[] tag)
//    {
//        WriteLog(message, tag, LogLevel.Warning);
//    }
//    public static void Error(string message, params string[] tag)
//    {
//        WriteLog(message, tag, LogLevel.Error);
//    }
//    public static void Fatal(string message, params string[] tag)
//    {
//        WriteLog(message, tag, LogLevel.Fatal);
//    }

//    private static void WriteLog(string message, string[] tag, LogLevel logLevel)
//    {
//        try
//        {
//            if (_contextAccessor.HttpContext == null || string.IsNullOrEmpty(_contextAccessor.HttpContext.TraceIdentifier))
//            {
//                if (string.IsNullOrEmpty(_asyncLocal.Value))
//                    lock (_lockObject)
//                        Guid.NewGuid().ToString("N");
//            }
//            else
//            {
//                _asyncLocal.Value = _contextAccessor.HttpContext.TraceIdentifier;
//            }

//            Log log = new Log
//            {
//                Id = SnowflakeId.Default().NextId(),
//                Level = logLevel,
//                LogTime = DateTime.Now,
//                Message = message,
//                Stack = GetStackInfo(),
//                TraceId = _asyncLocal.Value,
//                Tag = tag.ToList(),
//                SecretKey = _secretKey
//            };
//            _queue.Add(log);
//        }
//        catch { }
//    }

//    private static List<string> GetStackInfo()
//    {
//        StackTrace trace = new StackTrace(true);

//        List<string> result = new List<string>();
//        for (int i = 0; i < trace.FrameCount; i++)
//        {
//            StackFrame frame = trace.GetFrame(i);
//            MethodBase method = frame.GetMethod();
//            if (method.DeclaringType == null
//                || method.DeclaringType.FullName.StartsWith("System")
//                || method.DeclaringType.FullName.StartsWith("Microsoft")
//                || method.DeclaringType.FullName.StartsWith("Online.Log"))
//                continue;

//            var paras = method.GetParameters().Select(t => $"{t.ParameterType.Name} {t.Name}");

//            result.Add($"At {method.DeclaringType.FullName}.{method.Name}({string.Join(",", paras)}) Number({frame.GetFileLineNumber()})");
//        }
//        return result;
//    }
//}

//internal class Log
//{
//    public long Id { get; set; }
//    public DateTime LogTime { get; set; }
//    public LogLevel Level { get; set; }
//    public string SecretKey { get; set; }
//    public string TraceId { get; set; }
//    public string Message { get; set; }
//    public List<string> Stack { get; set; }
//    public List<string> Tag { get; set; }
//}

//internal enum LogLevel
//{
//    All = 0,
//    Trace = 1,
//    Debug = 2,
//    Information = 3,
//    Warning = 4,
//    Error = 5,
//    Fatal = 6
//}

//internal class SnowflakeId
//{
//    public const long Twepoch = 1288834974657L;

//    private const int WorkerIdBits = 5;
//    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 int WorkerIdShift = SequenceBits;
//    private const int DatacenterIdShift = SequenceBits + WorkerIdBits;
//    public const int TimestampLeftShift = SequenceBits + WorkerIdBits + DatacenterIdBits;
//    private const long SequenceMask = -1L ^ (-1L << SequenceBits);

//    private static SnowflakeId _snowflakeId;

//    private readonly object _lock = new object();
//    private static readonly object SLock = new object();
//    private long _lastTimestamp = -1L;

//    public SnowflakeId(long workerId, long datacenterId, long sequence = 0L)
//    {
//        WorkerId = workerId;
//        DatacenterId = datacenterId;
//        Sequence = sequence;

//        // sanity check for workerId
//        if (workerId > MaxWorkerId || workerId < 0)
//            throw new ArgumentException($"worker Id can't be greater than {MaxWorkerId} or less than 0");

//        if (datacenterId > MaxDatacenterId || datacenterId < 0)
//            throw new ArgumentException($"datacenter Id can't be greater than {MaxDatacenterId} or less than 0");
//    }

//    public long WorkerId { get; protected set; }
//    public long DatacenterId { get; protected set; }

//    public long Sequence { get; internal set; }

//    public static SnowflakeId Default()
//    {
//        lock (SLock)
//        {
//            if (_snowflakeId != null)
//            {
//                return _snowflakeId;
//            }

//            var random = new Random();

//            if (!int.TryParse(Environment.GetEnvironmentVariable("CAP_WORKERID", EnvironmentVariableTarget.Machine), out var workerId))
//            {
//                workerId = random.Next((int)MaxWorkerId);
//            }

//            if (!int.TryParse(Environment.GetEnvironmentVariable("CAP_DATACENTERID", EnvironmentVariableTarget.Machine), out var datacenterId))
//            {
//                datacenterId = random.Next((int)MaxDatacenterId);
//            }

//            return _snowflakeId = new SnowflakeId(workerId, datacenterId);
//        }
//    }

//    public virtual long NextId()
//    {
//        lock (_lock)
//        {
//            var timestamp = TimeGen();

//            if (timestamp < _lastTimestamp)
//                throw new Exception(
//                    $"InvalidSystemClock: Clock moved backwards, Refusing to generate id for {_lastTimestamp - timestamp} milliseconds");

//            if (_lastTimestamp == timestamp)
//            {
//                Sequence = (Sequence + 1) & SequenceMask;
//                if (Sequence == 0) timestamp = TilNextMillis(_lastTimestamp);
//            }
//            else
//            {
//                Sequence = 0;
//            }

//            _lastTimestamp = timestamp;
//            var id = ((timestamp - Twepoch) << TimestampLeftShift) |
//                     (DatacenterId << DatacenterIdShift) |
//                     (WorkerId << WorkerIdShift) | Sequence;

//            return id;
//        }
//    }

//    protected virtual long TilNextMillis(long lastTimestamp)
//    {
//        var timestamp = TimeGen();
//        while (timestamp <= lastTimestamp) timestamp = TimeGen();
//        return timestamp;
//    }

//    protected virtual long TimeGen()
//    {
//        return DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
//    }
//}

