using NUnit.Framework;
using System;
using TINK.Model.Bike;
using TINK.Model.User;
using TINK.Model.User.Account;
using TINK.ViewModel;

using Xamarin.Forms;
using TINK.Model.State;
using Rhino.Mocks;
using System.Collections.Generic;

using BikeInfoMutable = TINK.Model.Bike.BC.BikeInfoMutable;
using TINK.ViewModel.Bikes;
using TINK.Model.Device;
using TestFramework.Model.User.Account;

namespace UITest.Fixtures.ViewModel
{

    [TestFixture]
    public class TestBikeAtStationViewModel
    {
        private class BikeInfoMutable : TINK.Model.Bike.BC.BikeInfoMutable
        {
            public BikeInfoMutable(
                string p_iId,
                bool p_bIsDemo = false,
                IEnumerable<string> p_oGroup = null,
                WheelType? p_eWheelType = null,
                TypeOfBike? p_eTypeOfBike = null,
                string description = null,
                string p_strCurrentStationName = null,
                Uri operatorUri = null,
                Func<DateTime> p_oDateTimeProvider = null,
                IStateInfo stateInfo = null) : base(p_iId, p_bIsDemo, p_oGroup, p_eWheelType, p_eTypeOfBike, description, p_strCurrentStationName, operatorUri, null, p_oDateTimeProvider, stateInfo)
            {
            }
        }
        /// <summary>
        /// Tests base class functionaltiy by using child.
        /// </summary>
        [Test]
        public void TestStateText_NotLoggedIn()
        {
            var l_oBike = new BikeInfoMutable("2", false, new List<string> { "TINK" }, WheelType.Two, TypeOfBike.Cargo);

            var l_oStoreMock = new StoreMock(); // Account without user name, password and cookie

            var l_oUser = new User(
                    l_oStoreMock,
                    l_oStoreMock.Load().Result,
                    "123456789"); // Device identifier

            // Verify prerequisites
            Assert.AreEqual(InUseStateEnum.Disposable, l_oBike.State.Value);
            Assert.IsFalse(l_oUser.IsLoggedIn);

            // Verify view model.
            var l_oViewModel = new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
                null,
                null,
                null,
                null,
                NSubstitute.Substitute.For<ISmartDevice>(),
                null,
                l_oBike, 
                l_oUser, 
                new MyBikeInUseStateInfoProvider(),
                MockRepository.GenerateStub<IBikesViewModel>());

            Assert.AreEqual("2", l_oViewModel.Name);
            Assert.AreEqual("", l_oViewModel.DisplayId);
            Assert.AreEqual("2", l_oViewModel.Id);
            Assert.AreEqual("Available.", l_oViewModel.StateText);
            Assert.AreEqual(Color.Default, l_oViewModel.StateColor);
        }

        /// <summary>
        /// Tests base class functionaltiy by using child.
        /// </summary>
        [Test]
        public void TestStateText_LoggedIn_Reserved()
        {
            var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Reserved(
                (bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
                    null,
                    null,
                    null,
                    null,
                    NSubstitute.Substitute.For<ISmartDevice>(),
                    null,
                    bike, 
                    user, 
                    new BikeAtStationInUseStateInfoProvider(),
                    MockRepository.GenerateStub<IBikesViewModel>()));

            Assert.AreEqual("Still 15 minutes reserved.", l_oViewModel.StateText);
        }

        /// <summary>
        /// Tests base class functionaltiy by using child.
        /// </summary>
        [Test]
        public void TestStateText_LoggedIn_ReservedWithCopriConnect()
        {
            var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_ReservedWithCopriConnect(
                (bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
                    null,
                    null,
                    null,
                    null,
                    NSubstitute.Substitute.For<ISmartDevice>(),
                    null,
                    bike, 
                    user, 
                    new BikeAtStationInUseStateInfoProvider(),
                    MockRepository.GenerateStub<IBikesViewModel>()));

            Assert.AreEqual("Code 4asdfA, still 7 minutes reserved.", l_oViewModel.StateText);
        }

        /// <summary>
        /// Tests base class functionaltiy by using child.
        /// </summary>
        [Test]
        public void TestStateText_LoggedIn_Booked()
        {
            var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Booked(
                (bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
                    null,
                    null,
                    null,
                    null,
                    NSubstitute.Substitute.For<ISmartDevice>(),
                    null,
                    bike, 
                    user, 
                    new BikeAtStationInUseStateInfoProvider(),
                    MockRepository.GenerateStub<IBikesViewModel>()));

            Assert.AreEqual(
                $"Code 4asdfA, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}.",
                l_oViewModel.StateText);
        }

        /// <summary>
        /// Tests base class functionaltiy by using child.
        /// </summary>
        [Test]
        public void TestStateText_LoggedIn_ReservedBySomeoneElse()
        {
            var l_oBike = new BikeInfoMutable("2", false, new List<string> { "TINK" }, WheelType.Two, TypeOfBike.Cargo, "Test description", "3");

            l_oBike.State.Load(
                InUseStateEnum.Reserved,
                new DateTime(2017, 10, 24, 21, 49, 3),
                "ragu@gnu-systems.de",
                "4asdfA");

            var l_oStoreMock = new StoreMock(new Account("john@long", "123456789" /* password */, "987654321" /* session cookie */, new List<string> { "TINK" }));

            var l_oViewModel = new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
                null,
                null,
                null,
                null,
                NSubstitute.Substitute.For<ISmartDevice>(),
                null,
                l_oBike,
                new User(
                    l_oStoreMock,
                    l_oStoreMock.Load().Result,
                    "123456789"), // Device id
                new BikeAtStationInUseStateInfoProvider(),
                MockRepository.GenerateStub<IBikesViewModel>()); 

            Assert.AreEqual("Test description", l_oViewModel.Name);
            Assert.AreEqual("2", l_oViewModel.DisplayId);
            Assert.AreEqual("2", l_oViewModel.Id);
            Assert.AreEqual("Fahrrad bereits reserviert durch anderen Nutzer.", l_oViewModel.StateText);
            Assert.AreEqual(Color.Red, l_oViewModel.StateColor);
        }

        /// <summary>
        /// Tests base class functionaltiy by using child.
        /// </summary>
        [Test]
        public void TestStateText_LoggedIn_BookedBySomeoneElse()
        {
            var l_oBike = new BikeInfoMutable("2", false, new List<string> { "TINK" }, WheelType.Two, TypeOfBike.Cargo, "Test description", "3");

            l_oBike.State.Load(
                InUseStateEnum.Booked,
                new DateTime(2017, 10, 24, 21, 49, 3),
                "ragu@gnu-systems.de",
                "4asdfA");

            var l_oStoreMock = new StoreMock(new Account("john@long", "123456789" /* password */, "987654321" /* session cookie */, new List<string> { "TINK" }));

            var l_oViewModel = new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
                null,
                null,
                null,
                null,
                NSubstitute.Substitute.For<ISmartDevice>(),
                null,
                l_oBike,
                new User(
                    l_oStoreMock,
                    l_oStoreMock.Load().Result,
                    "123456789"),
                new BikeAtStationInUseStateInfoProvider(),
                MockRepository.GenerateStub<IBikesViewModel>());

            Assert.AreEqual("Test description", l_oViewModel.Name);
            Assert.AreEqual("2", l_oViewModel.DisplayId);
            Assert.AreEqual("2", l_oViewModel.Id);
            Assert.AreEqual("Fahrrad bereits gebucht durch anderen Nutzer.", l_oViewModel.StateText);
            Assert.AreEqual(Color.Red, l_oViewModel.StateColor);
        }
    }
}