//! Headless and hardware-backed audio capture logic.
//!
//! This module abstracts `cpal` to capture microphone input cleanly,
//! pushing raw samples directly to a lock-free ringbuffer.
//!
//! The `cpal` data callback is kept strictly lock-free and allocation-free
//! to satisfy real-time audio constraints.

use anyhow::{Result, anyhow};
use cpal::StreamConfig;
use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use ringbuf::HeapProd;
use ringbuf::traits::Producer;
use tracing::{error, info};

use super::{INPUT_CHANNELS, SAMPLE_RATE};

/// Sets up the default microphone device and returns the active cpal stream.
///
/// The stream pushes raw f32 samples into the provided ringbuffer producer.
///
/// # Errors
/// Returns an error if no input device is found or if the stream cannot be built.
pub fn start_audio_capture(mut producer: HeapProd<f32>) -> Result<cpal::Stream> {
    let host = cpal::default_host();

    let device = host
        .default_input_device()
        .ok_or_else(|| anyhow!("No default input device found"))?;

    // cpal 0.17 deprecates `name()` in favor of `description()`.
    let device_desc = device
        .description()
        .map_or_else(|_| "Unknown".to_string(), |d| d.name().to_string());
    info!("Using input device: {}", device_desc);

    let config = StreamConfig {
        channels: INPUT_CHANNELS,
        // cpal 0.17 changed SampleRate from a tuple struct to a plain u32 alias.
        sample_rate: SAMPLE_RATE,
        buffer_size: cpal::BufferSize::Default,
    };

    let stream = device.build_input_stream(
        &config,
        move |data: &[f32], _: &cpal::InputCallbackInfo| {
            // STRICT RULE: No locks, no allocations in this callback.
            // Just push samples to the ringbuffer.
            let _ = producer.push_slice(data);
        },
        move |err| {
            error!("An error occurred on the audio capture stream: {}", err);
        },
        None, // None = default timeout
    )?;

    stream.play()?;
    Ok(stream)
}
