using AsbCloudApp.Data;
using AsbCloudApp.Repositories;
using AsbCloudDb.Model;
using Mapster;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Xunit;

namespace AsbCloudWebApi.IntegrationTests.Repository;

public class DataSaubStatRepositoryTest : BaseIntegrationTest
{
   private readonly IDataSaubStatRepository dataSaubStatRepository;
   
   public DataSaubStatRepositoryTest(WebAppFactoryFixture factory)
      : base(factory)
   {
      dataSaubStatRepository = scope.ServiceProvider.GetRequiredService<IDataSaubStatRepository>();
      dbContext.CleanupDbSet<DataSaubStat>();
   }

   [Fact]
   public async Task GetLastDatesAsync_returns_success()
   {
      //arrange
      var telemetry = await dbContext.Telemetries.FirstAsync();
      var timeZoneOffset = TimeSpan.FromHours(telemetry.TimeZone.Hours);
      var dataSaubStat = CreateDataSaubStat(telemetry.Id, timeZoneOffset);
      dbContext.AddRange(dataSaubStat);
      await dbContext.SaveChangesAsync();

      var telemetryIds = dataSaubStat.Select(stat => stat.IdTelemetry).ToArray();

      //act
      var result = await dataSaubStatRepository.GetLastsAsync(telemetryIds, CancellationToken.None);

      //assert
      var expected = dataSaubStat.Max(stat => stat.DateEnd).ToOffset(timeZoneOffset);
      var actual = result.First().DateEnd;
      Assert.True((expected - actual).Ticks == 0.0);
   }

   [Fact]
   public async Task InsertRangeAsync_returns_success()
   {
      //arrange
      var telemetry = await dbContext.Telemetries.FirstAsync();
      var timeZoneOffset = TimeSpan.FromHours(telemetry.TimeZone.Hours);
      var dataSaubStat = CreateDataSaubStat(telemetry.Id, timeZoneOffset);
      var expectedDtos = dataSaubStat.Select(entity => ConvertToDto(entity, timeZoneOffset));

      //act
      await dataSaubStatRepository.InsertRangeAsync(expectedDtos, CancellationToken.None);

      //assert
      var entities = await dbContext.DataSaubStat.ToArrayAsync();
      var actualDtos = entities.Select(entity => ConvertToDto(entity, timeZoneOffset));

      var excludedProps = new[]
      {
         nameof(DataSaubStat.Telemetry),
         nameof(DataSaubStat.Id),
         nameof(DataSaubStat.OperationCategory)
      };

      foreach (var actualDto in actualDtos)
      {
         var statDto = expectedDtos.FirstOrDefault(stat => stat.DateEnd == actualDto.DateEnd &&
                                             stat.DateStart == actualDto.DateStart);

         MatchHelper.Match(actualDto, statDto, excludedProps);
      }
   }

   private static IEnumerable<DataSaubStat> CreateDataSaubStat(int idTelemetry, TimeSpan timeZoneOffset) => new DataSaubStat[]
   {
      new()
      {
         IdTelemetry = idTelemetry,
         DateEnd = new DateTimeOffset(2024, 1, 1, 20, 25, 0, timeZoneOffset).ToUniversalTime(),
         DateStart = new DateTimeOffset(2024, 1, 1, 20, 15, 0, timeZoneOffset).ToUniversalTime(),
         AxialLoad = 10.0,
         AxialLoadLimitMax = 10.0,
         AxialLoadSp = 10.0,
         BlockSpeedSp = 1000,
         DepthEnd = 10.0,
         DepthStart = 5.0,
         EnabledSubsystems = 1,
         Flow = 10.0,
         HasOscillation = true,
         IdCategory = WellOperationCategory.IdSlide,
         IdFeedRegulator = 1,
         Pressure = 10.0,
         PressureIdle = 10.0,
         PressureSp = 10.0,
         RotorSpeed = 9.0,
         RotorTorque = 9.0,
         RotorTorqueSp = 9.0,
         RotorTorqueLimitMax = 9.0,
         Speed = 10.0
      },
      new()
      {
         IdTelemetry = idTelemetry,
         DateEnd = new DateTimeOffset(2024, 2, 2, 20, 25, 0, timeZoneOffset).ToUniversalTime(),
         DateStart = new DateTimeOffset(2024, 2, 2, 20, 15, 0, timeZoneOffset).ToUniversalTime(),
         AxialLoad = 10.0,
         AxialLoadLimitMax = 10.0,
         AxialLoadSp = 10.0,
         BlockSpeedSp = 1000,
         DepthEnd = 10.0,
         DepthStart = 5.0,
         EnabledSubsystems = 1,
         Flow = 10.0,
         HasOscillation = true,
         IdCategory = WellOperationCategory.IdSlide,
         IdFeedRegulator = 1,
         Pressure = 10.0,
         PressureIdle = 10.0,
         PressureSp = 10.0,
         RotorSpeed = 10.0,
         RotorTorque = 10.0,
         RotorTorqueSp = 10.0,
         RotorTorqueLimitMax = 10.0,
         Speed = 10.0
      }
   };

   private static DataSaubStatDto ConvertToDto(DataSaubStat entity, TimeSpan timeZoneOffset)
   {
      var dto = entity.Adapt<DataSaubStatDto>();
      dto.DateStart = dto.DateStart.ToOffset(timeZoneOffset);
      dto.DateEnd = dto.DateEnd.ToOffset(timeZoneOffset);

      return dto;
   }
}