using Fuel.Infrastructure.Extension;
using System;

namespace Fuel.Infrastructure
{
    /// <summary>
    /// Redis实现锁帮助类
    /// </summary>
    public class RedisLockerHelper
    {
        /// <summary>
        /// 获取redis分布式锁
        /// </summary>
        /// <param name="lockKeyName"></param>
        /// <param name="lockTimeout">自动过期时间（毫秒）</param>
        /// <returns></returns>
        public static bool GetRedisDistributedLock(string lockKeyName, long lockTimeout)
        {
            if (SetNx(lockKeyName, TimeExtension.GetNowTimeStamp(true) + lockTimeout, lockTimeout))
            {
                return true;
            }
            else
            {
                //未获取到锁，继续判断，判断时间戳看看是否可以重置并获取锁
                long lockValue = RedisHelper.Get<long>(lockKeyName);
                long time = TimeExtension.GetNowTimeStamp(true);

                if (time > lockValue)
                {
                    //再次用当前时间戳getset
                    //返回固定key的旧值，旧值判断是否可以获取锁
                    long getsetResult = RedisHelper.GetSet<long>(lockKeyName, time);
                    if (getsetResult == lockValue)
                    {
                        RedisHelper.Expire(lockKeyName, TimeSpan.FromMilliseconds(lockTimeout));
                        return true;
                    }
                    else
                    {
                        return false;
                    }
                }
                else
                {
                    return false;
                }
            }

        }

        private static bool SetNx(string key, long time, double expireMS)
        {

            if (expireMS > 0)
            {
                if (RedisHelper.Set(key, time, TimeSpan.FromMilliseconds(expireMS), CSRedis.RedisExistence.Nx))
                    return true;
            }
            else
            {
                if (RedisHelper.SetNx(key, time))
                {
                    RedisHelper.Expire(key, TimeSpan.FromMilliseconds(expireMS));
                    return true;
                }
            }

            return false;
        }

    }


}
