using System.Threading.Channels;
using ErsatzTV.Application.Scheduling;
using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Scheduling;
using ErsatzTV.Infrastructure.Data;
using Microsoft.EntityFrameworkCore;

namespace ErsatzTV.Application.Playouts;

public class ReshufflePlayoutHandler(
    IMediator mediator,
    ChannelWriter<IBackgroundServiceRequest> channel,
    IDbContextFactory<TvContext> dbContextFactory)
    : IRequestHandler<ReshufflePlayout>
{
    public async Task Handle(ReshufflePlayout request, CancellationToken cancellationToken)
    {
        await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

        Option<Playout> maybePlayout = await dbContext.Playouts
            .AsNoTracking()
            .Where(p => p.ScheduleKind == PlayoutScheduleKind.Classic ||
                        p.ScheduleKind == PlayoutScheduleKind.Block ||
                        p.ScheduleKind == PlayoutScheduleKind.Sequential ||
                        p.ScheduleKind == PlayoutScheduleKind.Scripted)
            .SingleOrDefaultAsync(p => p.Id == request.PlayoutId, cancellationToken);

        foreach (Playout playout in maybePlayout)
        {
            // Roll a new play order. BuildPlayout(Reset) only reseeds Playout.Seed for CLASSIC playouts
            // (PlayoutBuilder); Block/Sequential/Scripted rebuild deterministically from the existing seed.
            // ErasePlayoutHistory is the one primitive that reseeds + clears the derived per-collection
            // enumerator anchors for ALL four kinds — run it first, then rebuild from scratch.
            await mediator.Send(new ErasePlayoutHistory(playout.Id), cancellationToken);
            await channel.WriteAsync(
                new BuildPlayout(playout.Id, PlayoutBuildMode.Reset),
                cancellationToken);
        }
    }
}
