namespace ytLive.Services.Audio;

/// <summary>
/// Computes the smoothed mic level (0..1) from captured samples. Pure —
/// unit-tested; the <see cref="AudioMixer"/> only feeds it and forwards the
/// result. RMS-based so it tracks perceived loudness, smoothed so the meter
/// does not flicker.
/// </summary>
public sealed class AudioLevelMeter
{
    private const float Smoothing = 0.2f;
    private float _level;

    public float Level => _level;

    /// <summary>
    /// Maps a linear level (0..1) onto the meter's display scale: -60 dBFS..0 dBFS
    /// spread linearly across 0..1, with +10 dB of input amplification. Linear RMS
    /// of real speech or game audio is ~0.01..0.1 (-40..-20 dBFS), which leaves a
    /// flat (linear) meter looking dead; the log scale makes typical levels occupy
    /// the bar and the amplification pushes real speech peaks into the red zone
    /// (0.8+) at maxed volume instead of hovering at its edge. Inputs at or below
    /// -60 dBFS (0.001 linear) read as zero — the meter never idles on background noise.
    /// </summary>
    public static float ToDisplay(float linear)
    {
        if (linear <= 0.001f)
            return 0f;
        var db = 20f * MathF.Log10(linear) + 10f;
        return Math.Clamp(1f + db / 60f, 0f, 1f);
    }

    public float Push(AudioSample sample)
    {
        if (sample.Samples.Length == 0)
            return _level;

        double sumSquares = 0;
        var count = 0;
        foreach (var value in sample.Samples)
        {
            sumSquares += value * value;
            count++;
        }

        var rms = (float)Math.Sqrt(sumSquares / count);
        _level = _level * (1 - Smoothing) + rms * Smoothing;
        return _level;
    }

    public void Reset() => _level = 0;
}
