using Grand.Data.Tests.MongoDb;
using Grand.Domain.Catalog;
using Grand.Domain.Customers;
using Grand.Domain.Data;
using Grand.Infrastructure;
using Grand.Infrastructure.Caching;
using Grand.Infrastructure.Tests.Caching;
using Grand.SharedKernel.Extensions;
using MediatR;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;

namespace Grand.Business.Catalog.Services.Products.Tests
{
    [TestClass()]
    public class AuctionServiceTests
    {
        private IRepository<Bid> _repository;
        private IRepository<Product> _productrepository;
        private Mock<IWorkContext> _workContextMock;
        private Mock<IMediator> _mediatorMock;
        private AuctionService _auctionService;
        private MemoryCacheBase _cacheBase;

        [TestInitialize()]
        public void InitializeTests()
        {
            CommonPath.BaseDirectory = "";

            _repository = new MongoDBRepositoryTest<Bid>();
            _productrepository = new MongoDBRepositoryTest<Product>();
            _workContextMock = new Mock<IWorkContext>();
            _workContextMock.Setup(c => c.CurrentStore).Returns(() => new Domain.Stores.Store() { Id = "" });
            _workContextMock.Setup(c => c.CurrentCustomer).Returns(() => new Customer());
            _mediatorMock = new Mock<IMediator>();
            _cacheBase = new MemoryCacheBase(MemoryCacheTest.Get(), _mediatorMock.Object);
            _auctionService = new AuctionService(_repository, _productrepository, _cacheBase, _mediatorMock.Object);
        }

        [TestMethod()]
        public async Task GetBidTest()
        {
            //Arrange
            var bid = new Bid() {
                Amount = 10
            };
            await _auctionService.InsertBid(bid);

            //Act
            var result = await _auctionService.GetBid(bid.Id);

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(10, result.Amount);
        }

        [TestMethod()]
        public async Task GetLatestBidTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);
            var bid2 = new Bid() {
                Amount = 12,
                ProductId = "1",
                Date = DateTime.UtcNow
            };
            await _auctionService.InsertBid(bid2);

            //Act
            var result = await _auctionService.GetLatestBid("1");

            //Assert
            Assert.IsNotNull(result);
            Assert.AreEqual(12, result.Amount);
        }

        [TestMethod()]
        public async Task GetBidsByProductIdTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);
            var bid2 = new Bid() {
                Amount = 12,
                ProductId = "1",
                Date = DateTime.UtcNow
            };
            await _auctionService.InsertBid(bid2);

            //Act
            var result = await _auctionService.GetBidsByProductId("1");

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

        [TestMethod()]
        public async Task GetBidsByCustomerIdTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                CustomerId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);
            var bid2 = new Bid() {
                Amount = 12,
                ProductId = "1",
                CustomerId = "2",
                Date = DateTime.UtcNow
            };
            await _auctionService.InsertBid(bid2);

            //Act
            var result = await _auctionService.GetBidsByCustomerId("1");

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

        [TestMethod()]
        public async Task InsertBidTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                CustomerId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);

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

        [TestMethod()]
        public async Task UpdateBidTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                CustomerId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);
            bid1.Amount = 12;
            //Act
            await _auctionService.UpdateBid(bid1);
            //Assert
            Assert.AreEqual(12, _repository.Table.FirstOrDefault().Amount);
        }

        [TestMethod()]
        public async Task DeleteBidTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                CustomerId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);
            //Act
            await _auctionService.DeleteBid(bid1);
            //Assert
            Assert.AreEqual(0, _repository.Table.Count());
        }

        [TestMethod()]
        public async Task UpdateHighestBidTest()
        {
            //Arrange
            var product = new Product();
            _productrepository.Insert(product);

            //Act
            await _auctionService.UpdateHighestBid(product, 15, "sample");

            //Assert
            Assert.AreEqual(15, _productrepository.Table.FirstOrDefault(x => x.Id == product.Id).HighestBid);
        }

        [TestMethod()]
        public async Task GetAuctionsToEndTest()
        {
            //Arrange
            var product1 = new Product() {
                ProductTypeId = ProductType.Auction,
                AvailableEndDateTimeUtc = DateTime.UtcNow.AddDays(1),
            };
            _productrepository.Insert(product1);
            var product2 = new Product() {
                ProductTypeId = ProductType.Auction,
                AvailableEndDateTimeUtc = DateTime.UtcNow.AddDays(-1),
            };
            _productrepository.Insert(product2);

            //Act
            var result = await _auctionService.GetAuctionsToEnd();

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

        [TestMethod()]
        public async Task UpdateAuctionEndedTest()
        {
            //Arrange
            var product1 = new Product() {
                ProductTypeId = ProductType.Auction,
                AvailableEndDateTimeUtc = DateTime.UtcNow.AddDays(1),
            };
            _productrepository.Insert(product1);

            //Act
            await _auctionService.UpdateAuctionEnded(product1, true, true);

            //Assert
            Assert.AreEqual(true, _productrepository.Table.FirstOrDefault(x => x.Id == product1.Id).AuctionEnded);
        }

        [TestMethod()]
        public async Task NewBidTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                CustomerId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);
            //Act
            await _auctionService.NewBid(new Customer() { Id = "1" }, new Product() { Id = "1" }, new Domain.Stores.Store(), new Domain.Localization.Language(), "", 12);
            //Assert
            Assert.AreEqual(12, _repository.Table.Where(x => x.ProductId == "1").Max(x => x.Amount));
        }

        [TestMethod()]
        public async Task CancelBidByOrderTest()
        {
            //Arrange
            var bid1 = new Bid() {
                Amount = 10,
                ProductId = "1",
                CustomerId = "1",
                OrderId = "1",
                Date = DateTime.UtcNow.AddDays(-1)
            };
            await _auctionService.InsertBid(bid1);
            //Act
            await _auctionService.CancelBidByOrder("1");
            //Assert
            Assert.AreEqual(0, _repository.Table.Count());
        }
    }
}