namespace OptionStudy.Next
{
    /// <summary>
    /// 5.2 配置模型
    /// IConfiguration 测试
    /// </summary>
    public class IConfigurationTest : IDisposable
    {
        private readonly ITestOutputHelper testOutput;

        private IDictionary<string, string?> sharedMemoryData = new Dictionary<string, string?>()
        {
            ["AppName"] = "MemoryAppName",
            ["AppVersion"] = "0.0.0.1",
            ["EMail:ReceiveAddress"] = "memory@163.com",
            ["EMail:Recipient"] = "memory",
        };

        public IConfigurationTest(ITestOutputHelper testOutputHelper)
        {
            testOutput = testOutputHelper;
        }

        /// <summary>
        /// 获取 IConfigrution 扩展方法添加数据源
        /// IConfigrution 极少直接实例化,通常是由 IConfigurationBuilder 设置之后,调用 Build 方法构建出来的。
        /// </summary>
        [Fact]
        public void IConfigrution_Build_AddInMemoryCollection_Test()
        {
            var builder = new ConfigurationBuilder();
            IConfigurationRoot? configrution = builder.AddInMemoryCollection(sharedMemoryData).Build();

            Assert.NotNull(configrution);
            Assert.Single(configrution.Providers);
            Assert.True(configrution["AppName"] == "MemoryAppName");
        }

        /// <summary>
        /// 获取 IConfigrution
        /// ConfigurationBuilder Add()方法
        /// </summary>
        [Fact]
        public void IConfigrution_Build_Add_Test()
        {
            //内存配置源
            MemoryConfigurationSource source = new MemoryConfigurationSource()
            {
                InitialData = sharedMemoryData,
            };

            var configrution = new ConfigurationBuilder().Add(source).Build();

            Assert.NotNull(configrution);
            Assert.Equal(3, configrution.GetChildren().Count());
        }

        /// <summary>
        /// 获取 IConfigrution 手动添加配置源
        /// </summary>
        [Fact]
        public void IConfigrution_Build_AddT_Test()
        {
            var configrution = new ConfigurationBuilder()
                .Add<MemoryConfigurationSource>(source =>
                {
                    source.InitialData = sharedMemoryData;
                })
                .Build();

            Assert.NotNull(configrution);
            Assert.Equal(3, configrution.GetChildren().Count());
        }

        /// <summary>
        /// IConfigrutionRoot
        /// </summary>
        [Fact]
        public void IConfigrutionRoot_Test()
        {
            var builder = new ConfigurationBuilder();
            var root = builder.AddInMemoryCollection(sharedMemoryData).Build();

            Assert.NotNull(root);
        }

        /// <summary>
        /// IConfigrutionRoot Provider
        /// </summary>
        [Fact]
        public void IConfigrutionRoot_Provider_Test()
        {
            var root = new ConfigurationBuilder().AddInMemoryCollection(sharedMemoryData).Build();
            Assert.NotNull(root);

            var providers = root.Providers;
            Assert.Single(providers);

            var memoryProvider = providers.FirstOrDefault() as MemoryConfigurationProvider;

            Assert.NotNull(memoryProvider);
        }

        /// <summary>
        /// IConfigrutionRoot 重新加载
        /// 内存配置源
        /// Load() 方法为空,重新加载不起作用。
        /// 通过 Add 添加的配置项,一直保留到程序结束
        /// </summary>
        [Fact]
        public void IConfigrutionRoot_Reload_MemorySource_Test()
        {
            var builder = new ConfigurationBuilder();
            var root = builder.AddInMemoryCollection(sharedMemoryData).Build();
            var provider = root.Providers.First() as MemoryConfigurationProvider;

            //设置:改变数据源
            provider?.Set("AppName", "UpdateAppName");
            Assert.Equal("UpdateAppName", root["AppName"]);

            // MemoryConfigurationProvider 有个特别的 Add 方法
            provider?.Add("AddKey", "AddValue");
            Assert.Equal("AddValue", root["AddKey"]);

            //重新加载:改变的值不会恢复,一直保持
            root.Reload();

            //MemoryConfigurationProvider Load()方法,什么都没做,所以更新值被保留
            provider?.Load();

            Assert.Equal("UpdateAppName", root["AppName"]);
            Assert.NotEqual("MemoryAppName", root["AppName"]);
        }

