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

using RedisStudyModel;

using StackExchange;
using StackExchange.Redis;

using RedisStuy;

namespace RedisStudyTest
{
    public class RedisHashStudyTest : IDisposable
    {
        private IDatabase redisDatabase = null;
        private RedisHashStudy hashStudy = null;
        private List<Student> students;
        private Student student = null;
        private string preHashKey = "RedisStudy:Student:";

        /// <summary>
        /// 构造
        /// </summary>
        public RedisHashStudyTest()
        {
            redisDatabase = RedisHelper.GetRedisDatabase();
            hashStudy = new RedisHashStudy();
            student = new Student()
            {
                Id = 1,
                Name = "王高峰",
                Age = 2 * 9
            };
            students = new List<Student>()
            {
                new Student()
                {
                    Id = 1001,
                    Name = "王高峰",
                    Age = 11
                },
                new Student()
                {
                    Id = 1002,
                    Name = "王高峰2",
                    Age = 22
                },
                new Student()
                {
                    Id = 1003,
                    Name = "王高峰3",
                    Age = 33
                },
                new Student()
                {
                    Id = 1004,
                    Name = "王高峰4",
                    Age = 44
                },
                new Student()
                {
                    Id = 1005,
                    Name = "王高峰5",
                    Age = 55
                },
            };

            //hashStudy.AddStudents(students);
        }

