using System.Net;
using AsbCloudApp.Data.DetectedOperation;
using AsbCloudApp.Data.WellOperation;
using AsbCloudApp.Requests;
using AsbCloudDb.Model;
using AsbCloudWebApi.IntegrationTests.Clients;
using AsbCloudWebApi.IntegrationTests.Data;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Xunit;

namespace AsbCloudWebApi.IntegrationTests.Controllers;

public class DetectedOperationControllerTests : BaseIntegrationTest
{
	private readonly IDetectedOperationClient client;

	private readonly DetectedOperationDto dto = new()
	{
		IdCategory = WellOperationCategory.IdRotor,
		DateStart = new DateTimeOffset(new DateTime(2023, 5, 12, 1,0,0, DateTimeKind.Utc)),
		DateEnd = new DateTimeOffset(new DateTime(2023, 5, 12, 1,0,0, DateTimeKind.Utc)),
		DepthStart = 0,
		DepthEnd = 80,
		OperationCategory = new WellOperationCategoryDto
		{
			Id = WellOperationCategory.IdRotor,
			IdParent = WellOperationCategory.IdDrilling,
			Name = "Бурение ротором"
		},
		EnabledSubsystems = new EnabledSubsystems
		{
			IsAutoRotor = true
		},
		Value = 400,
	};

	public DetectedOperationControllerTests(WebAppFactoryFixture factory)
		: base(factory)
	{
		client = factory.GetAuthorizedHttpClient<IDetectedOperationClient>(string.Empty);

		dbContext.CleanupDbSet<DetectedOperation>();
	}

	[Fact]
	public async Task InsertRangeAsync_returns_success()
	{
		//arrange
		var well = dbContext.Wells.First();
		dto.IdTelemetry = well.IdTelemetry!.Value;

		//act
		var response = await client.InsertRangeAsync(well.Id, new[] { dto });

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.NotNull(response.Content);
		Assert.Equal(1, response.Content);
	}

	[Fact]
	public async Task UpdateRangeAsync_returns_success()
	{
		//arrange
		var well = dbContext.Wells.First();
		dto.IdTelemetry = well.IdTelemetry!.Value;

		var entity = dto.Adapt<DetectedOperation>();
		dbContext.DetectedOperations.Add(entity);
		await dbContext.SaveChangesAsync();
		dto.Id = entity.Id;

		//act
		var response = await client.UpdateRangeAsync(well.Id, new[] { dto });

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.NotNull(response.Content);
		Assert.Equal(1, response.Content);
	}

	[Fact]
	public async Task UpdateRangeAsync_returns_bad_request_when_id_is_invalid()
	{
		//arrange
		var well = dbContext.Wells.First();

		//act
		var response = await client.UpdateRangeAsync(well.Id, new[] { dto });

		//assert
		Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
	}


	[Fact]
	public async Task DeleteRangeAsync_returns_success()
	{
		//arrange
		var well = dbContext.Wells.First();
		dto.IdTelemetry = well.IdTelemetry!.Value;

		var entity = dto.Adapt<DetectedOperation>();
		dbContext.DetectedOperations.Add(entity);
		await dbContext.SaveChangesAsync();

		var ids = await dbContext.DetectedOperations.Select(d => d.Id).ToArrayAsync();

		//act
		var response = await client.DeleteRangeAsync(well.Id, ids);

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.NotNull(response.Content);
		Assert.Equal(1, response.Content);
	}

	[Fact]
	public async Task GetAsync_returns_first_page()
	{
		//arrange
		const int pageSize = 10;
		const int pageIndex = 0;

		var request = new DetectedOperationRequest
		{
			Skip = pageIndex,
			Take = pageSize,
			IdsCategories = new[] { dto.IdCategory }
		};

		var well = dbContext.Wells.First();
		dto.IdTelemetry = well.IdTelemetry!.Value;
		
		var entity = dto.Adapt<DetectedOperation>();
		dbContext.DetectedOperations.Add(entity);
		await dbContext.SaveChangesAsync();

		//act
		var response = await client.GetAsync(well.Id, request);

		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.NotNull(response.Content);

		var totalExpected = response.Content.Count - pageSize * pageIndex;

		Assert.Equal(totalExpected, response.Content.Items.Count());
	}
	
	[Fact]
	public async Task GetAsync_returns_first_operation()
	{
		//arrange
		var well = dbContext.Wells.First();
		dto.IdTelemetry = well.IdTelemetry!.Value;
		
		var entity = dto.Adapt<DetectedOperation>();
		dbContext.DetectedOperations.Add(entity);
		await dbContext.SaveChangesAsync();

		var request = new DetectedOperationRequest
		{
			IdsCategories = new[] { dto.IdCategory }
		};
		
		//act
		var response = await client.GetAsync(well.Id, request);
		
		//assert
		Assert.Equal(HttpStatusCode.OK, response.StatusCode);
		Assert.NotNull(response.Content);

		var firstOperation = response.Content.Items.ElementAt(0);
		
		Assert.Equal(well.IdTelemetry, firstOperation.IdTelemetry);
		Assert.Equal(dto.EnabledSubsystems, firstOperation.EnabledSubsystems);
		Assert.Equal(dto.DateStart.ToOffset(TimeSpan.FromHours(Defaults.Timezone.Hours)), firstOperation.DateStart);
		Assert.Equal(dto.DateEnd.ToOffset(TimeSpan.FromHours(Defaults.Timezone.Hours)), firstOperation.DateEnd);
	}
}