using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Library.Domain.Abstract;
using Library.Domain.Entities;
using Library.Presentation.Controllers;
using System.Collections.Generic;
using System.Linq;
using Library.Presentation.Models;

namespace Library.UnitTests
{
    [TestClass]
    public class UnitTests
    {
        [TestMethod]
        public void CanGetAllBooks()
        {
            // Arrange
            // Creating mock repository
            Mock<IBookRepository> mock = new Mock<IBookRepository>();
            mock.Setup(m => m.Books).Returns(new Book[]
            {
                new Book { ID = 1, Name = "N1", Genre = "G1" },
                new Book { ID = 2, Name = "N2", Genre = "G2" },
                new Book { ID = 3, Name = "N3", Genre = "G3" },
                new Book { ID = 4, Name = "N4", Genre = "G2" },
                new Book { ID = 5, Name = "N5", Genre = "G2" },
                new Book { ID = 6, Name = "N6", Genre = "G3" }
            });
            // Creating BookController
            BookController controller = new BookController(mock.Object);

            // Action
            Book[] result = ((IEnumerable<Book>)controller.List(null).Model).OrderBy(b => b.ID).ToArray();

            // Assert
            Assert.AreEqual(result.Length, 6);
            Assert.IsTrue(result[0].Name == "N1" && result[0].Genre == "G1");
            Assert.IsTrue(result[1].Name == "N2" && result[1].Genre == "G2");
            Assert.IsTrue(result[2].Name == "N3" && result[2].Genre == "G3");
            Assert.IsTrue(result[3].Name == "N4" && result[3].Genre == "G2");
            Assert.IsTrue(result[4].Name == "N5" && result[4].Genre == "G2");
            Assert.IsTrue(result[5].Name == "N6" && result[5].Genre == "G3");
        }

        [TestMethod]
        public void CanFilterByGenre()
        {
            // Arrange
            // Creating mock repository
            Mock<IBookRepository> mock = new Mock<IBookRepository>();
            mock.Setup(m => m.Books).Returns(new Book[]
            {
                new Book { ID = 1, Name = "N1", Genre = "G1" },
                new Book { ID = 2, Name = "N2", Genre = "G2" },
                new Book { ID = 3, Name = "N3", Genre = "G3" },
                new Book { ID = 4, Name = "N4", Genre = "G2" },
                new Book { ID = 5, Name = "N5", Genre = "G2" },
                new Book { ID = 6, Name = "N6", Genre = "G3" }
            });
            // Creating BookController
            BookController controller = new BookController(mock.Object);

            // Action
            Book[] result = ((IEnumerable<Book>)controller.List("G2").Model).OrderBy(b => b.ID).ToArray();

            // Assert
            Assert.AreEqual(result.Length, 3);
            Assert.IsTrue(result[0].Name == "N2" && result[0].Genre == "G2");
            Assert.IsTrue(result[1].Name == "N4" && result[0].Genre == "G2");
            Assert.IsTrue(result[2].Name == "N5" && result[0].Genre == "G2");
        }

        [TestMethod]
        public void CanEditBook()
        {
            // Arrange
            // Creating mock repository
            Mock<IBookRepository> mock = new Mock<IBookRepository>();
            mock.Setup(m => m.Books).Returns(new Book[]
            {
                new Book { ID = 1 },
                new Book { ID = 2 },
                new Book { ID = 3 },
                new Book { ID = 4 }
            });
            // Creating BookController
            BookController controller = new BookController(mock.Object);

            // Action
            Book book1 = (Book)controller.Edit(2).Model;
            Book book2 = (Book)controller.Edit(3).Model;

            //Assert
            Assert.IsTrue(book1.ID == 2);
            Assert.IsTrue(book2.ID == 3);
        }

        [TestMethod]
        public void CannotEditNonexistentBook()
        {
            // Arrange
            // Creating mock repository
            Mock<IBookRepository> mock = new Mock<IBookRepository>();
            mock.Setup(m => m.Books).Returns(new Book[]
            {
                new Book { ID = 1 },
                new Book { ID = 3 },
                new Book { ID = 4 }
            });
            // Creating BookController
            BookController controller = new BookController(mock.Object);

            // Action
            Book book = (Book)controller.Edit(2).Model;

            // Assert
            Assert.IsNull(book);
        }

        [TestMethod]
        public void CanDeleteBook()
        {
            // Arrange
            // Create book
            Book book = new Book { ID = 3, Name = "N3", Genre = "G3" };

            // Creating mock repository
            Mock<IBookRepository> mock = new Mock<IBookRepository>();
            mock.Setup(m => m.Books).Returns(new Book[]
            {
                new Book { ID = 1, Name = "N1", Genre = "G1" },
                new Book { ID = 2, Name = "N2", Genre = "G2" },
                book
            });

            // Creating BookController
            BookController controller = new BookController(mock.Object);

            // Action
            controller.Delete(book.ID);

            //Assert
            mock.Verify(m => m.DeleteBook(book.ID));
        }

        [TestMethod]
        public void CanCreateGenres()
        {
            // Arrange
            // Creating mock repository
            Mock<IBookRepository> mock = new Mock<IBookRepository>();
            mock.Setup(m => m.Books).Returns(new Book[]
            {
                new Book { ID = 1, Name = "N1", Genre = "G3" },
                new Book { ID = 2, Name = "N2", Genre = "G2" },
                new Book { ID = 3, Name = "N3", Genre = "G1" },
                new Book { ID = 4, Name = "N4", Genre = "G2" },
                new Book { ID = 5, Name = "N5", Genre = "G2" },
                new Book { ID = 6, Name = "N6", Genre = "G1" }
            });
            // Creating NavigationController
            NavigationController controller = new NavigationController(mock.Object);

            // Action
            string[] result = ((NavigationViewModel)controller.GenresMenu().Model).Genres.ToArray();

            // Assert
            Assert.AreEqual(result.Length, 3);
            Assert.IsTrue(result[0] == "G1");
            Assert.IsTrue(result[1] == "G2");
            Assert.IsTrue(result[2] == "G3");
        }
    }
}
