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

namespace TeleWave.Application.Programming.Groups.UpdateGroup;

public sealed class UpdateGroupCommandHandler(
    IAppDbContext dbContext,
    DynamicGroupResolver dynamicResolver,
    GroupStatsService stats
) : ICommandHandler<UpdateGroupCommand, Result>
{
    public async Task<Result> Handle(
        UpdateGroupCommand 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(GroupErrors.NotFound);

        group.Rename(command.Name, command.Description);
        group.SetFilter(command.Filter?.ToJson());

        if (command.Mode is { } mode && mode != group.Mode)
            await SwitchModeAsync(group, mode, cancellationToken);

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

    /// <summary>
    /// Переход в статический режим материализует вычисленный состав: правило домен не понимает,
    /// а группа не должна опустеть от смены режима — на неё уже ссылаются слоты. Обратный переход
    /// домен делает сам (список становится закреплённым).
    /// </summary>
    private async Task SwitchModeAsync(
        Domain.Programming.Group group,
        GroupMode mode,
        CancellationToken cancellationToken
    )
    {
        if (mode == GroupMode.Dynamic)
        {
            group.SetMode(mode);
            return;
        }

        var composition = await dynamicResolver.ResolveAsync(group, cancellationToken);
        group.SetMode(mode);
        foreach (var element in composition)
            group.AddElement(element.Kind, element.Id);
    }
}
