using AsbCloudApp.Data.SAUB;
using AsbCloudDb.Model;
using AsbCloudWebApi.IntegrationTests.Clients;
using Xunit;

namespace AsbCloudWebApi.IntegrationTests.Controllers;
public class TelemetryControllerTest : BaseIntegrationTest
{
    private ITelemetryControllerClient client;
    static readonly string uid = DateTime.UtcNow.ToString("yyyyMMdd_HHmmssfff");

    private static readonly SimpleTimezone timezone = new() {TimezoneId = "a", Hours = 5 };
    private static readonly Telemetry telemetry = new Telemetry() {Id = 1, RemoteUid = uid, TimeZone = timezone, Info = new() };
    private readonly IEnumerable<EventDto> events = [new() { Id = 1, EventType = 1, IdCategory = 1, IdSound = 1, Message = "there is no spoon {tag1}", Tag = "tag1" }];
    private readonly IEnumerable<TelemetryUserDto> users = [new TelemetryUserDto() { Id = 1, Level = 0, Name = "Neo", Patronymic = "Kianovich", Surname = "Theone" }];
    private readonly IEnumerable<TelemetryMessageDto> messages = [new TelemetryMessageDto() { Id = 100, IdEvent = 1, WellDepth = 5, Date = DateTimeOffset.Now.ToOffset(TimeSpan.FromHours(5)), Arg0 = "3.14", IdTelemetryUser = 1 }];
    private readonly IEnumerable<TelemetryDataSaub> telemetryDataSaubEntities = [new TelemetryDataSaub()
    {
        IdTelemetry = telemetry.Id,
        DateTime = DateTimeOffset.UtcNow,
        AxialLoad = 2,
        WellDepth = 5,
        BitDepth = 5,
        BlockPosition = 5,
        BlockSpeed = 5,    
    }];
    private readonly TelemetryInfoDto telemetryInfoDto = new() 
    {
        TimeZoneId = timezone.TimezoneId,
        TimeZoneOffsetTotalHours = timezone.Hours,
        Cluster = "cluster1",
    };

    public TelemetryControllerTest(WebAppFactoryFixture factory)
        : base(factory)
    {
        client = factory.GetAuthorizedHttpClient<ITelemetryControllerClient>(string.Empty);
    }

