using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
using System.Linq;

namespace Falcon.SugarApi.Test
{
    [TestClass]
    public class ObjectExtendTest
    {
        [TestMethod]
        public void CloneToTest() {
            var s = new SourceClass { };
            var t = new TargetClass { };
            t.ica.ItemA = "itemb";

            Assert.IsTrue(t.ica.ItemA == "itemb");

            var r = s.CloneTo(t);

            Assert.IsNotNull(s);
            Assert.IsNotNull(r);
            Assert.IsNotNull(t);
            Assert.IsTrue(s.ia == t.ia,$"a.id:{s.ia},t.ia:{t.ia}");
            Assert.IsTrue(t.ia == 1);
            Assert.IsTrue(s.sa == t.sa);
            Assert.IsTrue(s.sc == "sc");
            Assert.IsTrue(t.sd == "sd");
            Assert.IsTrue(s.ica.ItemA == "itema");
            Assert.IsTrue(t.ica.ItemA == "itema");
            Assert.IsTrue(t.ica.Equals(s.ica));
        }

        [TestMethod]
        public void ChangeTypeTest() {
            int s = 1;
            var t = s.ChangeType(typeof(int));
            Console.WriteLine(t.GetType().FullName);
            Assert.IsTrue(t.GetType().Equals(typeof(int)));
        }
        /// <summary>
        /// 测试对象为null则会抛出异常
        /// </summary>
        [TestMethod]
        public void ThrowNullExceptionWhenNullTest() {
            var obj = new object();
            obj.ThrowNullExceptionWhenNull();
            obj = null;
            Assert.ThrowsException<ArgumentNullException>(() => obj.ThrowNullExceptionWhenNull());
        }

        /// <summary>
        /// 测试对象属性扩展
        /// </summary>
        [TestMethod]
        public void ExtendPropertyTest() {
            var obj = new ExtendPropertyTestClass {
                Id = 1,Name = "Falcon",Sex = null,Count = "count"
            };
            var ep = obj.ExpandProperties();
            Assert.IsNotNull(ep);
            Assert.IsTrue(ep.Count() == 4);
            Assert.IsTrue(ep.Select(m => m.Name).Distinct().Count() == 4);
            foreach(var p in ep) {
                if(p.Name == "Id") {
                    Assert.IsTrue(p.Type == typeof(int));
                    Assert.IsTrue(p.Value.Equals(obj.Id));
                    continue;
                }
                if(p.Name == "Name") {
                    Assert.IsTrue(p.Type == typeof(string));
                    Assert.IsTrue(p.Value.Equals(obj.Name));
                    continue;
                }
                if(p.Name == "Sex") {
                    Assert.IsTrue(p.Type == typeof(string));
                    Assert.IsTrue(p.Value == null);
                    continue;
                }
                if(p.Name == "Count") {
                    Assert.IsTrue(p.Type == typeof(string));
                    Assert.IsTrue(p.Value == "count");
                    continue;
                }
            }
        }

        /// <summary>
        /// 是否为空测试
        /// </summary>
        [TestMethod]
        public void IsNullTest() {
            object obj = null;
            Assert.IsTrue(obj.IsNull());
            Assert.IsFalse(obj.IsNotNull());

            obj = new object();
            Assert.IsTrue(obj.IsNotNull());
            Assert.IsFalse(obj.IsNull());

            object? obj1 = null;
            Assert.IsTrue(obj1.IsNull());
            Assert.IsFalse(obj1.IsNotNull());

            obj1 = new object();
            Assert.IsTrue(obj1.IsNotNull());
            Assert.IsFalse(obj1.IsNull());
        }

        /// <summary>
        /// 获取调用堆栈测试
        /// </summary>
        [TestMethod]
        public void GetStackTraceTest() {
            var r = this.GetStackTrace().ToArray();
            Assert.IsNotNull(r);
            foreach(var i in r) {
                Console.WriteLine(i.Name);
            }
            Assert.IsTrue(r.Count() > 0);
            Assert.IsTrue(r[0].Name == "GetStackTrace");
            Assert.IsTrue(r[1].Name == "GetStackTraceTest");

            var fullCount = this.GetStackTrace(full: true).Count();
            var nFullCount = this.GetStackTrace(full: false).Count();
            Assert.IsTrue(fullCount > nFullCount);

        }

        /// <summary>
        /// 测试In方法
        /// </summary>
        [TestMethod]
        public void ObjectInTest() {
            string obj = "abc";
            Assert.IsTrue(obj.In("eee","abc","1231"));
            Assert.IsFalse(obj.In("2313","eeee"));

            var o1 = new object();
            Assert.IsTrue(o1.In(o1));
            Assert.IsFalse(o1.In(new object(),new object()));

            var o2 = new ObjWithComparable { val = 1 };
            var o22 = new ObjWithComparable { val = 1 };
            var o23 = new ObjWithComparable { val = 1 };
            Assert.IsTrue(o2.In(o22,o23));
        }

        /// <summary>
        /// 应用动态比较的方式比较对象是否在另外两个对象区间。
        /// </summary>
        [TestMethod]
        public void ObjectBetweenTest() {
            Assert.IsTrue(1.Between(0,2));
            Assert.IsFalse(3.Between(0,1));
            var now = DateTime.Now;
            Assert.IsTrue(now.Between(now.AddSeconds(-1),now.AddSeconds(1)));
            Assert.IsFalse(now.Between(now.AddSeconds(1),now.AddSeconds(2)));
        }

    }
    /// <summary>
    /// 扩展属性测试类
    /// </summary>
    public class ExtendPropertyTestClass
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string? Sex { get; set; }
        public string Count { private get; set; }
    }

    public class SourceClass
    {
        public int ia { get; set; } = 1;
        public string sa { get; set; } = "sa";
        public string sc { get; set; } = "sc";
        public ItemClass ica { get; set; } = new ItemClass();
    }

    public class TargetClass
    {
        public int ia { get; set; }
        public string sa { get; set; }
        public string sd { get; set; } = "sd";
        public ItemClass ica { get; set; } = new ItemClass();
    }

    public class ItemClass
    {
        public string ItemA { get; set; } = "itema";
    }

    public class ObjWithComparable:IComparable<ObjWithComparable>
    {
        public int val { get; set; }

        public int CompareTo(ObjWithComparable? other) {
            return this.val - other.val;
        }
    }
}