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.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.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.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);
   }
}