using Grand.Business.Checkout.Services.Orders;
using Grand.Data.Tests.MongoDb;
using Grand.Data;
using Grand.Domain.Orders;
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.Checkout.Tests.Services.Orders
{
    [TestClass()]
    public class OrderTagServiceTests
    {
        private OrderTagService _service;
        private IRepository<OrderTag> _orderTagRepository;
        private IRepository<Order> _orderRepository;
        private MemoryCacheBase _cacheBase;
        private Mock<IMediator> _mediatorMock;

        [TestInitialize()]
        public void Init()
        {
            _orderTagRepository = new MongoDBRepositoryTest<OrderTag>();
            _orderRepository = new MongoDBRepositoryTest<Order>();

            _mediatorMock = new Mock<IMediator>();

            _cacheBase = new MemoryCacheBase(MemoryCacheTest.Get(), _mediatorMock.Object, new CacheConfig { DefaultCacheTimeMinutes = 1});

            _service = new OrderTagService(_orderTagRepository, _orderRepository, _cacheBase, _mediatorMock.Object);
        }

        [TestMethod()]
        public async Task GetAllOrderTagsTest()
        {
            //Arrange
            await _orderTagRepository.InsertAsync(new OrderTag());
            await _orderTagRepository.InsertAsync(new OrderTag());
            await _orderTagRepository.InsertAsync(new OrderTag());

            //Act
            var result = await _service.GetAllOrderTags();

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

        [TestMethod()]
        public async Task GetOrderTagByIdTest()
        {
            //Arrange
            await _orderTagRepository.InsertAsync(new OrderTag { Id = "1"});
            await _orderTagRepository.InsertAsync(new OrderTag());
            await _orderTagRepository.InsertAsync(new OrderTag());

            //Act
            var result = await _service.GetOrderTagById("1");

            //Assert
            Assert.IsNotNull(result);
        }

        [TestMethod()]
        public async Task GetOrderTagByNameTest()
        {
            //Arrange
            await _orderTagRepository.InsertAsync(new OrderTag { Id = "1", Name = "test" });
            await _orderTagRepository.InsertAsync(new OrderTag());
            await _orderTagRepository.InsertAsync(new OrderTag());

            //Act
            var result = await _service.GetOrderTagByName("test");

            //Assert
            Assert.IsNotNull(result);
        }

        [TestMethod()]
        public async Task InsertOrderTagTest()
        {
            //Act
            await _service.InsertOrderTag(new OrderTag());

            //Assert
            Assert.IsTrue(_orderTagRepository.Table.Any());
        }

        [TestMethod()]
        public async Task UpdateOrderTagTest()
        {
            //Arrange
            var orderTag = new OrderTag();
            await _orderTagRepository.InsertAsync(orderTag);

            //Act
            orderTag.Name = "test";
            await _service.UpdateOrderTag(orderTag);

            //Assert
            Assert.IsTrue(_orderTagRepository.Table.FirstOrDefault(x=>x.Id == orderTag.Id).Name == "test");
        }

        [TestMethod()]
        public async Task DeleteOrderTagTest()
        {
            //Arrange
            var orderTag = new OrderTag();
            await _orderTagRepository.InsertAsync(orderTag);

            //Act
            await _service.DeleteOrderTag(orderTag);

            //Assert
            Assert.IsFalse(_orderTagRepository.Table.FirstOrDefault(x => x.Id == orderTag.Id)?.Name == "test");
        }

        [TestMethod()]
        public async Task AttachOrderTagTest()
        {
            //Arrange
            var orderTag = new OrderTag();
            await _orderTagRepository.InsertAsync(orderTag);
            var order = new Order();
            await _orderRepository.InsertAsync(order);
            
            //Act
            await _service.AttachOrderTag(orderTag.Id, order.Id);

            //Assert
            Assert.IsTrue(_orderRepository.Table.FirstOrDefault(x => x.Id == order.Id).OrderTags.Any(z => z == orderTag.Id));
            Assert.IsTrue(_orderTagRepository.Table.FirstOrDefault(x => x.Id == orderTag.Id).Count == 1);
        }

        [TestMethod()]
        public async Task DetachOrderTagTest()
        {
            //Arrange
            var orderTag = new OrderTag();
            await _orderTagRepository.InsertAsync(orderTag);
            var order = new Order();
            await _orderRepository.InsertAsync(order);

            await _service.AttachOrderTag(orderTag.Id, order.Id);

            //Act
            await _service.DetachOrderTag(orderTag.Id, order.Id);

            //Assert
            Assert.IsFalse(_orderRepository.Table.FirstOrDefault(x => x.Id == order.Id).OrderTags.Any(z => z == orderTag.Id));
            Assert.IsTrue(_orderTagRepository.Table.FirstOrDefault(x => x.Id == orderTag.Id).Count == 0);
        }

        [TestMethod()]
        public async Task GetOrderCountTest()
        {
            //Arrange
            var orderTag = new OrderTag();
            await _orderTagRepository.InsertAsync(orderTag);
            var order = new Order();
            await _orderRepository.InsertAsync(order);

            await _service.AttachOrderTag(orderTag.Id, order.Id);

            //Act
            var result = await _service.GetOrderCount(orderTag.Id, string.Empty);

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