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

namespace AsbCloudWebApi.IntegrationTests.Repository;

public class DataSaubStatRepositoryTest : BaseIntegrationTest
{
    private static readonly TimeSpan timeSpan = TimeSpan.FromHours(1);

    private static readonly DataSaubStatDto[] statDtos = new DataSaubStatDto[2]
    {
        new()
        {
            IdTelemetry = 1,
            DateEnd = new DateTimeOffset(2024, 1, 1, 20, 25, 0, timeSpan),
            DateStart = new DateTimeOffset(2024, 1, 1, 20, 15, 0, timeSpan),
            AxialLoad = 10.0,
            AxialLoadLimitMax = 10.0,
            AxialLoadSp = 10.0,
            BlockSpeedSp = 1000,
            DepthEnd = 10.0,
            DepthStart = 5.0,
            EnabledSubsystems = 1,
            Flow = 10.0,
            HasOscillation = true,
            Id = default,
            IdCategory = 2,
            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 = 1,
            DateEnd = new DateTimeOffset(2024, 2, 2, 20, 25, 0, timeSpan),
            DateStart = new DateTimeOffset(2024, 2, 2, 20, 15, 0, timeSpan),
            AxialLoad = 10.0,
            AxialLoadLimitMax = 10.0,
            AxialLoadSp = 10.0,
            BlockSpeedSp = 1000,
            DepthEnd = 10.0,
            DepthStart = 5.0,
            EnabledSubsystems = 1,
            Flow = 10.0,
            HasOscillation = true,
            Id = default,
            IdCategory = 2,
            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 readonly WellOperationCategory category = new()
    {
        Id = 2,
        IdParent = null,
        Name = "Категория 2"
    };

    private readonly IDataSaubStatRepository dataSaubStatRepository;

    public DataSaubStatRepositoryTest(WebAppFactoryFixture factory) : base(factory)
    {
        dataSaubStatRepository = scope.ServiceProvider.GetRequiredService<IDataSaubStatRepository>();
    }

    [Fact]
    public async Task GetLastDatesAsync_returns_success()
    {
        //prepare
        dbContext.CleanupDbSet<DataSaubStat>();
        dbContext.CleanupDbSet<WellOperationCategory>();

        var dbSetSaubStat = dbContext.Set<DataSaubStat>();
        var dbSetCategories = dbContext.Set<WellOperationCategory>();

        var entities = statDtos.Select(stat => ConvertToEntity(stat));

        dbSetCategories.Add(category);
        dbContext.SaveChanges();

        dbSetSaubStat.AddRange(entities);
        dbContext.SaveChanges();

        //act
        var telemetryIds = statDtos.Select(stat => stat.IdTelemetry).ToArray();
        var result = await dataSaubStatRepository.GetLastsAsync(telemetryIds, CancellationToken.None);

        var expected = statDtos.Max(stat => stat.DateEnd);
        var actual = result.First().DateEnd;

        //assert
        Assert.True((expected - actual).Ticks == 0.0);
    }

    [Fact]
    public async Task InsertRangeAsync_returns_success()
    {
        //prepare
        dbContext.CleanupDbSet<DataSaubStat>();
        var dbSet = dbContext.Set<DataSaubStat>();
        
        var dbSetCategories = dbContext.Set<WellOperationCategory>();
        dbSetCategories.Add(category);

        dbContext.SaveChanges();
        
        //act
        var result = await dataSaubStatRepository.InsertRangeAsync(statDtos, CancellationToken.None);

        //assert
        Assert.Equal(statDtos.Length, result);

        var statDtosFromDb = dbSet.Select(stat => ConvertToDto(stat, timeSpan)).ToArray();

        var excludedProps = new[] {
            nameof(DataSaubStat.Telemetry),
            nameof(DataSaubStat.Id),
            nameof(DataSaubStat.OperationCategory)
        };
        foreach (var statDtoFromDb in statDtosFromDb)
        {
            var statDto = statDtos
                .Where(stat => stat.DateStart == statDtoFromDb.DateStart)
                .Where(stat => stat.DateEnd == statDtoFromDb.DateEnd)
                .FirstOrDefault();

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

    private static DataSaubStat ConvertToEntity(DataSaubStatDto stat)
    {
        var entity = stat.Adapt<DataSaubStat>();
        entity.DateStart = entity.DateStart.ToUniversalTime();
        entity.DateEnd = entity.DateEnd.ToUniversalTime();

        return entity;
    }

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

        return dto;
    }
}