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

namespace TeleWave.Application.Library.Collections.AddShowsToCollection;

public sealed class AddShowsToCollectionCommandHandler(IAppDbContext dbContext)
    : ICommandHandler<AddShowsToCollectionCommand, Result<AddShowsToCollectionResultDto>>
{
    public async Task<Result<AddShowsToCollectionResultDto>> Handle(
        AddShowsToCollectionCommand command,
        CancellationToken cancellationToken
    )
    {
        var showIds = command.ShowIds.Distinct().ToList();
        var shows = await dbContext
            .Shows.AsNoTracking()
            .Where(s => showIds.Contains(s.Id))
            .Select(s => new
            {
                s.Id,
                s.Name,
                s.Year,
            })
            .ToListAsync(cancellationToken);
        if (shows.Count == 0)
            return Result.Failure<AddShowsToCollectionResultDto>(ShowErrors.NotFound);

        var collection = await ResolveCollectionAsync(command, cancellationToken);
        if (collection is null)
            return Result.Failure<AddShowsToCollectionResultDto>(CollectionErrors.NotFound);

        // Год — главный порядок франшизы; без года часть уходит в конец, там её и переставят руками.
        var ordered = shows
            .OrderBy(s => s.Year is null)
            .ThenBy(s => s.Year)
            .ThenBy(s => s.Name, StringComparer.CurrentCultureIgnoreCase);

        var added = ordered.Count(show => collection.AddShow(show.Id) is not null);

        return Result.Success(
            new AddShowsToCollectionResultDto(collection.Id, collection.Name, added)
        );
    }

    private async Task<Collection?> ResolveCollectionAsync(
        AddShowsToCollectionCommand command,
        CancellationToken cancellationToken
    )
    {
        if (command.CollectionId is { } id)
            return await dbContext
                .Collections.Include(c => c.Items)
                .FirstOrDefaultAsync(c => c.Id == id, cancellationToken);

        var created = Collection.Create(command.NewCollectionName!);
        dbContext.Collections.Add(created);
        return created;
    }
}
