namespace ytLive.Services;

/// <summary>
/// Default <see cref="IGameAudioDetector"/>: samples a full-screen monitor
/// provider (the existing <c>IFullScreenDetector</c>) and the live loopback
/// level and advances a <see cref="GameAudioHysteresis"/>. The pure transitions
/// live in GameAudioHysteresis (unit-tested); this wrapper owns the providers
/// and the raised-changed event. WPF-free — the VM owns the poll timer.
/// </summary>
public sealed class GameAudioDetector : IGameAudioDetector
{
    private const float SoundFloor = 0.005f;

    private readonly Func<int?> _foregroundFullScreenMonitorProvider;
    private readonly Func<float> _loopbackLevelProvider;
    private readonly Func<DateTime> _now;
    private readonly GameAudioHysteresis _hysteresis = new();

    /// <param name="foregroundFullScreenMonitorProvider">Returns the monitor a
    /// full-screen foreground window covers, or null when windowed/none.</param>
    /// <param name="loopbackLevelProvider">Current smoothed desktop/game level (0..1).</param>
    /// <param name="now">Clock for the hysteresis windows; injectable for tests.</param>
    public GameAudioDetector(
        Func<int?> foregroundFullScreenMonitorProvider,
        Func<float> loopbackLevelProvider,
        Func<DateTime>? now = null)
    {
        _foregroundFullScreenMonitorProvider = foregroundFullScreenMonitorProvider;
        _loopbackLevelProvider = loopbackLevelProvider;
        _now = now ?? (() => DateTime.Now);
    }

    public bool IsGameAudioActive => _hysteresis.IsActive;

    public event Action<bool>? IsGameAudioActiveChanged;

    public void Poll()
    {
        var before = _hysteresis.IsActive;
        var isFullScreen = _foregroundFullScreenMonitorProvider() != null;
        var hasSound = _loopbackLevelProvider() > SoundFloor;
        _hysteresis.Update(isFullScreen, hasSound, _now());
        if (before != _hysteresis.IsActive)
            IsGameAudioActiveChanged?.Invoke(_hysteresis.IsActive);
    }
}
