using FluentValidation;
using LiteCqrs;
using TeleWave.Application.Common.Models;

namespace TeleWave.Application.Programming.Templates.Transfer;

/// <summary>
/// Загрузка сетки из файла. <paramref name="Replace"/> — снести существующие слоты и построить
/// заново; иначе слои и слоты добавляются к тому, что есть.
/// </summary>
public sealed record ImportGridCommand(Guid ChannelId, GridConfig Config, bool Replace)
    : ICommand<Result<GridImportResultDto>>;

/// <summary>
/// Что получилось. Пропущенные слоты — не ошибка импорта: файл мог прийти от ИИ или с другой
/// установки, где были свои группы, и валить весь импорт из-за одной незнакомой ссылки значит
/// заставить админа чинить JSON руками.
/// </summary>
public sealed record GridImportResultDto(
    int Layers,
    int Slots,
    int Skipped,
    int Removed,
    /// <summary>Сколько групп и коллекций файл принёс с собой — существующие не пересоздаются.</summary>
    int Groups,
    int Collections,
    IReadOnlyList<string> Warnings
);

public sealed class ImportGridCommandValidator : AbstractValidator<ImportGridCommand>
{
    public ImportGridCommandValidator()
    {
        RuleFor(x => x.Config.Format)
            .Equal(GridConfig.CurrentFormat)
            .WithMessage($"Ожидается формат «{GridConfig.CurrentFormat}».");
        RuleFor(x => x.Config.Version).InclusiveBetween(1, GridConfig.CurrentVersion);
        RuleFor(x => x.Config.Layers).NotEmpty();
        // Потолок на объём файла: недельная сетка — это десятки слотов, а не десятки тысяч.
        RuleFor(x => x.Config.Layers.Count).LessThanOrEqualTo(64);
        RuleFor(x => x.Config.Groups!.Count)
            .LessThanOrEqualTo(256)
            .When(x => x.Config.Groups is not null);
        RuleFor(x => x.Config.Collections!.Count)
            .LessThanOrEqualTo(256)
            .When(x => x.Config.Collections is not null);
        RuleForEach(x => x.Config.Layers)
            .ChildRules(layer =>
            {
                layer.RuleFor(l => l.Name).NotEmpty().MaximumLength(128);
                layer.RuleFor(l => l.Slots.Count).LessThanOrEqualTo(2048);
            });
    }
}
