using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;

using StackExchange.Redis;
using Xunit;
using Xunit.Extensions;
using Xunit.Serialization;
using Xunit.Abstractions;
using Xunit.Sdk;

using RedisStudyModel;
using RedisStuy;

namespace RedisStudyTest
{
    [Trait("RedisString", "All")]
    public class RedisStringStudyTest : IDisposable
    {
        #region 初始化
        private readonly ITestOutputHelper testOutput;
        private IDatabase redisDatabase = null;
        private RedisStringStudy redisStringStudy = null;
        private TimeSpan defaultExpiry =TimeSpan.FromSeconds(20);
        private string defaultRedisKey = "RedisStudy:String:xUnitTest";

        /// <summary>
        /// 构造
        /// </summary>
        public RedisStringStudyTest(ITestOutputHelper output)
        {
            this.testOutput = output;
            redisDatabase = RedisHelper.GetRedisDatabase();
            redisStringStudy = new RedisStringStudy();

        }
        #endregion

        #region StringSet

        /// <summary>
        /// 键名为空串时,操作正常
        /// 只是"Redis Desktop Manager"管理工具显示空白
        /// </summary>
        [Fact]
        public void StringSetKeyIsEmptyTest()
        {
            //添加正常
            var setResult = redisDatabase.StringSet(string.Empty, "Redis String key is string.empty");
            Assert.True(setResult);

            var getValue = redisDatabase.StringGet(string.Empty);
            Assert.Equal("Redis String key is string.empty", getValue);

            //更新正常
            setResult = redisDatabase.StringSet(string.Empty, "Updage empty key value to new values");
            Assert.True(setResult);

            getValue = redisDatabase.StringGet(string.Empty);
            Assert.Equal("Updage empty key value to new values", getValue);

            //清理
            redisDatabase.KeyDelete(string.Empty);
        }

        /// <summary>
        /// 设置一个键值对
        /// </summary>
        [Fact]
        public void StringSetOneKeyValueTest()
        {
            //不存在时,添加
            var setResult = redisStringStudy.StringSet(defaultRedisKey, "xUnit", defaultExpiry);
            Assert.True(setResult);

            var redisValue = redisStringStudy.StringGet(defaultRedisKey);
            Assert.Equal("xUnit", redisValue);

            //存在时,更新
            var setResult2 = redisStringStudy.StringSet(defaultRedisKey, "xUnit update", defaultExpiry);
            Assert.True(setResult2);

            var  redisValue2 = redisStringStudy.StringGet(defaultRedisKey);
            Assert.Equal("xUnit update", redisValue2);
        }

        /// <summary>
        /// 设置值为字符串
        /// </summary>
        [Fact]
        public void StringSetForString()
        {
            var setResult = redisStringStudy.StringSet(defaultRedisKey, "I am string", defaultExpiry);
            Assert.True(setResult);

            var redisValue = redisStringStudy.StringGet(defaultRedisKey);
            Assert.Equal("I am string", redisValue);
        }

        /// <summary>
        /// 设置值为数字
        /// </summary>
        [Fact]
        public void StringSetForNumber()
        {
            var setResult = redisStringStudy.StringSet(defaultRedisKey, 20000, defaultExpiry);
            Assert.True(setResult);

            var redisValue = redisStringStudy.StringGet(defaultRedisKey);
            Assert.Equal(20000, redisValue);
        }

        /// <summary>
        /// 设置值为json
        /// </summary>
        [Fact]
        public void StringSetForJson()
        {
            var stuent = new
            {
                Id=1,
                Name="王高峰",
                Age=30,
                Number="05121098"
            };

            var json = JsonConvert.SerializeObject(stuent);

            var setResult = redisStringStudy.StringSet(defaultRedisKey, json, defaultExpiry);
            Assert.True(setResult);

            //Newtonsoft.Json 反序列化为匿名类型
            var redisValue = redisStringStudy.StringGet(defaultRedisKey);
            var anonymousType = JsonConvert.DeserializeAnonymousType(redisValue, stuent);
            Assert.True(anonymousType.Id == stuent.Id && anonymousType.Name == stuent.Name && anonymousType.Age == stuent.Age && anonymousType.Number == stuent.Number);

        }

        /// <summary>
        /// 设置值为Bit
        /// </summary>
        [Fact]
        public void StringSetForBit()
        {
            var setResult = redisStringStudy.StringSet(defaultRedisKey, Encoding.UTF8.GetBytes("我要转变为二进制数据,再存储"), defaultExpiry);
            Assert.True(setResult);

            var redisValue = (byte[])redisStringStudy.StringGet(defaultRedisKey);

            Assert.Equal("我要转变为二进制数据,再存储", Encoding.UTF8.GetString(redisValue, 0, redisValue.Length));
        }

