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

namespace TeleWave.Application.Programming.Groups.AddGroupElements;

public sealed class AddGroupElementsCommandHandler(IAppDbContext dbContext, GroupStatsService stats)
    : ICommandHandler<AddGroupElementsCommand, Result<int>>
{
    public async Task<Result<int>> Handle(
        AddGroupElementsCommand command,
        CancellationToken cancellationToken
    )
    {
        var group = await dbContext
            .Groups.Include(g => g.Items)
            .FirstOrDefaultAsync(g => g.Id == command.GroupId, cancellationToken);
        if (group is null)
            return Result.Failure<int>(GroupErrors.NotFound);

        var requested = command.Elements.Distinct().ToList();

        // Ссылки полиморфные, внешнего ключа нет — проверяем существование сами, иначе в группе
        // осядут позиции, которые никогда не развернутся в контент.
        var showIds = requested
            .Where(e => e.ElementKind == GroupElementKind.Show)
            .Select(e => e.ElementId)
            .ToList();
        var collectionIds = requested
            .Where(e => e.ElementKind == GroupElementKind.Collection)
            .Select(e => e.ElementId)
            .ToList();

        var knownShows = await dbContext
            .Shows.Where(s => showIds.Contains(s.Id))
            .Select(s => s.Id)
            .ToListAsync(cancellationToken);
        var knownCollections = await dbContext
            .Collections.Where(c => collectionIds.Contains(c.Id))
            .Select(c => c.Id)
            .ToListAsync(cancellationToken);

        if (knownShows.Count != showIds.Count || knownCollections.Count != collectionIds.Count)
            return Result.Failure<int>(GroupErrors.ElementNotFound);

        var added = requested.Count(element =>
            group.AddElement(element.ElementKind, element.ElementId) is not null
        );

        await stats.RecomputeAsync(group, cancellationToken);
        return Result.Success(added);
    }
}