        [Fact]
        public void AddStudentExceptionTest()
        {
            string redisKey = preHashKey + student.Id;
            //参数异常测试
            Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet(string.Empty, null));
            Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet("", null));
            Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet(preHashKey + "-1", null));
            Assert.Throws<ArgumentNullException>(() => hashStudy.HashSet(preHashKey + "-1", new HashEntry[] { }));
        }

        [Fact]
        public void AddStudentWhenTest()
        {
            string redisKey = preHashKey + student.Id;

            var id_When_NotExists_No = hashStudy.HashSet(redisKey, "Id", student.Id + 1, When.NotExists);
            Assert.True(id_When_NotExists_No);

            var id_When_NotExists_Yes = hashStudy.HashSet(redisKey, "Id2", student.Id + 1, When.NotExists);
            Assert.False(id_When_NotExists_Yes);

            var id_When_Exists_Yes = hashStudy.HashSet(redisKey, "Id", student.Id + 1, When.Exists);
            Assert.True(id_When_Exists_Yes);

            var id_When_Exists_No = hashStudy.HashSet(redisKey, "Id3", student.Id + 1, When.Exists);
            Assert.False(id_When_Exists_No);

            var id_When_Always_Exists = hashStudy.HashSet(redisKey, "Id", student.Id + 1, When.Always);
            Assert.True(id_When_Always_Exists);

            var id_When_Always_NotExists = hashStudy.HashSet(redisKey, "Id4", student.Id + 1, When.Always);
            Assert.True(id_When_Always_NotExists);
        }

        [Fact]
        public void AddStudentCommandFlagTest()
        {
            string redisKey = preHashKey + student.Id;
        }

        [Fact]
        public void AddStudentTest()
        {
            string redisKey = preHashKey + student.Id;
            var studentEntries = new HashEntry[]
            {
                new HashEntry("Id",1),
                new HashEntry("Name",student.Name),
                new HashEntry("Age",student.Age),
            };

            //插入Sudent
            var addHash = hashStudy.HashSet(redisKey, studentEntries, CommandFlags.None);
            Assert.True(addHash);

            //设置过期
            redisDatabase.KeyExpire(redisKey, TimeSpan.FromSeconds(5));
        }

        /// <summary>
        /// 更新学生异常测试
        /// </summary>
        [Fact]
        public void UpdateStudentExceptionTest()
        {
            string redisKey = preHashKey + student.Id;
            //不存在Key
            Assert.Throws<Exception>(()=> hashStudy.HashSet(string.Empty, "Id", -1));
        }

        /// <summary>
        /// 更新学生
        /// </summary>
        [Theory]
        [InlineData("Id", 1)]
        [InlineData("Name",1)]
        [InlineData("Age",1)]
        public void UpdateStudentTest(RedisValue fieldName, RedisValue value)
        {
            string redisKey = preHashKey + student.Id;
            var addOrUpdateOne = hashStudy.HashSet(redisKey, fieldName, value+1);
            Assert.True(addOrUpdateOne);
            addOrUpdateOne = hashStudy.HashSet(redisKey, "Name", student.Name + 1);
            Assert.True(addOrUpdateOne);
            addOrUpdateOne = hashStudy.HashSet(redisKey, "Age", student.Age + 1);
            Assert.True(addOrUpdateOne);
        }

        [Theory]
        [InlineData(-1)]
        [InlineData(-2)]
        [InlineData(-3)]
        public void DelStudentTest(int studentId)
        {
            Assert.False(redisDatabase.KeyDelete(preHashKey + studentId));
        }

        [Theory]
        [InlineData(-100)]
        public void DelStudentTest2(int studentId)
        {
            Assert.False(redisDatabase.KeyDelete(preHashKey + studentId));
        }

        [Fact]
        public void QueryOneStudentTest()
        {
            //hashStudy.AddStudent(this.student);

            //var queryStudent = hashStudy.QueryOneStudent(this.student.Id);

            //Assert.NotNull(queryStudent);
            //Assert.True(this.student.Id==queryStudent.Id);
            //Assert.True(this.student.Name == queryStudent.Name);
            //Assert.True(this.student.Age == queryStudent.Age);
        }

        [Fact]
        public void ExistStudentTest()
        {
            //Assert.True(hashStudy.ExistStudent(students[0].Id));
            //Assert.True(hashStudy.ExistStudent(students[1].Id));
            //Assert.True(hashStudy.ExistStudent(students[2].Id));
            //Assert.True(hashStudy.ExistStudent(students[3].Id));
            //Assert.True(hashStudy.ExistStudent(students[4].Id));

            //Assert.False(hashStudy.ExistStudent(-1000));
            //Assert.False(hashStudy.ExistStudent(-2000));
        }

        /// <summary>
        /// 查询所有学生
        /// </summary>
        [Fact]
        public void QueryAllStudent()
        {
            //List<Student> students = hashStudy.QueryAllStudents();

            //Assert.NotNull(students);
            //Assert.Equal(students.Count(), students.Count);
        }

        /// <summary>
        /// 清理
        /// </summary>
        public void Dispose()
        {
            if (student != null)
            {
                redisDatabase.KeyDelete(preHashKey + student.Id);
            }

            foreach (var temp in students)
            {
                redisDatabase.KeyDelete(preHashKey + temp.Id);
            }
        }

        #region  辅助方法
        public HashEntry[] StudentsToHashEntrys(Student student)
        {
            if (student == null)
            {
                return null;
            }

            var entrys = new List<HashEntry>()
            {
                new HashEntry("Id",student.Id),
                new HashEntry("Name",student.Name),
                new HashEntry("Age",student.Age),
            };
            return entrys.ToArray();
        }

        public Student HashEntrysToStudent(HashEntry[] hashEntrys)
        {
            if (hashEntrys == null)
            {
                return null;
            }

            if (hashEntrys.Length <= 0)
            {
                return null;
            }

            var student = new Student();
            foreach (var entry in hashEntrys)
            {
                switch (entry.Name)
                {
                    case "Id":
                        student.Id = entry.Value.IsInteger ? (int)entry.Value : default(int); ;
                        break;
                    case "Name":
                        student.Name = entry.Value.ToString();
                        break;
                    case "Age":
                        student.Age = entry.Value.IsInteger ? (int)entry.Value : default(int);
                        break;
                    default:
                        break;
                }
            }

            return student;
        }
        #endregion
    }
}