using ErsatzTV.Application.Troubleshooting;
using ErsatzTV.Application.Troubleshooting.Queries;
using ErsatzTV.Core;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Domain.Scheduling;
using ErsatzTV.Core.Errors;
using ErsatzTV.Infrastructure.Data;
using ErsatzTV.Tests.Support;
using LanguageExt;
using NUnit.Framework;
using Shouldly;

namespace ErsatzTV.Tests.Application.Troubleshooting;

[TestFixture]
public class GetPlayoutHistoryDetailsHandlerTests
{
    private InMemoryTvContext _db = null!;

    [SetUp]
    public async Task SetUp() => _db = await InMemoryTvContext.CreateAsync();

    [TearDown]
    public async Task TearDown() => await _db.DisposeAsync();

    [Test]
    public async Task Should_Return_NotFoundError_When_Row_Missing()
    {
        var handler = new GetPlayoutHistoryDetailsHandler(_db.Factory);

        Either<BaseError, PlayoutHistoryDetailsViewModel> result =
            await handler.Handle(new GetPlayoutHistoryDetails(999), CancellationToken.None);

        result.IsLeft.ShouldBeTrue();
        LeftOf(result).ShouldBeOfType<NotFoundError>();
    }

    [Test]
    public async Task Should_Decode_Collection_Key_When_Row_Exists()
    {
        int historyId = await SeedHistory(
            """{"CollectionType":"Collection","CollectionId":1,"PlaybackOrder":"Shuffle"}""",
            "{}",
            seedCollection: true);

        var handler = new GetPlayoutHistoryDetailsHandler(_db.Factory);

        Either<BaseError, PlayoutHistoryDetailsViewModel> result =
            await handler.Handle(new GetPlayoutHistoryDetails(historyId), CancellationToken.None);

        result.IsRight.ShouldBeTrue();
        PlayoutHistoryDetailsViewModel vm = RightOf(result);
        vm.PlaybackOrder.ShouldBe(PlaybackOrder.Shuffle);
        vm.CollectionType.ShouldBe(CollectionType.Collection);
        vm.Name.ShouldBe("Cartoons");
    }

    [Test]
    public async Task Should_Return_Error_When_Key_Json_Is_Malformed()
    {
        int historyId = await SeedHistory("this is not json", "{}", seedCollection: false);

        var handler = new GetPlayoutHistoryDetailsHandler(_db.Factory);

        Either<BaseError, PlayoutHistoryDetailsViewModel> result =
            await handler.Handle(new GetPlayoutHistoryDetails(historyId), CancellationToken.None);

        result.IsLeft.ShouldBeTrue();
        LeftOf(result).ShouldNotBeOfType<NotFoundError>();
    }

    private async Task<int> SeedHistory(string key, string details, bool seedCollection)
    {
        await using TvContext context = _db.CreateContext();

        if (seedCollection)
        {
            context.Collections.Add(new Collection { Id = 1, Name = "Cartoons" });
        }

        var history = new PlayoutHistory
        {
            PlayoutId = 1,
            BlockId = 10,
            PlaybackOrder = PlaybackOrder.Shuffle,
            Index = 0,
            Key = key,
            ChildKey = string.Empty,
            IsCurrentChild = false,
            When = DateTime.UtcNow,
            Finish = DateTime.UtcNow.AddHours(1),
            Details = details
        };
        context.PlayoutHistory.Add(history);
        await context.SaveChangesAsync();
        return history.Id;
    }

    private static BaseError LeftOf(Either<BaseError, PlayoutHistoryDetailsViewModel> either) =>
        either.Match(Left: e => e, Right: _ => throw new AssertionException("Expected Left"));

    private static PlayoutHistoryDetailsViewModel RightOf(Either<BaseError, PlayoutHistoryDetailsViewModel> either) =>
        either.Match(Left: _ => throw new AssertionException("Expected Right"), Right: v => v);
}
