using ErsatzTV.Core.Domain;
using ErsatzTV.Core.Extensions;
using ErsatzTV.Core.Interfaces.Scheduling;
namespace ErsatzTV.Core.Scheduling;
///
/// Weighted / fair-share distribution (issue #70). Picks a *source* by smooth weighted round-robin,
/// then takes that source's next item. A source's is its
/// relative share of airtime: weights 3:1 emit A A B A per rotation.
///
/// Fair-share is the equal-weights degenerate case (the default, since Weight defaults to 1):
/// every source airs equally often regardless of library size, so a small show loops while a
/// large one works through its items. This is what distinguishes it from
/// , whose balanced shuffle plays every item
/// exactly once per cycle and therefore leaves airtime proportional to collection size
/// (it prevents clumping, not domination).
///
///
/// Deterministic and stateless: the emitted sequence is a pure function of
/// (, ),
/// so it restores by replay exactly like its siblings and needs no per-source persisted counters.
///
///
public class WeightedShuffleCollectionEnumerator : IMediaCollectionEnumerator
{
///
/// Upper bound on the precomputed rotation, so a large collection paired with a low weight
/// (picks needed grows as items * totalWeight / weight) can't allocate without limit. Hitting the
/// clamp only means the largest source doesn't finish its items within one rotation before the
/// reseed; the weight ratio itself is unaffected.
///
private const int MaxCycleLength = 100_000;
///
/// Bounds the avoid-an-immediate-repeat retry when a rotation wraps. Unlike
/// , whose reshuffle randomizes which item leads the
/// next cycle, this order's lead item is decided by weight — the heaviest source always wins the first
/// pick. So when that source has a single item the lead never changes and an unbounded retry would spin
/// forever. Avoiding a back-to-back repeat is a nicety; never terminating is not.
///
private const int MaxReshuffleAttempts = 10;
private readonly CancellationToken _cancellationToken;
private readonly IList _collections;
private readonly Lazy