using greyn.Deployment;
using System;
using System.Dynamic;
using System.Collections.Generic;
using System.Reflection;
using Newtonsoft.Json;
using System.Globalization;
using Newtonsoft.Json.Converters;

namespace deployment.tests;

public class ConfigTests
{
    public class AConfigurationSubType
    {
        public double aValueType {get;set;} = 892.49;
        public int aValueTypeButNotAField = 1429;
        public Dictionary<string, double> anEnumerableType {get; set;} = new Dictionary<string, double> {{"test1", 420.69}, {"test2", 420.70}};
    }
    public class AConfigurationType
    {
        public float aValueTypeButNotAField = 156.697f;
        public string aField {get;set;} = "hi there, hello";
        public AConfigurationSubType subtyped = new AConfigurationSubType();
        public AConfigurationSubType subtyped2 = new AConfigurationSubType();
    }

    #region Config
    private const string PerfectConfiguration = @"{
        aValueTypeButNotAField: 796.651,
        aField: ""I've decided"",
        subtyped: 
        {
            aValueType: 94.298,
            aValueTypeButNotAField: 9241,
            anEnumerableType: 
            {
                ""test3"": 420.71,
                ""test4"": 420.72
            }
        },
        subtyped2: 
        {
            aValueType: 95.298,
            aValueTypeButNotAField: 9242,
            anEnumerableType: 
            {
                ""test5"": 420.73,
                ""test6"": 420.74
            }
        }
    }";
    private const string EmptyConfiguration = "{}";
    private const string MalformedConfiguration = "{{}";
    private const string InvalidValueConfiguration_00001 = @"{
        aValueTypeButNotAField = ""796.651"",
    }";
    #endregion
    
    [TearDown]
    public void TearDown()
    {
        if(File.Exists("appsettings.json"))
            File.Delete("appsettings.json");
    }
