using LiteCqrs;
using Microsoft.EntityFrameworkCore;
using TeleWave.Application.Common.Interfaces;
using TeleWave.Application.Common.Models;
using TeleWave.Domain.Media;

namespace TeleWave.Application.Media.Register;

public sealed class RegisterMediaAssetCommandHandler(IAppDbContext dbContext, IMediaStorage storage)
    : ICommandHandler<RegisterMediaAssetCommand, Result<Guid>>
{
    public async Task<Result<Guid>> Handle(
        RegisterMediaAssetCommand command,
        CancellationToken cancellationToken
    )
    {
        // Дедуп по имени: тот же файл уже в библиотеке (кроме проваленных — их разрешаем перезалить).
        var duplicate = await dbContext.MediaAssets.AnyAsync(
            x =>
                x.OriginalFileName == command.OriginalFileName
                && x.Status != MediaAssetStatus.Failed,
            cancellationToken
        );
        if (duplicate)
            return Result.Failure<Guid>(MediaErrors.DuplicateFileName);

        var extension = Path.GetExtension(command.OriginalFileName).ToLowerInvariant();
        var asset = MediaAsset.Register(command.OriginalFileName, extension, command.Source);

        // Сначала фиксируем ассет в БД, затем переносим файл в originals/. Если перенос не удался —
        // откатываем регистрацию, чтобы не оставить orphan (либо есть и строка БД, и файл, либо нет ни
        // того, ни другого). Обратный порядок оставлял бы перемещённый файл без строки БД при сбое save.
        dbContext.MediaAssets.Add(asset);
        await dbContext.SaveChangesAsync(cancellationToken);
        try
        {
            await storage.PromoteToOriginalAsync(
                command.Source,
                command.SourceToken,
                asset.Id,
                extension,
                cancellationToken
            );
        }
        catch
        {
            dbContext.MediaAssets.Remove(asset);
            await dbContext.SaveChangesAsync(cancellationToken);
            throw;
        }

        return Result.Success(asset.Id);
    }
}
