﻿namespace Cars.Tests.JustMock
{
    using System;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using Cars.Contracts;
    using Cars.Tests.JustMock.Mocks;
    using Cars.Controllers;
    using System.Collections.Generic;
    using Cars.Models;


    [TestClass]
    public class CarsControllerTests
    {
        private ICarsRepository carsData;
        private CarsController controller;

        public CarsControllerTests()
            : this(new JustMockCarsRepository())
        {
        }

        public CarsControllerTests(ICarsRepositoryMock carsDataMock)
        {
            this.carsData = carsDataMock.CarsData;
        }
        
        [TestInitialize]
        public void CreateController()
        {
            this.controller = new CarsController(this.carsData);
        }

        //Write mocks for the rest of ICarsRepository interface (sorting) 
        [TestMethod]
        public void SortingByMakeWorksCorrectly()
        {
            this.controller.Sort("make");
            Telerik.JustMock.Mock.Assert(() => this.carsData.SortedByMake(), Telerik.JustMock.Occurs.AtLeast(1));
        }

        //Write mocks for the rest of ICarsRepository interface (sorting) 
        [TestMethod]
        public void SortingByYearWorksCorrectly()
        {
            this.controller.Sort("year");
            Telerik.JustMock.Mock.Assert(() => this.carsData.SortedByYear(), Telerik.JustMock.Occurs.AtLeast(1));
        }

        //Write mocks for the rest of ICarsRepository interface (sorting) 
        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void SortingByWrongGivesException()
        {
            this.controller.Sort("beer");
        }

        //Write missing unit test so that the controller functionality is fully tested
        [TestMethod]
        public void SearchingWorksCorrectly()
        {
            this.controller.Search("random string");
            Telerik.JustMock.Mock.Assert(() => this.carsData.Search("random string"), Telerik.JustMock.Occurs.AtLeast(1));
        }

        [TestMethod]
        public void IndexShouldReturnAllCars()
        {
            var model = (ICollection<Car>)this.GetModel(() => this.controller.Index());

            Assert.AreEqual(4, model.Count);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddingCarShouldThrowArgumentNullExceptionIfCarIsNull()
        {
            var model = (Car)this.GetModel(() => this.controller.Add(null));
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddingCarShouldThrowArgumentNullExceptionIfCarMakeIsNull()
        {
            var car = new Car
            {
                Id = 15,
                Make = "",
                Model = "330d",
                Year = 2014
            };

            var model = (Car)this.GetModel(() => this.controller.Add(car));
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void AddingCarShouldThrowArgumentNullExceptionIfCarModelIsNull()
        {
            var car = new Car
            {
                Id = 15,
                Make = "BMW",
                Model = "",
                Year = 2014
            };

            var model = (Car)this.GetModel(() => this.controller.Add(car));
        }

        [TestMethod]
        public void AddingCarShouldReturnADetail()
        {
            var car = new Car
            {
                Id = 15,
                Make = "BMW",
                Model = "330d",
                Year = 2014
            };

            var model = (Car)this.GetModel(() => this.controller.Add(car));

            Assert.AreEqual(1, model.Id);
            Assert.AreEqual("Audi", model.Make);
            Assert.AreEqual("A4", model.Model);
            Assert.AreEqual(2005, model.Year);
        }

        private object GetModel(Func<IView> funcView)
        {
            var view = funcView();
            return view.Model;
        }
    }
}
