using JSMR.Application.Scanning.Contracts;
using JSMR.Application.Scanning.Ports;
using JSMR.Domain.Entities;
using JSMR.Infrastructure.Data;
using JSMR.Infrastructure.Ingestion;
using JSMR.Tests.Fixtures;
using Microsoft.EntityFrameworkCore;
using Shouldly;

namespace JSMR.Tests.Ingestion.English;

public class English_Insert_Then_Update_Tests(MariaDbContainerFixture container) : EnglishIngestionTestBase(container)
{
    [Fact]
    public async Task Insert_Then_Update()
    {
        await using AppDbContext dbContext = await GetAppDbContextAsync();

        // Part 1 -- Insert
        VoiceWorkIngest ingest = new()
        {
            MakerId = "RG00001",
            MakerName = "Good Dreams",
            ProductId = "RJ0000001",
            Title = "Today Sounds (EN)",
            Description = "An average product. (EN)"
        };

        EnglishVoiceWorkUpdater updater = new(dbContext, LanguageIdentifier);
        VoiceWorkUpsertResult[] results = await updater.UpsertAsync([ingest], TestContext.Current.CancellationToken);

        VoiceWork voiceWork = await dbContext.VoiceWorks.SingleAsync(v => v.ProductId == "RJ0000001", TestContext.Current.CancellationToken);
        EnglishVoiceWork? englishVoiceWork = await dbContext.EnglishVoiceWorks.SingleOrDefaultAsync(e => e.VoiceWorkId == voiceWork.VoiceWorkId, TestContext.Current.CancellationToken);

        englishVoiceWork.ShouldNotBeNull();
        englishVoiceWork.ProductName.ShouldBe("Today Sounds (EN)");
        englishVoiceWork.Description.ShouldBe("An average product. (EN)");
        englishVoiceWork.IsValid?.ShouldBeTrue();

        results.Length.ShouldBe(1);
        results.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(1);
        results.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(0);
        results.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(0);
        results.Count(r => r.Status == VoiceWorkUpsertStatus.Unchanged).ShouldBe(0);
        results.Sum(r => r.Issues.Count).ShouldBe(0);

        // Part 2 -- Update
        VoiceWorkIngest ingestUpdate = ingest with
        {
            Title = "Today Sounds (EN v2)",
            Description = "Updated English description."
        };

        VoiceWorkUpsertResult[] updatedResults = await updater.UpsertAsync([ingestUpdate], CancellationToken.None);

        EnglishVoiceWork? updatedEnglishVoiceWork = await dbContext.EnglishVoiceWorks.SingleOrDefaultAsync(e => e.VoiceWorkId == voiceWork.VoiceWorkId, TestContext.Current.CancellationToken);
        updatedEnglishVoiceWork.ShouldNotBeNull();
        updatedEnglishVoiceWork.ProductName.ShouldBe("Today Sounds (EN v2)");
        updatedEnglishVoiceWork.Description.ShouldBe("Updated English description.");
        updatedEnglishVoiceWork.IsValid?.ShouldBeTrue();

        updatedResults.Length.ShouldBe(1);
        updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(0);
        updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(1);
        updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(0);
        updatedResults.Count(r => r.Status == VoiceWorkUpsertStatus.Unchanged).ShouldBe(0);
        updatedResults.Sum(r => r.Issues.Count).ShouldBe(0);

        // Part 3 -- Update Again (No Change)
        VoiceWorkUpsertResult[] updatedAgainResults = await updater.UpsertAsync([ingestUpdate], CancellationToken.None);

        EnglishVoiceWork? updatedAgainEnglishVoiceWork = await dbContext.EnglishVoiceWorks.SingleOrDefaultAsync(e => e.VoiceWorkId == voiceWork.VoiceWorkId, TestContext.Current.CancellationToken);
        updatedAgainEnglishVoiceWork.ShouldNotBeNull();
        updatedAgainEnglishVoiceWork.ProductName.ShouldBe("Today Sounds (EN v2)");
        updatedAgainEnglishVoiceWork.Description.ShouldBe("Updated English description.");
        updatedAgainEnglishVoiceWork.IsValid?.ShouldBeTrue();

        updatedAgainResults.Length.ShouldBe(1);
        updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Inserted).ShouldBe(0);
        updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Updated).ShouldBe(0);
        updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Skipped).ShouldBe(0);
        updatedAgainResults.Count(r => r.Status == VoiceWorkUpsertStatus.Unchanged).ShouldBe(1);
        updatedAgainResults.Sum(r => r.Issues.Count).ShouldBe(0);
    }
}