/*    

    [Test]
    public void load_doesnt_explode()
    {
        File.WriteAllText("appsettings.json", PerfectConfiguration);
        var conf = greyn.Deployment.Configurator<AConfigurationType>.Load();
        Assert.Pass();
    }
    */
    [Test]
    public void load_loads()
    {
        File.WriteAllText("appsettings.json", PerfectConfiguration);
        var conf = greyn.Deployment.Configurator<AConfigurationType>.Load();
        
        Assert.AreEqual(796.651f, conf.aValueTypeButNotAField);
        Assert.AreEqual("I've decided", conf.aField);
        Assert.AreEqual(94.298, conf.subtyped.aValueType);
        Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField);
        Assert.IsNotNull(conf.subtyped.anEnumerableType);
        Assert.AreEqual( 420.71, conf.subtyped.anEnumerableType["test3"]);
        Assert.AreEqual( 420.72, conf.subtyped.anEnumerableType["test4"]);
        Assert.IsNotNull(conf.subtyped2);
    }
    /*
    [Test]
    public void load_acceptsnullasvalue()
    {
        File.WriteAllText("appsettings.json", @"{
            aValueTypeButNotAField: 796.651,
            aField: ""I've decided"",
            subtyped: 
            {
                aValueType: 94.298,
                aValueTypeButNotAField: 9241,
                anEnumerableType: null
            },
            subtyped2: 
            {
                aValueType: 95.298,
                aValueTypeButNotAField: 9242,
                anEnumerableType: 
                {
                    ""test5"": 420.73,
                    ""test6"": 420.74
                }
            }
        }");
        
        var conf = greyn.Deployment.Configurator<AConfigurationType>.Load();
                    System.Threading.Thread.Sleep(1000);
        
        
        Assert.AreEqual(796.651f, conf.aValueTypeButNotAField);
        Assert.AreEqual("I've decided", conf.aField);
        Assert.AreEqual(94.298, conf.subtyped.aValueType);
        Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField);
        Assert.IsNotNull(conf.subtyped);

        Assert.IsNull(conf.subtyped.anEnumerableType);

        Assert.IsNotNull(conf.subtyped2);
        Assert.AreEqual(95.298, conf.subtyped2.aValueType);
        Assert.AreEqual(9242, conf.subtyped2.aValueTypeButNotAField);
        Assert.IsNotNull(conf.subtyped2.anEnumerableType);
        Assert.AreEqual( 420.73, conf.subtyped2.anEnumerableType["test5"]);
        Assert.AreEqual( 420.74, conf.subtyped2.anEnumerableType["test6"]);
    }
    [Test]
    public void load_acceptsnull_forparenttype()
    {
        File.WriteAllText("appsettings.json", @"{
            aValueTypeButNotAField: 796.651,
            aField: ""I've decided"",
            subtyped: null,
            subtyped2: 
            {
                aValueType: 95.298,
                aValueTypeButNotAField: 9242,
                anEnumerableType: 
                {
                    ""test5"": 420.73,
                    ""test6"": 420.74
                }
            }
        }");
        var conf = greyn.Deployment.Configurator<AConfigurationType>.Load();
                    System.Threading.Thread.Sleep(1000);
        
        Assert.AreEqual(796.651f, conf.aValueTypeButNotAField);
        Assert.AreEqual("I've decided", conf.aField);

        Assert.IsNull(conf.subtyped);

        Assert.IsNotNull(conf.subtyped2);
        Assert.AreEqual(95.298, conf.subtyped2.aValueType);
        Assert.AreEqual(9242, conf.subtyped2.aValueTypeButNotAField);
        Assert.IsNotNull(conf.subtyped2.anEnumerableType);
        Assert.AreEqual( 420.73, conf.subtyped2.anEnumerableType["test5"]);
        Assert.AreEqual( 420.74, conf.subtyped2.anEnumerableType["test6"]);
    }
    [Test]
    public void load_usesdefaultfornullablemissing()
    {
        File.WriteAllText("appsettings.json", @"{
            aValueTypeButNotAField: 796.651,
            
            subtyped: 
            {
                aValueType: 94.298,
                aValueTypeButNotAField: 9241,
                anEnumerableType: 
                {
                    ""test3"": 420.71,
                    ""test4"": 420.72
                }
            },
            subtyped2: 
            {
                aValueType: 95.298,
                aValueTypeButNotAField: 9242,
                anEnumerableType: 
                {
                    ""test5"": 420.73,
                    ""test6"": 420.74
                }
            }
        }");
        var conf = greyn.Deployment.Configurator<AConfigurationType>.Load();
                    System.Threading.Thread.Sleep(1000);

        Assert.AreEqual(796.651f, conf.aValueTypeButNotAField);
        Assert.AreEqual("hi there, hello", conf.aField);
        Assert.AreEqual(94.298, conf.subtyped.aValueType);
        Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField);
        Assert.IsNotNull(conf.subtyped.anEnumerableType);
        Assert.AreEqual( 420.71, conf.subtyped.anEnumerableType["test3"]);
        Assert.AreEqual( 420.72, conf.subtyped.anEnumerableType["test4"]);
        Assert.IsNotNull(conf.subtyped2);
    }
    [Test]
    public void load_usesdefaultfornonnullablemissing()
    {
        File.WriteAllText("appsettings.json", @"{
            aField: ""I've decided"",
            subtyped: 
            {
                aValueType: 94.298,
                aValueTypeButNotAField: 9241,
                anEnumerableType: 
                {
                    ""test3"": 420.71,
                    ""test4"": 420.72
                }
            },
            subtyped2: 
            {
                aValueType: 95.298,
                aValueTypeButNotAField: 9242,
                anEnumerableType: 
                {
                    ""test5"": 420.73,
                    ""test6"": 420.74
                }
            }
        }");
    
        var conf = greyn.Deployment.Configurator<AConfigurationType>.Load();
                    System.Threading.Thread.Sleep(1000);

        Assert.AreEqual(156.697f, conf.aValueTypeButNotAField);
        Assert.AreEqual("I've decided", conf.aField);
        Assert.AreEqual(94.298, conf.subtyped.aValueType);
        Assert.AreEqual(9241, conf.subtyped.aValueTypeButNotAField);
        Assert.IsNotNull(conf.subtyped.anEnumerableType);
        Assert.AreEqual( 420.71, conf.subtyped.anEnumerableType["test3"]);
        Assert.AreEqual( 420.72, conf.subtyped.anEnumerableType["test4"]);
        Assert.IsNotNull(conf.subtyped2);
    }
*/

    [Test]
    public void live_reload()
    {
        File.WriteAllText("appsettings.json", @"{
            aField: ""I've decided"",
            subtyped: 
            {
                aValueType: 94.298,
                aValueTypeButNotAField: 9241,
                anEnumerableType: 
                {
                    ""test3"": 420.71,
                    ""test4"": 420.72
                }
            },
            subtyped2: 
            {
                aValueType: 95.298,
                aValueTypeButNotAField: 9242,
                anEnumerableType: 
                {
                    ""test5"": 420.73,
                    ""test6"": 420.74
                }
            }
        }");
    
        var conf = greyn.Deployment.Configurator<AConfigurationType>.Load();
                    System.Threading.Thread.Sleep(1000);

        Assert.AreEqual(94.298, conf.subtyped.aValueType);

        var wait= true;
        greyn.Deployment.Configurator<AConfigurationType>.Changed += (sender, e) => {
            conf = (e as Configurator<AConfigurationType>.ConfigChangedEventArgs).NewConfig;
            wait = false;
        };

File.WriteAllText("appsettings.json", @"{
            aField: ""I've decided"",
            subtyped: 
            {
                aValueType: 94.301,
                aValueTypeButNotAField: 9241,
                anEnumerableType: 
                {
                    ""test3"": 420.71,
                    ""test4"": 420.72
                }
            },
            subtyped2: 
            {
                aValueType: 95.298,
                aValueTypeButNotAField: 9242,
                anEnumerableType: 
                {
                    ""test5"": 420.73,
                    ""test6"": 420.74
                }
            }
        }");

        while(wait)
        {
            System.Threading.Thread.Sleep(1000);
        }

        Assert.AreEqual(94.301, conf.subtyped.aValueType);
    }
}