using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Domain.Library;

namespace TeleWave.Application.Media;

/// <summary>
/// Сносит медиа шоу: записи расписания по его ассетам, сами ассеты и файлы на диске.
///
/// Порядок жёсткий и общий для всех, кто этим пользуется: сначала БД в транзакции, файлы — только
/// после успешного коммита. Наоборот было бы хуже всего: при падении остались бы серии, ссылающиеся
/// на удалённые с диска файлы, и раздача упёрлась бы в пустоту.
/// </summary>
public sealed class ShowMediaEraser(IAppDbContext dbContext, IMediaStorage storage)
{
    /// <summary>Ассет к удалению с диска: идентификатор и расширение оригинала.</summary>
    public readonly record struct ErasedAsset(Guid Id, string Extension);

    /// <summary>
    /// Удаляет из БД ассеты шоу и связанные записи расписания. Возвращает то, что предстоит убрать
    /// с диска, — вызывающий делает это после коммита своей транзакции.
    /// </summary>
    public async Task<IReadOnlyList<ErasedAsset>> EraseAsync(
        Show show,
        CancellationToken cancellationToken
    )
    {
        var assetIds = show.Episodes.Select(e => e.MediaAssetId).Distinct().ToList();
        if (assetIds.Count == 0)
            return [];

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

        await dbContext
            .ScheduleEntries.Where(e => assetIds.Contains(e.MediaAssetId))
            .ExecuteDeleteAsync(cancellationToken);
        await dbContext
            .MediaAssets.Where(a => assetIds.Contains(a.Id))
            .ExecuteDeleteAsync(cancellationToken);

        return assets;
    }

    /// <summary>Убирает файлы (оригинал и нарезку). Best-effort: строки в БД уже удалены.</summary>
    public async Task DeleteFilesAsync(
        IReadOnlyList<ErasedAsset> assets,
        CancellationToken cancellationToken
    )
    {
        foreach (var asset in assets)
            await storage.DeleteAssetArtifactsAsync(asset.Id, asset.Extension, cancellationToken);
    }
}
