using System.Collections.Concurrent;
namespace Flaro.Api;
/// Was gerade läuft, je Gerät.
///
///
///
/// Im Arbeitsspeicher, nicht in der Datenbank. „Wer schaut gerade
/// was" ist eine Frage über den Augenblick; sie zu speichern hiesse, nach
/// einem Neustart Wiedergaben anzuzeigen, die es nicht mehr gibt. Fällt der
/// Container aus, ist die Antwort ohnehin „niemand".
///
///
/// Abgeleitet aus den Fortschrittsmeldungen, nicht aus einer eigenen
/// Anmeldung am Spieler. Jeder Client meldet beim Abspielen ohnehin alle
/// paar Sekunden, wo er steht — wer das als Lebenszeichen liest, braucht
/// kein zweites Verfahren, das ein Client vergessen könnte. Bleibt die
/// Meldung aus, läuft der Eintrag von selbst ab.
///
///
public sealed class PlaybackSessions(TimeProvider clock)
{
/// Wie lange eine Wiedergabe ohne Meldung als laufend gilt.
///
///
/// Die Clients melden alle zehn Sekunden. Eine Minute lässt Raum für
/// einen Aussetzer, ohne dass eine längst beendete Wiedergabe noch
/// minutenlang im Dashboard steht.
///
public static readonly TimeSpan Lebensdauer = TimeSpan.FromMinutes(1);
private readonly ConcurrentDictionary _laufend = new();
public sealed record Wiedergabe(
string DeviceKey,
Guid UserId,
string UserName,
Guid ItemId,
string Title,
string? SubTitle,
string? PosterImage,
TimeSpan Position,
TimeSpan? Runtime,
string DeviceName,
DateTimeOffset LastSeenAt);
/// Hält fest, dass dieses Gerät gerade etwas abspielt.
public void Melden(Wiedergabe wiedergabe) =>
_laufend[wiedergabe.DeviceKey] = wiedergabe;
/// Nimmt eine Wiedergabe heraus — beim Beenden.
public void Beenden(string deviceKey) => _laufend.TryRemove(deviceKey, out _);
/// Was gerade läuft. Abgelaufenes fällt dabei heraus.
public IReadOnlyList Laufende()
{
var grenze = clock.GetUtcNow() - Lebensdauer;
// Beiläufig aufräumen. Ein eigener Hintergrunddienst für eine
// Handvoll Einträge wäre Aufwand ohne Gegenwert.
foreach (var (schluessel, eintrag) in _laufend)
{
if (eintrag.LastSeenAt < grenze) _laufend.TryRemove(schluessel, out _);
}
return _laufend.Values.OrderBy(w => w.UserName).ThenBy(w => w.Title).ToList();
}
}