using LiteCqrs;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
using TeleWave.Application.Library;

namespace TeleWave.Application.Maintenance.DeleteShowMedia;

public sealed class DeleteShowMediaCommandHandler(IAppDbContext dbContext, IMediaStorage storage)
    : ICommandHandler<DeleteShowMediaCommand, Result<int>>
{
    public async Task<Result<int>> Handle(
        DeleteShowMediaCommand command,
        CancellationToken cancellationToken
    )
    {
        var show = await dbContext
            .Shows.Include(s => s.Episodes)
            .FirstOrDefaultAsync(s => s.Id == command.ShowId, cancellationToken);
        if (show is null)
            return Result.Failure<int>(ShowErrors.NotFound);

        var episodes = show.Episodes.ToList();
        var assetIds = episodes.Select(e => e.MediaAssetId).Distinct().ToList();

        var assets = await dbContext
            .MediaAssets.Where(a => assetIds.Contains(a.Id))
            .Select(a => new { a.Id, a.OriginalExtension })
            .ToListAsync(cancellationToken);

        // Все три операции БД (удаление записей расписания, ассетов, отвязка серий) — атомарно в одной
        // транзакции; файлы удаляем только после успешного коммита (best-effort), чтобы при падении не
        // остаться с сериями, указывающими на уже удалённые с диска ассеты.
        await using var transaction = await dbContext.BeginTransactionAsync(cancellationToken);
        await dbContext
            .ScheduleEntries.Where(e => assetIds.Contains(e.MediaAssetId))
            .ExecuteDeleteAsync(cancellationToken);
        await dbContext
            .MediaAssets.Where(a => assetIds.Contains(a.Id))
            .ExecuteDeleteAsync(cancellationToken);

        // Серии шоу теперь указывают на удалённые ассеты — убираем их.
        foreach (var episode in episodes)
            show.RemoveEpisode(episode.Id);
        await dbContext.SaveChangesAsync(cancellationToken);
        await transaction.CommitAsync(cancellationToken);

        foreach (var asset in assets)
            await storage.DeleteAssetArtifactsAsync(
                asset.Id,
                asset.OriginalExtension,
                cancellationToken
            );

        return Result.Success(assets.Count);
    }
}
