using Newtonsoft.Json;
using NUnit.Framework;
using System;
using TINK.Model.State;


namespace TestTINKLib.Fixtures.State
{
    
    [TestFixture]
    public class TestStateInfoSerializeJSON
    {
        [Test]
        public void TestSerializeJSON_Disposable()
        {
            string l_strJSONDetected;
            {
                // Create object to test.
                var l_oInUseState = new StateInfoMutable(() => new DateTime(2017, 09, 20, 23, 20, 0));

                // Serialize object and verify json
                l_strJSONDetected = JsonConvert.SerializeObject(l_oInUseState, new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Auto,
                    NullValueHandling = NullValueHandling.Ignore,
                });

                const string EXPECTED = @"
                    {
                        ""StateInfoObject"":
                        {
                            ""$type"":""TINK.Model.State.StateAvailableInfo, TINKLib""
                        }
                    }";
                Assert.AreEqual(
					TestHelper.PrepareXmlForStringCompare(EXPECTED.Replace("\n", string.Empty).Replace("\r", string.Empty)),
					TestHelper.PrepareXmlForStringCompare(l_strJSONDetected.Replace("\n", string.Empty).Replace("\r", string.Empty)));
            }

            {
                // Deserialize object
                var l_oInUseStateTarget = JsonConvert.DeserializeObject<StateInfoMutable>(l_strJSONDetected, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });

