using AsbCloudApp.Services;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;

namespace AsbCloudWebApi.Tests.ServicesTests
{
    public abstract class CrudServiceTestAbstract<TDto>
        where TDto : AsbCloudApp.Data.IId
    {
        private readonly ICrudService<TDto> service;

        public CrudServiceTestAbstract()
        {
            AsbCloudInfrastructure.DependencyInjection.MapsterSetup();
            service = MakeService();
        }

        protected abstract ICrudService<TDto> MakeService();
        protected abstract TDto MakeNewItem();

        [Fact]
        public async Task<int> Insert()
        {
            var newItem = MakeNewItem();
            var id = await service.InsertAsync(newItem, CancellationToken.None);
            Assert.True(id > 0);
            return id;
        }

        [Fact]
        public async Task InsertRange()
        {
            var items = new TDto[2];
            items[0] = MakeNewItem();
            items[1] = MakeNewItem();
            var count = await service.InsertRangeAsync(items, CancellationToken.None);
            Assert.Equal(2, count);
        }

        [Fact]
        public async Task GetById()
        {
            var id = await Insert();
            var gotItem = await service.GetOrDefaultAsync(id, CancellationToken.None);
            Assert.True(id > 0);
            Assert.Equal(id, gotItem.Id);
        }

        [Fact]
        public async Task GetAll()
        {
            var items = await service.GetAllAsync(CancellationToken.None);
            var count = items.Count();
            await Insert();
            var newItems = await service.GetAllAsync(CancellationToken.None);
            var newCount = newItems.Count();
            Assert.True(newCount > 0);
            Assert.Equal(count + 1, newCount);
        }

        [Fact]
        public async Task UpdateAsync_returns_notfound()
        {
            var item = MakeNewItem();
            item.Id = int.MaxValue - 1;
            var updatedId = await service.UpdateAsync(item, CancellationToken.None);
            Assert.True(updatedId < 0);
        }

        [Fact]
        public async Task UpdateAsync()
        {
            var newItem = MakeNewItem();
            newItem.Id = await service.InsertAsync(newItem, CancellationToken.None);
            var item = MakeNewItem();
            item.Id = newItem.Id;
            var updatedId = await service.UpdateAsync(item, CancellationToken.None);
            Assert.True(newItem.Id > 0);
            Assert.Equal(newItem.Id, updatedId);
        }

        [Fact]
        public async Task DeleteAsync()
        {
            var newItem = MakeNewItem();
            var id = await service.InsertAsync(newItem, CancellationToken.None);
            var deletedId = await service.DeleteAsync(id, CancellationToken.None);
            Assert.True(id > 0);
            Assert.Equal(id, deletedId);
        }
    }
}