using System.Text.Json;
using System.Text.Json.Serialization;
using TeleWave.Domain.Programming;

namespace TeleWave.Application.Programming.Templates;

/// <summary>
/// Условия показа врезки. Хранятся структурно, а не выражением: парсер выражений, его валидация
/// и отдельный UI обошлись бы дорого, а покрывают ровно те же несколько реальных случаев.
/// </summary>
public sealed record JunctionConditions(
    /// <summary>Ставить только при смене шоу, а не между сериями одного.</summary>
    bool OnlyOnElementChange = false,
    /// <summary>Не ставить чаще, чем раз в N минут (0 — без ограничения).</summary>
    int MinMinutesBetween = 0,
    /// <summary>Только в эти дейпарты (пусто — в любые).</summary>
    IReadOnlyList<Daypart>? Dayparts = null,
    /// <summary>Только в это окно суток канала (null — в любое время).</summary>
    JunctionTimeWindow? TimeWindow = null,
    /// <summary>Вероятность показа в процентах; 100 — всегда.</summary>
    int Chance = 100,
    /// <summary>Ставить только в пределах ±N минут от круглого часа (0 — без привязки).</summary>
    int NearHourMinutes = 0
)
{
    private static readonly JsonSerializerOptions Options = new()
    {
        PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
        DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull,
        Converters = { new JsonStringEnumConverter() },
    };

    /// <summary>Действует ли врезка в этом дейпарте.</summary>
    public bool AllowsDaypart(Daypart daypart) =>
        Dayparts is not { Count: > 0 } || Dayparts.Contains(daypart);

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

    public static JunctionConditions? FromJson(string? json)
    {
        if (string.IsNullOrWhiteSpace(json))
            return null;

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

/// <summary>Окно суток канала; допускает переход через полночь («с 23:00 до 06:00»).</summary>
public sealed record JunctionTimeWindow(TimeOnly From, TimeOnly To);