                // Verify state.
                Assert.AreEqual(InUseStateEnum.Disposable, l_oInUseStateTarget.Value);
                Assert.AreEqual("Disposable", l_oInUseStateTarget.ToString());
                Assert.IsNull(l_oInUseStateTarget.RemainingTime);
                Assert.IsNull(l_oInUseStateTarget.From);
                Assert.IsNull(l_oInUseStateTarget.MailAddress);
                Assert.IsNull(l_oInUseStateTarget.Code);
            }
        }
        [Test]
        public void TestSerializeJSON_Booked()
        {
            // Create object to test.
            var l_oInUseState = new StateInfoMutable(
                () => new DateTime(2017, 11, 18, 23, 20, 0) // Mocked time stamp returned when StateInfo- object is crated
            );

            l_oInUseState.Load(
                InUseStateEnum.Booked,
                new DateTime(2017, 11, 18, 23, 19, 0),  // Time booked at
                "heiz@mustermann",
                "173"); // Code

            Assert.AreEqual(InUseStateEnum.Booked, l_oInUseState.Value);
            Assert.AreEqual("heiz@mustermann", l_oInUseState.MailAddress);
            Assert.AreEqual(new DateTime(2017, 11, 18, 23, 19, 0), l_oInUseState.From);
            Assert.AreEqual("173", l_oInUseState.Code);

            // Verify json
            const string EXPECTED = @"
            {
                ""StateInfoObject"":
                {
                    ""$type"":""TINK.Model.State.StateOccupiedInfo, TINKLib"",
                    ""From"":""2017 - 11 - 18T23: 19:00"",
                    ""MailAddress"":""heiz @mustermann"",""Code"":""173""
                }
            }";

            var l_oDetected = JsonConvert.SerializeObject(l_oInUseState, new JsonSerializerSettings
            {
                TypeNameHandling = TypeNameHandling.Auto,
                NullValueHandling = NullValueHandling.Ignore,
            });

            Assert.AreEqual(
				TestHelper.PrepareXmlForStringCompare(EXPECTED).Replace("\n", string.Empty).Replace("\r", string.Empty),
				TestHelper.PrepareXmlForStringCompare(l_oDetected).Replace("\n", string.Empty).Replace("\r", string.Empty));

            // Deserialize object an verify state.
            var l_oStateTarget = JsonConvert.DeserializeObject<StateInfoMutable>(l_oDetected, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
            // Verify state.
            Assert.AreEqual(InUseStateEnum.Booked, l_oStateTarget.Value);
            Assert.AreEqual(new DateTime(2017, 11, 18, 23, 19, 0), l_oInUseState.From);
            Assert.AreEqual("heiz@mustermann", l_oStateTarget.MailAddress);
            Assert.AreEqual("173", l_oInUseState.Code);
        }

        [Test]
        public void TestSerializeJSON_Reserved_NoCode()
        {
            string l_strJSONDetected;

            {
                // Create object to test.
                var l_oInUseState = new StateInfoMutable(() => new DateTime(2017, 09, 21, 23, 20, 0));
                l_oInUseState.Load(
                    InUseStateEnum.Reserved,
                    new DateTime(2017, 09, 21, 23, 20, 0),
                    "heiz@mustermann");

                Assert.AreEqual(InUseStateEnum.Reserved, l_oInUseState.Value);
                Assert.AreEqual("heiz@mustermann", l_oInUseState.MailAddress);
                Assert.AreEqual(new DateTime(2017, 09, 21, 23, 20, 0), l_oInUseState.From);
                Assert.AreEqual(new TimeSpan(0, 15, 0), l_oInUseState.RemainingTime);
                Assert.IsNull(l_oInUseState.Code);

                l_strJSONDetected = JsonConvert.SerializeObject(l_oInUseState, new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Auto,
                    NullValueHandling = NullValueHandling.Ignore,
                });

                // Verify json
                const string EXPECTED = @"
                {
                    ""StateInfoObject"":
                    {
                        ""$type"":""TINK.Model.State.StateRequestedInfo, TINKLib"",
                        ""From"":""2017 - 09 - 21T23: 20:00"",
                        ""MailAddress"":""heiz @mustermann""
                    }
                }";

                Assert.AreEqual(
					TestHelper.PrepareXmlForStringCompare(EXPECTED.Replace("\n", string.Empty).Replace("\r", string.Empty)),
					TestHelper.PrepareXmlForStringCompare(l_strJSONDetected.Replace("\n", string.Empty).Replace("\r", string.Empty)));
            }

            {
                // Deserialize object an verify state.
                var l_oStateTarget = JsonConvert.DeserializeObject<StateInfoMutable>(l_strJSONDetected, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
                // Verify state.
                Assert.AreEqual(InUseStateEnum.Reserved, l_oStateTarget.Value);
                Assert.AreEqual("heiz@mustermann", l_oStateTarget.MailAddress);
                Assert.AreEqual(new DateTime(2017, 09, 21, 23, 20, 0), l_oStateTarget.From);
                Assert.IsNull(l_oStateTarget.RemainingTime, "If deserialized date time provider is DateTime.Now. With a from- value of 2017-11- ... there is no more time remaining.");
                Assert.IsNull(l_oStateTarget.Code);
            }
        }

        [Test]
        public void TestSerializeJSON_Reserved()
        {
            string l_strJSONDetected;

            {
                Func<DateTime> l_oNow = () => new DateTime(2017, 11, 18, 23, 18, 0);
                // Create object to test.
                var l_oInUseState = new StateInfoMutable(l_oNow);

                DateTime l_oFrom = new DateTime(2017, 11, 18, 23, 18, 0);
                l_oInUseState.Load(
                    InUseStateEnum.Reserved,
                    l_oFrom,
                    "z@C",
                    "01815A");

                Assert.AreEqual(InUseStateEnum.Reserved, l_oInUseState.Value);
                Assert.AreEqual("z@C", l_oInUseState.MailAddress);
                Assert.AreEqual(new DateTime(2017, 11, 18, 23, 18, 0), l_oInUseState.From);
                Assert.AreEqual((new TimeSpan(0, 15, 0)).Subtract(l_oNow().Subtract(l_oFrom)), l_oInUseState.RemainingTime);
                Assert.AreEqual("01815A", l_oInUseState.Code);

                l_strJSONDetected = JsonConvert.SerializeObject(l_oInUseState, new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Auto,
                    NullValueHandling = NullValueHandling.Ignore,
                });

                // Verify json
                const string EXPECTED = @"
                {
                    ""StateInfoObject"":
                    {
                        ""$type"":""TINK.Model.State.StateRequestedInfo, TINKLib"",
                        ""From"":""2017 - 11 - 18T23: 18:00"",
                        ""MailAddress"":""z @C"",
                        ""Code"":""01815A""
                    }
                }";

                Assert.AreEqual(
					TestHelper.PrepareXmlForStringCompare(EXPECTED.Replace("\n", string.Empty).Replace("\r", string.Empty)),
					TestHelper.PrepareXmlForStringCompare(l_strJSONDetected.Replace("\n", string.Empty).Replace("\r", string.Empty)));
            }

            {
                // Deserialize object an verify state.
                var l_oStateTarget = JsonConvert.DeserializeObject<StateInfoMutable>(l_strJSONDetected, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
                // Verify state.
                Assert.AreEqual(InUseStateEnum.Reserved, l_oStateTarget.Value);
                Assert.AreEqual("z@C", l_oStateTarget.MailAddress);
                Assert.AreEqual(new DateTime(2017, 11, 18, 23, 18, 0), l_oStateTarget.From);
                Assert.IsNull(l_oStateTarget.RemainingTime, "If deserialized date time provider is DateTime.Now. With a from- value of 2017-11- ... there is no more time remaining.");
                Assert.AreEqual("01815A", l_oStateTarget.Code);
            }
        }
    }
}