    [Fact]
    public async Task GetTelemetriesInfoByLastData()
    {
        // Arrange
        dbContext.CleanupDbSet<Telemetry>();
        dbContext.Set<Telemetry>().Add(telemetry);
        dbContext.Set<TelemetryDataSaub>().AddRange(telemetryDataSaubEntities);
        dbContext.SaveChanges();

        // Act
        var response = await client.GetTelemetriesInfoByLastData(CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
    }

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

        // act
        var response = await client.PostInfoAsync(uid, telemetryInfoDto, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();

        Assert.Equal(1, telemetriesCount);
    }
    
    [Fact]
    public async Task PostInfoAsync_twice_should_be_ok()
    {
        // arrange
        dbContext.CleanupDbSet<Telemetry>();

        // act
        _ = await client.PostInfoAsync(uid, telemetryInfoDto, CancellationToken.None);
        var response = await client.PostInfoAsync(uid, telemetryInfoDto, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();

        Assert.Equal(1, telemetriesCount);
    }

    [Fact]
    public async Task PostUsersAsync()
    {
        // arrange
        dbContext.CleanupDbSet<Telemetry>();
        dbContext.Set<Telemetry>().Add(telemetry);
        dbContext.SaveChanges();

        // act
        var response = await client.PostUsersAsync(uid, users, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();
        var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();

        Assert.Equal(1, telemetriesCount);
        Assert.Equal(1, telemetryUserCount);
    }

    [Fact]
    public async Task PostUsers_twice_should_be_ok()
    {
        // arrange
        dbContext.CleanupDbSet<TelemetryUser>();
        dbContext.CleanupDbSet<Telemetry>();
        dbContext.Set<Telemetry>().Add(telemetry);
        dbContext.SaveChanges();

        // act
        _ = await client.PostUsersAsync(uid, users, CancellationToken.None);
        var response = await client.PostUsersAsync(uid, users, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();
        var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();

        Assert.Equal(1, telemetriesCount);
        Assert.Equal(1, telemetryUserCount);
    }

    [Fact]
    public async Task PostEventsAsync()
    {
        // arrange
        dbContext.CleanupDbSet<TelemetryEvent>();
        dbContext.CleanupDbSet<Telemetry>();
        dbContext.Set<Telemetry>().Add(telemetry);
        dbContext.SaveChanges();

        // act
        var response = await client.PostEventsAsync(uid, events, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();
        var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();

        Assert.Equal(1, telemetriesCount);
        Assert.Equal(1, telemetryEventCount);
    }

    [Fact]
    public async Task PostEventsAsync_twice_should_be_ok()
    {
        // arrange
        dbContext.CleanupDbSet<TelemetryEvent>();
        dbContext.CleanupDbSet<Telemetry>();
        dbContext.Set<Telemetry>().Add(telemetry);
        dbContext.SaveChanges();

        // act
        _ = await client.PostEventsAsync(uid, events, CancellationToken.None);
        var response = await client.PostEventsAsync(uid, events, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();
        var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();

        Assert.Equal(1, telemetriesCount);
        Assert.Equal(1, telemetryEventCount);
    }

    [Fact]
    public async Task PostMessagesAsync()
    {
        // arrange
        dbContext.CleanupDbSet<TelemetryMessage>();
        dbContext.CleanupDbSet<TelemetryEvent>();
        dbContext.CleanupDbSet<TelemetryUser>();
        dbContext.CleanupDbSet<Telemetry>();

        dbContext.Set<Telemetry>().Add(telemetry);
        dbContext.SaveChanges();

        // act
        _ = await client.PostEventsAsync(uid, events, CancellationToken.None);
        _ = await client.PostUsersAsync(uid, users, CancellationToken.None);
        var response = await client.PostMessagesAsync(uid, messages, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();
        var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();
        var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();
        var telemetryMessageCount = dbContext.Set<TelemetryMessage>().Count();

        Assert.Equal(1, telemetriesCount);
        Assert.Equal(1, telemetryEventCount);
        Assert.Equal(1, telemetryUserCount);
        Assert.Equal(1, telemetryMessageCount);
    }

    [Fact]
    public async Task PostMessagesAsync_twice_should_be_ok()
    {
        // arrange
        dbContext.CleanupDbSet<TelemetryMessage>();
        dbContext.CleanupDbSet<TelemetryEvent>();
        dbContext.CleanupDbSet<TelemetryUser>();
        dbContext.CleanupDbSet<Telemetry>();
        dbContext.Set<Telemetry>().Add(telemetry);
        dbContext.SaveChanges();

        // act
        _ = await client.PostEventsAsync(uid, events, CancellationToken.None);
        _ = await client.PostUsersAsync(uid, users, CancellationToken.None);
        _ = await client.PostMessagesAsync(uid, messages, CancellationToken.None);
        var response = await client.PostMessagesAsync(uid, messages, CancellationToken.None);

        // Assert
        Assert.Equal(System.Net.HttpStatusCode.OK, response.StatusCode);
        var telemetriesCount = dbContext.Set<Telemetry>().Count();
        var telemetryEventCount = dbContext.Set<TelemetryEvent>().Count();
        var telemetryUserCount = dbContext.Set<TelemetryUser>().Count();
        var telemetryMessageCount = dbContext.Set<TelemetryMessage>().Count();

        Assert.Equal(1, telemetriesCount);
        Assert.Equal(1, telemetryEventCount);
        Assert.Equal(1, telemetryUserCount);
        Assert.Equal(2, telemetryMessageCount);
    }
}