using ErsatzTV.Core.Domain; using ErsatzTV.Core.Domain.Scheduling; using ErsatzTV.Core.Interfaces.Scheduling; using ErsatzTV.Core.Scheduling; using ErsatzTV.Infrastructure.Data; using ErsatzTV.Infrastructure.Extensions; using Microsoft.EntityFrameworkCore; namespace ErsatzTV.Infrastructure.Scheduling; public class RerunHelper(IDbContextFactory dbContextFactory) : IRerunHelper { private int _playoutId; private readonly Dictionary> _mediaItems = new(); private readonly Dictionary> _history = new(); private readonly Dictionary _firstRunOrder = new(); private readonly Dictionary _rerunOrder = new(); private readonly Dictionary> _historyToRemove = new(); private readonly Dictionary> _historyToAdd = new(); public bool ClearHistory { get; set; } public async Task InitWithMediaItems( int playoutId, CollectionKey collectionKey, List mediaItems, CancellationToken cancellationToken) { if (_mediaItems.TryAdd(collectionKey.RerunCollectionId!.Value, mediaItems)) { _playoutId = playoutId; await using TvContext dbContext = await dbContextFactory.CreateDbContextAsync(cancellationToken); Option maybeRerunCollection = await dbContext.RerunCollections .AsNoTracking() .SelectOneAsync( rc => rc.Id == collectionKey.RerunCollectionId, rc => rc.Id == collectionKey.RerunCollectionId, cancellationToken); foreach (RerunCollection rerunCollection in maybeRerunCollection) { System.Collections.Generic.HashSet history = await dbContext.RerunHistory .AsNoTracking() .Filter(rh => rh.PlayoutId == playoutId && rh.RerunCollectionId == rerunCollection.Id) .Map(rh => rh.MediaItemId) .ToHashSetAsync(cancellationToken); if (ClearHistory) { List historyToRemove = await dbContext.RerunHistory .AsNoTracking() .Filter(rh => rh.PlayoutId == playoutId && rh.RerunCollectionId == rerunCollection.Id) .Map(rh => rh.Id) .ToListAsync(cancellationToken); _historyToRemove.Add(rerunCollection.Id, historyToRemove); history.Clear(); } _history.Add(rerunCollection.Id, history); // save playback orders _firstRunOrder.Add(rerunCollection.Id, rerunCollection.FirstRunPlaybackOrder); _rerunOrder.Add(rerunCollection.Id, rerunCollection.RerunPlaybackOrder); _historyToAdd.Add(rerunCollection.Id, []); } } } public IMediaCollectionEnumerator CreateEnumerator( CollectionKey collectionKey, CollectionEnumeratorState state, CancellationToken cancellationToken) { var playbackOrder = collectionKey.CollectionType is CollectionType.RerunFirstRun ? _firstRunOrder[collectionKey.RerunCollectionId!.Value] : _rerunOrder[collectionKey.RerunCollectionId!.Value]; return RerunMediaCollectionEnumerator.Create( this, collectionKey, _mediaItems[collectionKey.RerunCollectionId!.Value], playbackOrder, state, cancellationToken); } public bool IsFirstRun(CollectionKey collectionKey, int mediaItemId) => !_history[collectionKey.RerunCollectionId!.Value].Contains(mediaItemId); public bool IsRerun(CollectionKey collectionKey, int mediaItemId) => _history[collectionKey.RerunCollectionId!.Value].Contains(mediaItemId); public int FirstRunCount(CollectionKey collectionKey) => _mediaItems[collectionKey.RerunCollectionId!.Value].Count - _history[collectionKey.RerunCollectionId!.Value].Count; public int RerunCount(CollectionKey collectionKey) => _history[collectionKey.RerunCollectionId!.Value].Count; public void AddToHistory(CollectionKey collectionKey, int mediaItemId, DateTimeOffset scheduledAt) { var history = new RerunHistory { PlayoutId = _playoutId, RerunCollectionId = collectionKey.RerunCollectionId!.Value, MediaItemId = mediaItemId, When = scheduledAt.UtcDateTime }; if (_history[collectionKey.RerunCollectionId!.Value].Add(mediaItemId)) { _historyToAdd[collectionKey.RerunCollectionId!.Value].Add(history); } } public System.Collections.Generic.HashSet GetHistoryToRemove() => _historyToRemove.SelectMany(kvp => kvp.Value).ToHashSet(); public List GetHistoryToAdd() => _historyToAdd.SelectMany(kvp => kvp.Value).ToList(); }