//! CLI driver — capture or playback or both.

use std::path::PathBuf;
use std::process::ExitCode;
use std::time::Duration;

use audio_capture_playback_spike::{synth_sine_wav, AudioCapture, AudioPlayback};
use tracing::{info, warn};

fn main() -> ExitCode {
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
        )
        .init();

    let mode = std::env::args().nth(1).unwrap_or_else(|| "roundtrip".into());
    let tmp = std::env::temp_dir();
    let cap_path = tmp.join("chanora_audio_spike_capture.wav");
    let play_path = tmp.join("chanora_audio_spike_synth.wav");

    let result: anyhow::Result<()> = match mode.as_str() {
        "capture" => do_capture(&cap_path),
        "synth" => do_synth(&play_path),
        "playback" => do_playback(&play_path),
        "roundtrip" => do_roundtrip(&cap_path, &play_path),
        other => {
            eprintln!("unknown mode: {other}. Use one of: capture, synth, playback, roundtrip.");
            return ExitCode::from(2);
        }
    };

    if let Err(e) = result {
        eprintln!("error: {e:#}");
        return ExitCode::from(1);
    }
    ExitCode::SUCCESS
}

fn do_capture(path: &PathBuf) -> anyhow::Result<()> {
    info!(target: "spike", "capture → {}", path.display());
    let frames = AudioCapture::record_to_wav(path, Duration::from_secs(1))?;
    println!("captured {} frames to {}", frames, path.display());
    Ok(())
}

fn do_synth(path: &PathBuf) -> anyhow::Result<()> {
    info!(target: "spike", "synth → {}", path.display());
    let (frames, sr) = synth_sine_wav(path, 440.0, Duration::from_millis(500), 48_000)?;
    println!("synthesised {} frames @ {} Hz to {}", frames, sr, path.display());
    Ok(())
}

fn do_playback(path: &PathBuf) -> anyhow::Result<()> {
    info!(target: "spike", "playback ← {}", path.display());
    AudioPlayback::play_wav(path)?;
    println!("playback finished");
    Ok(())
}

fn do_roundtrip(cap_path: &PathBuf, play_path: &PathBuf) -> anyhow::Result<()> {
    // Try real capture first; if no input device or the capture failed,
    // fall back to synthesised audio so the playback path is still
    // exercised. This mirrors what production code would do during
    // a "device test" UI on headless or permission-denied hosts.
    let to_play = match AudioCapture::record_to_wav(cap_path, Duration::from_millis(750)) {
        Ok(n) if n > 0 => {
            info!(target: "spike", "captured {} frames; playing back", n);
            cap_path.clone()
        }
        Ok(_) => {
            warn!(target: "spike", "capture wrote 0 frames; falling back to synth");
            let (n, sr) = synth_sine_wav(play_path, 440.0, Duration::from_millis(500), 48_000)?;
            info!(target: "spike", frames = n, sample_rate = sr, "synthesised fallback");
            play_path.clone()
        }
        Err(e) => {
            warn!(target: "spike", error = %e, "capture unavailable; falling back to synth");
            let (n, sr) = synth_sine_wav(play_path, 440.0, Duration::from_millis(500), 48_000)?;
            info!(target: "spike", frames = n, sample_rate = sr, "synthesised fallback");
            play_path.clone()
        }
    };

    AudioPlayback::play_wav(&to_play)?;
    println!("round-trip complete (played from {})", to_play.display());
    Ok(())
}
