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

namespace ResourcesManager.Controllers.Tests
{
    [TestClass()]
    public class ResourcesControllerTests
    {
        List<Resource> expectedResources;
        Mock<IResourceRepository> mockResourceRepo;
        Mock<IUserRepository> mockUserRepo;
        ResourcesController resourcesController;

        [TestInitialize]
        public void InitializeTestData()
        {
            expectedResources = new List<Resource> {
                new Resource() { Id=1, Name = "Béla", AssetTag = "4jk5h23k", IsShared = false },
                new Resource() { Id=2, Name = "Lajos", AssetTag = "6546", IsShared = true },
                new Resource() { Id=3, Name = "Kati", AssetTag = "u547547", IsShared = false }
            };
            mockResourceRepo = new Mock<IResourceRepository>() { CallBase = true };
            mockUserRepo = new Mock<IUserRepository>() { CallBase = true };
            resourcesController = new ResourcesController(mockResourceRepo.Object, mockUserRepo.Object);

            mockResourceRepo.Setup(m => m.GetResouces()).Returns(expectedResources);

            mockResourceRepo.Setup(m => m.GetResourceByID(It.IsAny<int>())).Returns((int id) => 
            {
                return expectedResources.FirstOrDefault(x => x.Id == id);
            });

            mockResourceRepo.Setup(m => m.InsertResouce(It.IsAny<Resource>())).Returns((Resource resource) =>
            {
                expectedResources.Add(resource);
                return true;
            });

            mockResourceRepo.Setup(m => m.UpdateResouce(It.IsAny<Resource>())).Returns((Resource target) =>
            {
                var resource = expectedResources.FirstOrDefault(x => x.Id == target.Id);
                if (resource == null)
                {
                    return false;
                }
                resource.Name = target.Name;
                resource.Description = target.Description;
                resource.AssetTag = target.AssetTag;
                resource.ImagePath = target.ImagePath;
                resource.IsShared = target.IsShared;
                resource.TimeLimit = target.TimeLimit;
                resource.Reservation = target.Reservation;
                resource.Users = target.Users;
                return true;
            });

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

        [TestMethod()]
        public void Resources_Get_Index_Test()
        {
            var result = resourcesController.Index();
            Assert.IsNotNull((result as ViewResult).Model);

        }

        [TestMethod()]
        public void Resources_Get_Details_Ok_Test()
        {
            var result = resourcesController.Details(1);
            Assert.IsNotNull((result as ViewResult).Model);
        }

        [TestMethod()]
        public void Resources_Get_Details_Fail_Test()
        {
            var result = resourcesController.Details(null) as HttpStatusCodeResult;
            Assert.IsNotNull(result);
            Assert.AreEqual(result.StatusCode, 400);
        }

        [TestMethod()]
        public void Resources_Get_Create_Test()
        {
            var result = resourcesController.Create();
            Assert.IsNotNull(result);
        }

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

            resourcesController.Create(new Resource() {Id=4, Name = "Sanyi", AssetTag = "hh564he56", IsShared = false });

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

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

            resourcesController.Create(new Resource() { Name = "Sanyi", IsShared = false });

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

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

        [TestMethod()]
        public void Resources_Post_Edit_Ok_Test()
        {
            string beforeName = "Katika";
            resourcesController.Edit(new Resource() { Id = 3, Name = beforeName, AssetTag = "u547547", IsShared = false });
            object afterName = ((resourcesController.Details(3) as ViewResult).Model as Resource).Name;
            Assert.AreEqual(beforeName, afterName);
        }

        [TestMethod()]
        public void Resources_Post_Edit_Fail_Test()
        {
            string beforeName = "Katika";
            resourcesController.Edit(new Resource() { Id = 3, Name = beforeName, IsShared = false });
            object afterName = ((resourcesController.Details(3) as ViewResult).Model as Resource).Name;
            Assert.AreNotEqual(beforeName, afterName);
        }

        [TestMethod()]
        public void Resources_Get_Delete_Test()
        {
            var result = resourcesController.Delete(1);
            Assert.AreEqual((result as ViewResult).Model, expectedResources[0]);
        }

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

            resourcesController.DeleteConfirmed(1);

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

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

            resourcesController.DeleteConfirmed(8);

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

        [TestCleanup]
        public void Resources_CleanUpTestData()
        {
            expectedResources = null;
            mockResourceRepo = null;
            mockUserRepo = null;
        }
    }
}