        /// <summary>
        /// 设置一组键值对
        /// </summary>
        [Fact]
        public void StringSetGroupKeyValueTest()
        {
            //添加
            KeyValuePair<RedisKey, RedisValue>[] keyValuePairs = new KeyValuePair<RedisKey, RedisValue>[]
            {
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:1","group1"),
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:2",20),
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:3","{\"Id\":1,\"Name\":\"wanggaofeng\",\"Age\":20}"),
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:3",BitConverter.GetBytes(123)),
            };

            var setResult = redisStringStudy.StringSet(keyValuePairs);
            Assert.True(setResult);

            //更新
            keyValuePairs = new KeyValuePair<RedisKey, RedisValue>[]
            {
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:1","group3"),
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:2",20),
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:3","{\"Id\":1,\"Name\":\"wanggaofeng\",\"Age\":20}"),
                new KeyValuePair<RedisKey, RedisValue>("RedisStudy:String:3",BitConverter.GetBytes(200)),
            };
            setResult = redisStringStudy.StringSet(keyValuePairs);
            Assert.True(setResult);

            //清理
            redisDatabase.KeyDelete("RedisStudy:String:1");
            redisDatabase.KeyDelete("RedisStudy:String:2");
            redisDatabase.KeyDelete("RedisStudy:String:3");

        }
        #endregion

        #region StringSetRange

        [Fact]
        public void StringSetRangeNotKeyTest()
        {
            var alterRangeLenth = redisStringStudy.StringSetRange(defaultRedisKey, 0, "first");
            Assert.Equal("first".Length, alterRangeLenth);
        }

        [Fact]
        public void StringSetRangeTest()
        {
            var alterRangeLenth = redisStringStudy.StringSetRange(defaultRedisKey, 0, "first");
            Assert.Equal("first".Length, alterRangeLenth);

            alterRangeLenth = redisStringStudy.StringSetRange(defaultRedisKey, 1, "second");
            Assert.Equal("fsecond".Length, alterRangeLenth);
        }
        #endregion

        #region StringAppend

        [Fact]
        public void StringAppendStringTest()
        {
            //不存在时,添加并设置初始值
            var redisValueLenth = redisStringStudy.StringAppend(defaultRedisKey, "source");
            Assert.Equal("source".Length, redisValueLenth);

            //存在时,追加
            redisValueLenth = redisStringStudy.StringAppend(defaultRedisKey, " append");
            Assert.Equal("source append".Length, redisValueLenth);
        }

        [Fact]
        public void StringAppendNumberTest()
        {
            //不存在时,添加并设置初始值
            var redisValueLenth = redisStringStudy.StringAppend(defaultRedisKey, 123);
            Assert.Equal(3, redisValueLenth);

            //存在时,追加
            redisValueLenth = redisStringStudy.StringAppend(defaultRedisKey, 456);
            Assert.Equal(6, redisValueLenth);

        }
        #endregion

        #region StringIncrement

        [Fact]
        public void StringIncrementIntegerTest()
        {
            //key不存在,则添加后自增
            var result = redisStringStudy.StringIncrement(defaultRedisKey,1);
            Assert.Equal(1, result);

            //key存在,自增
            result = redisStringStudy.StringIncrement(defaultRedisKey, 2);
            Assert.Equal(3, result);

            //自增负数,等于自减
            result = redisStringStudy.StringIncrement(defaultRedisKey, -1);
            Assert.Equal(2, result);
        }

        [Fact]
        public void StringIncrementDoubleTest()
        {
            //key不存在,则添加后自增
            var result = redisStringStudy.StringIncrement(defaultRedisKey, 1.5);
            Assert.Equal(1.5, result);

            //key存在,自增
            result = redisStringStudy.StringIncrement(defaultRedisKey, 2.1);
            var absResult = Math.Abs(3.6-result);
            Assert.True(absResult < 0.1);

            //自增负数,等于自减
            result = redisStringStudy.StringIncrement(defaultRedisKey, -1.1);
            absResult = Math.Abs(2.5 - result);
            Assert.True(absResult < 0.1);
        }

        #endregion

        #region StringDecrement

        [Fact]
        public void StringDecrementIntegerTest()
        {
            //key不存在,则添加后自减
            var result = redisStringStudy.StringDecrement(defaultRedisKey, 1);
            Assert.Equal(-1, result);

            //key存在,自减
            result = redisStringStudy.StringDecrement(defaultRedisKey, 2);
            Assert.Equal(-3, result);

            //自减负数,等于自增
            result = redisStringStudy.StringDecrement(defaultRedisKey, -1);
            Assert.Equal(-2, result);
        }

        [Fact]
        public void StringDecrementDoubleTest()
        {
            //key不存在,则添加后自减
            var result = redisStringStudy.StringDecrement(defaultRedisKey, 1.5);
            Assert.Equal(-1.5, result);

            //key存在,自减
            result = redisStringStudy.StringDecrement(defaultRedisKey, 2.1);
            var absResult = Math.Abs(-3.6 - result);
            Assert.True(absResult < 0.1);

            //自减负数,等于自增
            result = redisStringStudy.StringDecrement(defaultRedisKey, -1.1);
            absResult = Math.Abs(-2.5 - result);
            Assert.True(absResult < 0.1);
        }

        #endregion

        #region StringGet

        [Fact]
        public void StringGetNotKeyTest()
        {
            var result =  redisStringStudy.StringGet("xxxxxxxxx");

            Assert.False(result.HasValue);
        }
        #endregion

        #region 清理
        public void Dispose()
        {
            redisDatabase.KeyDelete(defaultRedisKey);
        }
        #endregion
    }
}