using Grand.Business.Catalog.Services.Products;
using Grand.Business.Core.Interfaces.Catalog.Products;
using Grand.Data.Tests.MongoDb;
using Grand.Domain.Catalog;
using Grand.Data;
using Grand.Infrastructure.Caching;
using Grand.Infrastructure.Configuration;
using Grand.Infrastructure.Tests.Caching;
using MediatR;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Grand.Business.Catalog.Tests.Services.Products
{
    [TestClass()]
    public class SpecificationAttributeServiceTests
    {

        SpecificationAttributeService service;
        private IRepository<SpecificationAttribute> _repository;
        private IRepository<Product> _repositoryProduct;
        private MemoryCacheBase _cacheBase;
        private Mock<IMediator> _mediatorMock;
        private Mock<IProductService> _productServiceMock;

        [TestInitialize()]
        public void Init()
        {
            _repository = new MongoDBRepositoryTest<SpecificationAttribute>();
            _repositoryProduct = new MongoDBRepositoryTest<Product>();
            _mediatorMock = new Mock<IMediator>();
            _productServiceMock = new Mock<IProductService>();
            _productServiceMock.Setup(a => a.GetProductsByIds(It.IsAny<string[]>(), false)).Returns(() => Task.FromResult((IList<Product>)new List<Product> { new Product { Id = "1", Published = true }, new Product { Id = "2", Published = true }, new Product { Id = "3", Published = true } }));
            _cacheBase = new MemoryCacheBase(MemoryCacheTest.Get(), _mediatorMock.Object, new CacheConfig { DefaultCacheTimeMinutes = 1});
            service = new SpecificationAttributeService(_cacheBase, _repository, _repositoryProduct, _mediatorMock.Object);
        }       

        [TestMethod()]
        public async Task GetSpecificationAttributeByIdTest()
        {
            //Arrange
            var specificationAttribute = new SpecificationAttribute {
                Name = "test"
            };
            await service.InsertSpecificationAttribute(specificationAttribute);

            //Act
            var result = await service.GetSpecificationAttributeById(specificationAttribute.Id);

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual("test", result.Name);
        }

        [TestMethod()]
        public async Task GetSpecificationAttributeBySeNameTest()
        {
            //Arrange
            var specificationAttribute = new SpecificationAttribute {
                Name = "test",
                SeName = "test"
            };
            await service.InsertSpecificationAttribute(specificationAttribute);

            //Act
            var result = await service.GetSpecificationAttributeBySeName("test");

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual("test", result.Name);
        }

        [TestMethod()]
        public async Task GetSpecificationAttributesTest()
        {
            //Arrange
            await service.InsertSpecificationAttribute(new SpecificationAttribute());
            await service.InsertSpecificationAttribute(new SpecificationAttribute());
            await service.InsertSpecificationAttribute(new SpecificationAttribute());

            //Act
            var result = await service.GetSpecificationAttributes();

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(3, result.Count);
        }

        [TestMethod()]
        public async Task InsertSpecificationAttributeTest()
        {
            //Arrange
            var specificationAttribute = new SpecificationAttribute {
                Name = "test",
                SeName = "test"
            };

            //Act
            await service.InsertSpecificationAttribute(specificationAttribute);

            //Assert
            Assert.AreEqual(1, _repository.Table.Count());
        }

        [TestMethod()]
        public async Task UpdateSpecificationAttributeTest()
        {
            //Arrange
            var specificationAttribute = new SpecificationAttribute {
                Name = "test",
                SeName = "test"
            };
            await service.InsertSpecificationAttribute(specificationAttribute);

            //Act
            specificationAttribute.Name = "test2";
            await service.UpdateSpecificationAttribute(specificationAttribute);

            //Assert
            Assert.AreEqual("test2", _repository.Table.FirstOrDefault(x=>x.Id == specificationAttribute.Id).Name);
        }

        [TestMethod()]
        public async Task DeleteSpecificationAttributeTest()
        {
            //Arrange
            var specificationAttribute = new SpecificationAttribute {
                Name = "test",
                SeName = "test"
            };
            await service.InsertSpecificationAttribute(specificationAttribute);

            //Act
            await service.DeleteSpecificationAttribute(specificationAttribute);

            //Assert
            Assert.IsNull(_repository.Table.FirstOrDefault(x => x.Id == specificationAttribute.Id));
        }

        [TestMethod()]
        public async Task GetSpecificationAttributeByOptionIdTest()
        {
            //Arrange
            var specificationAttribute = new SpecificationAttribute {
                Name = "test",
                SeName = "test"
            };
            var attr = new SpecificationAttributeOption();
            specificationAttribute.SpecificationAttributeOptions.Add(attr);

            await service.InsertSpecificationAttribute(specificationAttribute);

            //Act
            var result = await service.GetSpecificationAttributeByOptionId(attr.Id);

            //Assert
            Assert.IsNotNull(result);
        }

        [TestMethod()]
        public async Task DeleteSpecificationAttributeOptionTest()
        {
            //Arrange
            var specificationAttribute = new SpecificationAttribute {
                Name = "test",
                SeName = "test"
            };
            var attr = new SpecificationAttributeOption();
            specificationAttribute.SpecificationAttributeOptions.Add(attr);

            await service.InsertSpecificationAttribute(specificationAttribute);

            //Act
            await service.DeleteSpecificationAttributeOption(attr);

            //Assert
            Assert.AreEqual(0, _repository.Table.FirstOrDefault(x=>x.Id == specificationAttribute.Id).SpecificationAttributeOptions.Count);
        }

        [TestMethod()]
        public async Task InsertProductSpecificationAttributeTest()
        {
            //Arrange
            var product = new Product();

            await _repositoryProduct.InsertAsync(product);

            //Act
            var attr = new ProductSpecificationAttribute();
            await service.InsertProductSpecificationAttribute(attr, product.Id);

            //Assert
            Assert.AreEqual(1, _repositoryProduct.Table.FirstOrDefault(x => x.Id == product.Id).ProductSpecificationAttributes.Count);
        }

        [TestMethod()]
        public async Task UpdateProductSpecificationAttributeTest()
        {
            //Arrange
            var product = new Product();
            await _repositoryProduct.InsertAsync(product);
            var attr = new ProductSpecificationAttribute();
            await service.InsertProductSpecificationAttribute(attr, product.Id);

            //Act
            attr.CustomName = "test";
            await service.UpdateProductSpecificationAttribute(attr, product.Id);

            //Assert
            Assert.AreEqual("test", _repositoryProduct.Table.FirstOrDefault(x => x.Id == product.Id).ProductSpecificationAttributes.FirstOrDefault(x=>x.Id == attr.Id).CustomName);
        }

        [TestMethod()]
        public async Task DeleteProductSpecificationAttributeTest()
        {
            //Arrange
            var product = new Product();
            await _repositoryProduct.InsertAsync(product);

            var attr = new ProductSpecificationAttribute();
            await service.InsertProductSpecificationAttribute(attr, product.Id);

            //Act
            await service.DeleteProductSpecificationAttribute(attr, product.Id);

            //Assert
            Assert.AreEqual(0, _repositoryProduct.Table.FirstOrDefault(x => x.Id == product.Id).ProductSpecificationAttributes.Count);

        }

        [TestMethod()]
        public async Task GetProductSpecificationAttributeCountTest()
        {
            //Arrange
            var product = new Product();
            await _repositoryProduct.InsertAsync(product);

            var attr = new ProductSpecificationAttribute();
            await service.InsertProductSpecificationAttribute(attr, product.Id);

            //Act
            var result = service.GetProductSpecificationAttributeCount();

            //Assert
            Assert.AreEqual(1,result);
        }
    }
}