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

namespace ErsatzTV.Application.ProgramSchedules;

public class DeleteProgramScheduleItemHandler(
    IDbContextFactory<TvContext> dbContextFactory,
    ChannelWriter<IBackgroundServiceRequest> channel) : IRequestHandler<DeleteProgramScheduleItem, Either<BaseError, Unit>>
{
    public async Task<Either<BaseError, Unit>> Handle(
        DeleteProgramScheduleItem request,
        CancellationToken cancellationToken)
    {
        await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken);

        ProgramScheduleItem item = await dbContext.ProgramScheduleItems
            .Include(i => i.ProgramSchedule)
            .ThenInclude(ps => ps.Playouts)
            .SingleOrDefaultAsync(
                i => i.Id == request.ProgramScheduleItemId && i.ProgramScheduleId == request.ProgramScheduleId,
                cancellationToken);

        if (item is null)
        {
            return new NotFoundError(
                $"ProgramScheduleItem {request.ProgramScheduleItemId} does not exist on schedule {request.ProgramScheduleId}.");
        }

        List<Playout> playouts = item.ProgramSchedule.Playouts;
        dbContext.ProgramScheduleItems.Remove(item);

        // bump the optimistic-concurrency token so this config edit rotates other clients' ETags (#253)
        item.ProgramSchedule.Version++;

        await dbContext.SaveChangesForcingVersion(cancellationToken);

        // post-commit side effect runs on CancellationToken.None so a late request cancellation
        // can't abort it after the commit landed (#254)
        foreach (Playout playout in playouts)
        {
            await channel.WriteAsync(new BuildPlayout(playout.Id, PlayoutBuildMode.Refresh), CancellationToken.None);
        }

        return Unit.Default;
    }
}
