using NUnit.Framework;
using System;
using System.Collections.Generic;
using TINK.Model.Bike;
using TINK.Model.Bikes.Bike;
using TINK.Model.State;

using BikeInfo = TINK.Model.Bike.BC.BikeInfo;
using BikeInfoMutable = TINK.Model.Bike.BC.BikeInfoMutable;

namespace TestTINKLib
{
    
    [TestFixture]
    public class TestBikeCollectionMutable
    {
        private class BikeInfoMutable : TINK.Model.Bike.BC.BikeInfoMutable
        {
            public BikeInfoMutable(
                int id,
                bool isDemo = false,
                IEnumerable<string> group = null,
                WheelType? wheelType = null,
                TypeOfBike? typeOfBike = null,
                string description = null,
                int? currentStationId = null,
                Uri operatorUri = null,
                TariffDescription tariffDescription = null,
                Func<DateTime> dateTimeProvider = null,
                IStateInfo stateInfo = null) : base(id, isDemo, group, wheelType, typeOfBike, description, currentStationId, operatorUri, tariffDescription, dateTimeProvider, stateInfo)
            {
            }
        }

        /// <summary> Tests the member.</summary>
        [Test]
        public void TestAdd()
        {
            var l_oColl = new BikeCollectionMutable();

            l_oColl.Add(new BikeInfoMutable(57, false, new List<string> { "TINK" },  WheelType.Two, TypeOfBike.Allround));

            Assert.Throws<Exception>(() => l_oColl.Add(new BikeInfoMutable(57, false, new List<string> { "TINK" }, WheelType.Trike, TypeOfBike.Cargo)));
        }

        [Test]
        public void TestUpdate_Null()
        {
            var l_oBikeRequested = new BikeInfoMutable(20, false, new List<string> { "TINK" }, WheelType.Trike, TypeOfBike.Allround);
            l_oBikeRequested.State.Load(new StateInfo(() => DateTime.Now, DateTime.Now, "john@long", "1234"));

            var l_oBikeColl = new BikeCollectionMutable
            {
                new BikeInfoMutable(63, false, new List<string> { "TINK" },  WheelType.Two, TypeOfBike.Allround),
                new BikeInfoMutable(57, false, new List<string> { "TINK" },  WheelType.Trike, TypeOfBike.Cargo),
                l_oBikeRequested,
            };

            // Verify initial state
            Assert.NotNull(l_oBikeColl.GetById(63));
            Assert.AreEqual(InUseStateEnum.Disposable, l_oBikeColl.GetById(57).State.Value);
            Assert.AreEqual(InUseStateEnum.Reserved, l_oBikeColl.GetById(20).State.Value);
            Assert.Null(l_oBikeColl.GetById(33));

            l_oBikeColl.Update(null);

            // Verify modified state
            Assert.Null(l_oBikeColl.GetById(63));
            Assert.Null(l_oBikeColl.GetById(57));
            Assert.Null(l_oBikeColl.GetById(20));
            Assert.Null(l_oBikeColl.GetById(33));
        }

        [Test]
        public void TestUpdate()
        {
            var l_oBikeRequested = new BikeInfoMutable(20, false, new List<string> { "TINK" }, WheelType.Trike, TypeOfBike.Allround);
            l_oBikeRequested.State.Load(new StateInfo(() => DateTime.Now, DateTime.Now, "john@long", "1234"));

            var l_oBikeColl = new BikeCollectionMutable
            {
                new BikeInfoMutable(63, false, new List<string> { "TINK" },  WheelType.Two, TypeOfBike.Allround),
                new BikeInfoMutable(57, false, new List<string> { "TINK" },  WheelType.Trike, TypeOfBike.Cargo),
                l_oBikeRequested,
            };

            // Verify initial state
            Assert.NotNull(l_oBikeColl.GetById(63)); // Will be removed
            Assert.AreEqual(InUseStateEnum.Disposable, l_oBikeColl.GetById(57).State.Value); // Will be requested
            Assert.AreEqual(InUseStateEnum.Reserved, l_oBikeColl.GetById(20).State.Value); // Will be booked
            Assert.Null(l_oBikeColl.GetById(33)); // 

            var l_oBikeResponse = new List<BikeInfo>
            {
                new BikeInfo(57, false, new List<string> {"TINK" }, WheelType.Trike, TypeOfBike.Allround, "Test description", 7, null /*operator uri*/, null, DateTime.Now, "john@long,", "1234"),
                new BikeInfo(20, false, new List<string> {"TINK" }, WheelType.Trike, TypeOfBike.Allround, "Test description", 7, null /*operator uri*/, null, DateTime.Now, "john@long,", "1234"),
                new BikeInfo(33, 7, null /*operator uri*/, null, false, new List<string> {"TINK" }, WheelType.Trike, TypeOfBike.Allround),
            };

            l_oBikeColl.Update(l_oBikeResponse);

            // Verify modified state
            Assert.Null(l_oBikeColl.GetById(63));
            Assert.AreEqual(InUseStateEnum.Booked, l_oBikeColl.GetById(57).State.Value);
            Assert.AreEqual(InUseStateEnum.Booked, l_oBikeColl.GetById(20).State.Value);
            Assert.NotNull(l_oBikeColl.GetById(33));
        }
    }
}