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

namespace TeleWave.Application.Media.MovieImport;

public sealed class AutoAttachMovieCommandHandler(
    IAppDbContext dbContext,
    IMetadataProviderResolver resolver,
    MovieMatcher matcher,
    ShowMetadataApplier applier
) : ICommandHandler<AutoAttachMovieCommand, Result<bool>>
{
    public async Task<Result<bool>> Handle(
        AutoAttachMovieCommand command,
        CancellationToken cancellationToken
    )
    {
        // Источник берём первый настроенный: выбирать его в фоне некому, а настроен обычно один.
        if (resolver.AvailableKeys is not [var provider, ..])
            return Result.Success(false);

        var asset = await dbContext.MediaAssets.FirstOrDefaultAsync(
            a => a.Id == command.AssetId,
            cancellationToken
        );
        if (asset is null)
            return Result.Failure<bool>(MediaErrors.NotFound);

        // Ассет мог уже уехать в шоу вручную, пока файл ждал очереди.
        var taken = await dbContext.Shows.AnyAsync(
            s => s.Episodes.Any(e => e.MediaAssetId == command.AssetId),
            cancellationToken
        );
        if (taken)
            return Result.Success(false);

        var candidate = await matcher.PickConfidentAsync(
            command.FileName,
            provider,
            cancellationToken
        );
        if (candidate is null)
            return Result.Success(false);

        // Фильм, уже стоящий в библиотеке под этим идентификатором, повторно не заводим: это не
        // второй фильм, а второй файл того же — разбирать такое человеку.
        var duplicate = await dbContext.Shows.AnyAsync(
            s => s.MetadataProvider == provider && s.MetadataExternalId == candidate.ExternalId,
            cancellationToken
        );
        if (duplicate)
            return Result.Success(false);

        var show = Show.Create(candidate.Title, ShowKind.Single);
        dbContext.Shows.Add(show);
        show.AddEpisode(command.AssetId);

        var applied = await applier.ApplyAsync(
            show,
            provider,
            candidate.ExternalId,
            cancellationToken
        );

        // Имя берём из карточки источника: в поиске оно могло прийти из другой локали.
        if (applied.IsSuccess && applied.Value.Title is { Length: > 0 } title)
            show.SetName(title);

        // Метаданные не легли — шоу с файлом всё равно полезнее, чем ассет без шоу: название
        // у него правильное, а постер дотянет массовое обогащение.
        return Result.Success(applied.IsSuccess);
    }
}