        /// <summary>
        /// IConfigrutionRoot 重新加载
        /// 命令行配置源:重新加载后,修改的配置项被恢复
        /// 环境变量与文件类配置源,同理也会被恢复
        /// </summary>
        [Fact]
        public void IConfigrutionRoot_Reload_ComandSource_Test()
        {
            var builder = new ConfigurationBuilder();
            var root = builder.AddCommandLine(new string[] { "AppName=CommandAppName", "EMail:ReceiveAddress=command@163.com" }).Build();

            //设置:改变数据源
            var provider = root.Providers.First() as CommandLineConfigurationProvider;
            provider?.Set("AppName", "UpdateAppName");
            Assert.Equal("UpdateAppName", root["AppName"]);

            //重新加载:改变的值被恢复
            root.Reload();

            Assert.NotEqual("UpdateAppName", root["AppName"]);
            Assert.Equal("CommandAppName", root["AppName"]);
        }

        /// <summary>
        /// IConfigrutionRoot 索引
        /// 功能和规则同 GetSection 方法
        /// </summary>
        [Fact]
        public void IConfigrutionRoot_Index_Test()
        {
            var root = new ConfigurationBuilder().AddInMemoryCollection(sharedMemoryData).Build();

            Assert.NotNull(root);

            Assert.Equal("MemoryAppName", root["AppName"]);
            Assert.Equal("0.0.0.1", root["AppVersion"]);
            Assert.Equal("memory@163.com", root["EMail:ReceiveAddress"]);
            Assert.Equal("memory", root["EMail:Recipient"]);
            Assert.Null(root["NotExcits_xxxxxxx"]);
            Assert.Null(root["EMail:NotExcits_xxxxxxx"]);
        }

        /// <summary>
        /// IConfigrutionRoot GetSection
        /// </summary>
        [Fact]
        public void IConfigrutionRoot_GetSection_Test()
        {
            IDictionary<string, string?> data = new Dictionary<string, string?>()
            {
                ["A:B:C:D"] = "ABCD",
            };

            var root = new ConfigurationBuilder().AddInMemoryCollection(data).Build();

            Assert.NotNull(root);

            var sectionABCD1 = root.GetSection("A:B:C:D");
            var sectionABCD2 = root.GetSection("A:B:C").GetSection("D");
            var sectionABCD3 = root.GetSection("A:B").GetSection("C:D");
            var sectionABCD4 = root.GetSection("A").GetSection("B").GetSection("C").GetSection("D");

            //虽然均指向同一个配置节点,但是引用对象却不同:因为 GetSection() 总是会创建新的 IConfigrutionSection 对象
            Assert.Equal("ABCD", sectionABCD1.Value);
            Assert.Equal("ABCD", sectionABCD2.Value);
            Assert.Equal("ABCD", sectionABCD3.Value);
            Assert.Equal("ABCD", sectionABCD4.Value);

            Assert.NotEqual(sectionABCD1, sectionABCD2);
            Assert.NotEqual(sectionABCD3, sectionABCD4);

            //获取不存在的节点时,不是返回null,而是正常返回节点,只是节点的值为null
            var sectionNoExsit = root.GetSection("NoExsit");

            Assert.NotNull(sectionNoExsit);
        }

        /// <summary>
        /// IConfigrutionRoot GetChildren
        /// 获取直接子代配置子节
        /// </summary>
        [Fact]
        public void IConfigrutionRoot_GetChildren_Test()
        {
            var root = new ConfigurationBuilder().AddInMemoryCollection(sharedMemoryData).Build();

            var chields = root.GetChildren().ToList();

            //个数是3,而不是4:获取的是直接子代配置子节点
            //第三个是 EMail 节点(EMail:ReceiveAddress与EMail:Recipient的父节点)
            Assert.Equal(3,chields.Count);

            Assert.Equal("MemoryAppName", chields[0].Value);
            Assert.Null( chields[2].Value);

            Assert.Equal(2, chields[2].GetChildren().Count());
        }

        public void Dispose()
        {

        }
    }
}