using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using ResourcesManager.Controllers;
using ResourcesManager.Interfaces;
using ResourcesManager.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Mvc;

namespace ResourcesManager.Controllers.Tests
{
    [TestClass()]
    public class ReservationsControllerTests
    {
        List<Reservation> expectedReservs;
        Mock<IReservationRepository> mockReservRepo;
        Mock<IUserRepository> mockUserRepo;
        Mock<IResourceRepository> mockResourceRepo;
        Mock<IStatisticRepository> mockStatRepo;
        ReservationsController reservController;

        [TestInitialize]
        public void InitializeTestData()
        {
            expectedReservs = new List<Reservation> {
                new Reservation() { Id=1, Begining = DateTime.Now, End = DateTime.Now.AddHours(1)},
                new Reservation() { Id=2, Begining = DateTime.Now, End = DateTime.Now.AddHours(1) },
                new Reservation() { Id=3, Begining = DateTime.Now, End = DateTime.Now.AddHours(1) }
            };
            mockReservRepo = new Mock<IReservationRepository>() { CallBase = true };
            mockUserRepo = new Mock<IUserRepository>() { CallBase = true };
            mockResourceRepo = new Mock<IResourceRepository>() { CallBase = true };
            mockStatRepo = new Mock<IStatisticRepository>() { CallBase = true };
            reservController = new ReservationsController(mockReservRepo.Object, mockUserRepo.Object, mockResourceRepo.Object, mockStatRepo.Object);

            mockReservRepo.Setup(m => m.GetReservations()).Returns(expectedReservs);

            mockReservRepo.Setup(m => m.GetReservationByID(It.IsAny<int>())).Returns((int id) =>
            {
                return expectedReservs.FirstOrDefault(x => x.Id == id);
            });

            mockReservRepo.Setup(m => m.InsertReservation(It.IsAny<Reservation>())).Returns((Reservation reserv) =>
            {
                expectedReservs.Add(reserv);
                return true;
            });

            mockReservRepo.Setup(m => m.UpdateReservation(It.IsAny<Reservation>())).Returns((Reservation target) =>
            {
                var reserv = expectedReservs.FirstOrDefault(x => x.Id == target.Id);
                if (reserv == null)
                {
                    return false;
                }
                reserv.Begining = target.Begining;
                reserv.End = target.End;
                reserv.Resource = target.Resource;
                reserv.ResourceId = target.ResourceId;
                reserv.User = target.User;
                return true;
            });

            mockReservRepo.Setup(m => m.DeleteReservation(It.IsAny<int>())).Returns((int id) =>
            {
                var resource = expectedReservs.FirstOrDefault(x => x.Id == id);
                if (resource == null)
                {
                    return false;
                }
                expectedReservs.Remove(resource);
                return true;
            });
        }

        [TestMethod()]
        public void Reservation_Get_Index_Test()
        {
            var result = reservController.Index();
            Assert.IsNotNull((result as ViewResult).Model);
        }

        [TestMethod()]
        public void Reservation_Get_Week_Test()
        {
            var result = reservController.Week(DateTime.Now);
            Assert.IsNotNull((result as ViewResult).Model);
        }

        [TestMethod()]
        public void Reservation_Get_Day_Test()
        {
            var result = reservController.Day(DateTime.Now);
            Assert.IsNotNull((result as ViewResult).Model);
        }

        [TestMethod()]
        public void Reservation_Get_Create_Test()
        {
            var result = reservController.Create(1);
            Assert.IsNotNull((result as ViewResult).Model);
        }

        [TestMethod()]
        public void Reservation_Post_Create_Ok_Test()
        {
            var beforeCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(3, beforeCount);

            reservController.Create(new Reservation() { Id = 4, Begining = DateTime.Now, End = DateTime.Now.AddHours(1) });

            var afterCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(4, afterCount);
        }

        [TestMethod()]
        public void Reservation_Post_Create_Fail_Test()
        {
            var beforeCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(3, beforeCount);

            reservController.Create(new Reservation() { Id = 4, Begining = DateTime.Now });

            var afterCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(3, afterCount);
        }

        [TestMethod()]
        public void Reservation_Get_Edit_Test()
        {
            var result = reservController.Edit(1);
            Assert.IsNotNull((result as ViewResult).Model);
        }

        [TestMethod()]
        public void Reservation_Post_Edit_Ok_Test()
        {
            var beforeBegin = DateTime.Now.AddDays(2);
            reservController.Edit(new Reservation() { Id = 3, Begining = DateTime.Now, End = DateTime.Now.AddHours(1) });
            object afterBegin = ((reservController.Details(3) as ViewResult).Model as Reservation).Begining;
            Assert.AreEqual(beforeBegin, afterBegin);
        }

        [TestMethod()]
        public void Reservation_Post_Edit_Fail_Test()
        {
            var beforeBegin = DateTime.Now.AddDays(2);
            reservController.Edit(new Reservation() { Id = 3, Begining = DateTime.Now });
            object afterBegin = ((reservController.Details(3) as ViewResult).Model as Reservation).Begining;
            Assert.AreEqual(beforeBegin, afterBegin);
        }

        [TestMethod()]
        public void Reservation_Get_Delete_Test()
        {
            var result = reservController.Delete(1);
            Assert.IsNotNull((result as ViewResult).Model);
        }

        [TestMethod()]
        public void Reservation_Post_Delete_Ok_Test()
        {
            var beforeCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(3, beforeCount);

            reservController.DeleteConfirmed(1);

            var afterCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(2, afterCount);
        }

        [TestMethod()]
        public void Reservation_Post_Delete_Fail_Test()
        {
            var beforeCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(3, beforeCount);

            reservController.DeleteConfirmed(8);

            var afterCount = ((reservController.Index() as ViewResult).Model as IEnumerable<Reservation>).Count();
            Assert.AreEqual(3, afterCount);
        }

        [TestCleanup]
        public void Resources_CleanUpTestData()
        {
            expectedReservs = null;
            mockReservRepo = null;
            mockUserRepo = null;
        }
    }
}