using NAudio.Wave;

namespace ytLive.Services.Audio;

/// <summary>
/// Captures the user's desktop/game audio (TASK 4 ship step 4) via WASAPI
/// loopback on the default render device. Runs for the app's lifetime so the
/// game audio bar stays live in preview.
/// </summary>
public sealed class WasapiLoopbackAudioSource : IAudioSource
{
    private WasapiLoopbackCapture? _capture;

    public event Action? Started;
    public event Action<AudioSample>? SampleReady;
    public event Action<Exception>? Failed;

    public void Start()
    {
        if (_capture != null)
            throw new InvalidOperationException("Already started.");

        try
        {
            _capture = new WasapiLoopbackCapture();
            _capture.DataAvailable += OnDataAvailable;
            _capture.RecordingStopped += OnRecordingStopped;
            _capture.StartRecording();
            Started?.Invoke();
        }
        catch (Exception ex)
        {
            Stop();
            Failed?.Invoke(ex);
        }
    }

    public void Stop()
    {
        if (_capture == null)
            return;

        try
        {
            _capture.StopRecording();
        }
        catch
        {
        }
        _capture.Dispose();
        _capture = null;
    }

    public void Dispose() => Stop();

    private void OnDataAvailable(object? sender, WaveInEventArgs e)
    {
        if (e.BytesRecorded <= 0)
            return;

        var format = _capture?.WaveFormat ?? WaveFormat.CreateIeeeFloatWaveFormat(48000, 2);
        var samples = WaveToFloat.Convert(e.Buffer, e.BytesRecorded, format);
        if (samples.Length > 0)
            SampleReady?.Invoke(new AudioSample(samples, format.SampleRate, format.Channels));
    }

    private void OnRecordingStopped(object? sender, StoppedEventArgs e)
    {
        if (e.Exception != null)
            Failed?.Invoke(e.Exception);
    }
}
