using System.Text.Json;
using System.Text.Json.Serialization;

namespace TeleWave.Application.Programming.Templates;

/// <summary>Как слот выбирает элемент группы.</summary>
public enum SlotStrategyType
{
    /// <summary>Элементы группы по порядку позиций.</summary>
    Sequential = 0,

    /// <summary>Случайный элемент, не показанный последние N дней.</summary>
    RandomWithCooldown = 1,

    /// <summary>Всегда один и тот же элемент.</summary>
    Fixed = 2,
}

/// <summary>Что делать, когда остывание отсекло всех кандидатов.</summary>
public enum CooldownFallback
{
    /// <summary>Взять элемент, не игравший дольше всех.</summary>
    OldestFirst = 0,

    /// <summary>Проигнорировать остывание на этот выход.</summary>
    IgnoreCooldown = 1,
}

/// <summary>
/// Стратегия выбора элемента внутри слота. Отвечает только за выбор элемента: единицы внутри элемента
/// всегда идут по порядку от курсора — сериал не должен прыгать по сериям.
///
/// Размер блока живёт на слоте отдельно и ортогонален стратегии: любую можно скомбинировать
/// с «одна единица», «четыре подряд» или «пока не наберётся два часа».
/// </summary>
public sealed record SlotStrategy(
    SlotStrategyType Type = SlotStrategyType.Sequential,
    /// <summary>Начинать группу заново, дойдя до конца (иначе слот останавливается).</summary>
    bool RestartOnEnd = true,
    /// <summary>Дней остывания для <see cref="SlotStrategyType.RandomWithCooldown"/>.</summary>
    int CooldownDays = 0,
    CooldownFallback Fallback = CooldownFallback.OldestFirst,
    /// <summary>Закреплённый элемент для <see cref="SlotStrategyType.Fixed"/>.</summary>
    Guid? FixedElementId = null
)
{
    private static readonly JsonSerializerOptions Options = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        Converters = { new JsonStringEnumConverter() },
    };

    public string ToJson() => JsonSerializer.Serialize(this, Options);

    /// <summary>Разбирает сохранённую стратегию. Повреждённый JSON — как отсутствие стратегии:
    /// слот получит поведение по умолчанию, а не уронит генерацию всего канала.</summary>
    public static SlotStrategy? FromJson(string? json)
    {
        if (string.IsNullOrWhiteSpace(json))
            return null;

        try
        {
            return JsonSerializer.Deserialize<SlotStrategy>(json, Options);
        }
        catch (JsonException)
        {
            return null;
        }
    }
}
