namespace TeleWave.Domain.Programming;

/// <summary>
/// Позиция группы: ссылка на шоу или коллекцию плюс вес и порядок.
///
/// <see cref="ElementId"/> — полиморфная ссылка, поэтому внешнего ключа на неё нет: удаление шоу
/// или коллекции из библиотеки чистит позиции команд удаления, а не каскадом БД.
/// </summary>
public class GroupItem
{
    public Guid Id { get; private set; }
    public Guid GroupId { get; private set; }
    public GroupElementKind ElementKind { get; private set; }
    public Guid ElementId { get; private set; }

    /// <summary>Чем эта позиция является для группы — см. <see cref="GroupItemRole"/>.</summary>
    public GroupItemRole Role { get; private set; }

    /// <summary>
    /// Вес при случайном выборе внутри группы (по умолчанию 1). Не конфликтует с остыванием, если
    /// применять их в правильном порядке: сначала остывание отсекает недавно показанное, затем
    /// взвешенный выбор работает среди оставшихся.
    /// </summary>
    public int Weight { get; private set; }

    /// <summary>Порядок для последовательных стратегий (может иметь разрывы после удалений).</summary>
    public int Position { get; private set; }

    public const int DefaultWeight = 1;

    private GroupItem() { }

    internal static GroupItem Create(
        Guid groupId,
        GroupElementKind elementKind,
        Guid elementId,
        int position,
        GroupItemRole role = GroupItemRole.Member
    ) =>
        new()
        {
            Id = Guid.NewGuid(),
            GroupId = groupId,
            ElementKind = elementKind,
            ElementId = elementId,
            Role = role,
            Weight = DefaultWeight,
            Position = position,
        };

    internal void SetRole(GroupItemRole role) => Role = role;

    internal void SetPosition(int position) => Position = position;

    internal void SetWeight(int weight) => Weight = Math.Max(0, weight);
}
