using Microsoft.Extensions.DependencyInjection;
using Persistence.Client;
using Persistence.Client.Clients.Interfaces;
using Persistence.Database.Model;
using System.Net;
using Xunit;

namespace Persistence.IntegrationTests.Controllers
{
    public class SetpointControllerTest : BaseIntegrationTest
    {
        private readonly ISetpointClient setpointClient;
        private class TestObject
        {
            public string? Value1 { get; set; }
            public int? Value2 { get; set; }
        }
        public SetpointControllerTest(WebAppFactoryFixture factory) : base(factory)
        {
            var scope = factory.Services.CreateScope();
            var persistenceClientFactory = scope.ServiceProvider
                .GetRequiredService<PersistenceClientFactory>();

			setpointClient = persistenceClientFactory.GetSetpointClient();
		}

        [Fact]
        public async Task GetCurrent_returns_success()
        {
            //arrange
            var setpointKeys = new List<Guid>()
            {
                Guid.NewGuid(),
                Guid.NewGuid()
            };

			//act
			var response = await setpointClient.GetCurrent(setpointKeys, new CancellationToken());

			//assert
			Assert.NotNull(response);
			Assert.Empty(response);
		}

        [Fact]
        public async Task GetCurrent_AfterSave_returns_success()
        {
            //arrange
            var setpointKey = await Add();

			//act
			var response = await setpointClient.GetCurrent([setpointKey], new CancellationToken());

			//assert
			Assert.NotNull(response);
			Assert.NotEmpty(response);
			Assert.Equal(setpointKey, response.FirstOrDefault()?.Key);
		}

        [Fact]
        public async Task GetHistory_returns_success()
        {
            //arrange
            var setpointKeys = new List<Guid>()
            {
                Guid.NewGuid(),
                Guid.NewGuid()
            };
            var historyMoment = DateTimeOffset.UtcNow;

			//act
			var response = await setpointClient.GetHistory(setpointKeys, historyMoment, new CancellationToken());

			//assert
			Assert.NotNull(response);
			Assert.Empty(response);
		}

        [Fact]
        public async Task GetHistory_AfterSave_returns_success()
        {
            //arrange
            var setpointKey = await Add();
            var historyMoment = DateTimeOffset.UtcNow;
            historyMoment = historyMoment.AddDays(1);

			//act
			var response = await setpointClient.GetHistory([setpointKey], historyMoment, new CancellationToken());

			//assert
			Assert.NotNull(response);
			Assert.NotEmpty(response);
			Assert.Equal(setpointKey, response.FirstOrDefault()?.Key);
		}

        [Fact]
        public async Task GetLog_returns_success()
        {
            //arrange
            var setpointKeys = new List<Guid>()
            {
                Guid.NewGuid(),
                Guid.NewGuid()
            };

			//act
			var response = await setpointClient.GetLog(setpointKeys, new CancellationToken());

			//assert
			Assert.NotNull(response);
			Assert.Empty(response);
		}

        [Fact]
        public async Task GetLog_AfterSave_returns_success()
        {
            //arrange
            var setpointKey = await Add();

			//act
			var response = await setpointClient.GetLog([setpointKey], new CancellationToken());

			//assert
			Assert.NotNull(response);
			Assert.NotEmpty(response);
			Assert.Equal(setpointKey, response.FirstOrDefault().Key);
		}

        [Fact]
        public async Task GetDatesRange_returns_success()
        {
            //arrange
            dbContext.CleanupDbSet<Setpoint>();

			//act
			var response = await setpointClient.GetDatesRangeAsync(CancellationToken.None);

			//assert
			Assert.NotNull(response);
			Assert.Equal(DateTimeOffset.MinValue, response!.From);
			Assert.Equal(DateTimeOffset.MaxValue, response!.To);
		}

        [Fact]
        public async Task GetDatesRange_AfterSave_returns_success()
        {
            //arrange
            dbContext.CleanupDbSet<Setpoint>();

            await Add();

			var dateBegin = DateTimeOffset.MinValue;
			var take = 1;
			var part = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);

			//act
			var response = await setpointClient.GetDatesRangeAsync(CancellationToken.None);

			//assert
			Assert.NotNull(response);

			var expectedValue = part!
				.FirstOrDefault()!.Created
				.ToString("dd.MM.yyyy-HH:mm:ss");
			var actualValueFrom = response.From
				.ToString("dd.MM.yyyy-HH:mm:ss");
			Assert.Equal(expectedValue, actualValueFrom);

			var actualValueTo = response.To
				.ToString("dd.MM.yyyy-HH:mm:ss");
			Assert.Equal(expectedValue, actualValueTo);
		}

        [Fact]
        public async Task GetPart_returns_success()
        {
            //arrange
            var dateBegin = DateTimeOffset.UtcNow;
            var take = 2;

			//act
			var response = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);

			//assert
			Assert.NotNull(response);
			Assert.Empty(response);
		}

        [Fact]
        public async Task GetPart_AfterSave_returns_success()
        {
            //arrange
            var dateBegin = DateTimeOffset.UtcNow;
            var take = 1;
            await Add();

			//act
			var response = await setpointClient.GetPart(dateBegin, take, CancellationToken.None);

			//assert
			Assert.NotNull(response);
			Assert.NotEmpty(response);
		}

        [Fact]
        public async Task Save_returns_success()
        {
            await Add();
        }

        private async Task<Guid> Add()
        {
            //arrange
            var setpointKey = Guid.NewGuid();
            var setpointValue = new TestObject()
            {
                Value1 = "1",
                Value2 = 2
            };

			//act
			await setpointClient.Add(setpointKey, setpointValue, new CancellationToken());

			return setpointKey;
		}
	}
}