using FluentValidation;
using TeleWave.Domain.Programming;

namespace TeleWave.Application.Programming.Templates;

/// <summary>Полный набор настроек слота — общий для создания и правки.</summary>
public sealed record SlotInput(
    string Title,
    int? Weekday,
    TimeOnly TargetStart,
    int TargetDurationMinutes,
    Daypart Daypart,
    SlotKind SlotKind,
    Guid? GroupId,
    SlotStrategy? Strategy,
    RepeatSource? RepeatSource,
    SlotBlockMode BlockMode,
    int BlockValue,
    OverflowPolicy OverflowPolicy,
    bool IsAnchor,
    int MaxDriftMinutes,
    int? SnapToMinutes,
    /// <summary>Стык между единицами внутри блока.</summary>
    Guid? JunctionBetweenId = null,
    /// <summary>Стык в конце блока (null — берётся стык шаблона по умолчанию).</summary>
    Guid? JunctionAfterId = null
);

public sealed class SlotInputValidator : AbstractValidator<SlotInput>
{
    /// <summary>Округлять старт можно только до значений, которые читаются как «круглое время».</summary>
    private static readonly int[] AllowedSnap = [5, 10, 15, 30];

    public SlotInputValidator()
    {
        RuleFor(x => x.Title).NotEmpty().MaximumLength(256);
        RuleFor(x => x.Weekday).InclusiveBetween(0, 6).When(x => x.Weekday is not null);

        // Сутки — верхняя граница осмысленного слота: длиннее он всё равно перекроет сам себя.
        RuleFor(x => x.TargetDurationMinutes).InclusiveBetween(1, 24 * 60);
        RuleFor(x => x.BlockValue).GreaterThan(0);
        RuleFor(x => x.MaxDriftMinutes).InclusiveBetween(0, 12 * 60);

        RuleFor(x => x.SnapToMinutes)
            .Must(value => value is null || AllowedSnap.Contains(value.Value))
            .WithMessage("Округление старта допустимо до 5, 10, 15 или 30 минут.");

        RuleFor(x => x.Strategy!.CooldownDays)
            .InclusiveBetween(0, 3650)
            .When(x => x.Strategy is not null);

        RuleFor(x => x.RepeatSource!.DaysAgo)
            .InclusiveBetween(1, 365)
            .When(x => x.RepeatSource is not null);
        RuleFor(x => x.RepeatSource!.DurationMinutes)
            .InclusiveBetween(1, 24 * 60)
            .When(x => x.RepeatSource is not null);
    }
}
