//! 音频采集：cpal 输入流 → 单声道 → 线性重采样 16kHz i16 → 100ms 帧（3200B）。

use cpal::traits::{DeviceTrait, HostTrait, StreamTrait};
use std::sync::mpsc::Sender;

pub const TARGET_RATE: u32 = 16000;
pub const FRAME_SAMPLES: usize = 1600; // 100ms @16k

pub fn list_devices() -> Vec<String> {
    let host = cpal::default_host();
    host.input_devices()
        .map(|it| it.filter_map(|d| d.name().ok()).collect())
        .unwrap_or_default()
}

/// 触发麦克风授权（11F 引导页）：短暂起一个输入流，首次会弹系统授权框。
/// 返回 true 表示流可建立（设备可用 / 已授权或用户刚授权）。
#[tauri::command]
pub async fn request_microphone() -> bool {
    tauri::async_runtime::spawn_blocking(|| {
        let (tx, rx) = std::sync::mpsc::channel::<Vec<u8>>();
        match start("", tx) {
            Ok(capture) => {
                std::thread::sleep(std::time::Duration::from_millis(300));
                drop(rx);
                drop(capture);
                true
            }
            Err(_) => false,
        }
    })
    .await
    .unwrap_or(false)
}

/// 采集句柄：drop 即停止。cpal::Stream 在 macOS 上非 Send，
/// 因此流由专用线程持有，句柄只保留停止信号端。
pub struct Capture {
    stop: Option<Sender<()>>,
}

impl Drop for Capture {
    fn drop(&mut self) {
        self.stop.take(); // 关闭通道 → 采集线程退出并销毁流
    }
}

/// 启动采集；每凑满 100ms 帧经 `tx` 发出。
pub fn start(device_name: &str, tx: Sender<Vec<u8>>) -> Result<Capture, String> {
    let (stop_tx, stop_rx) = std::sync::mpsc::channel::<()>();
    let (ready_tx, ready_rx) = std::sync::mpsc::channel::<Result<(), String>>();
    let device_name = device_name.to_string();

    std::thread::spawn(move || {
        let built = build_stream(&device_name, tx);
        match built {
            Ok(stream) => {
                if let Err(e) = stream.play() {
                    let _ = ready_tx.send(Err(e.to_string()));
                    return;
                }
                let _ = ready_tx.send(Ok(()));
                // 阻塞直至句柄 drop（发送端关闭 → recv Err）
                let _ = stop_rx.recv();
                drop(stream);
            }
            Err(e) => {
                let _ = ready_tx.send(Err(e));
            }
        }
    });

    ready_rx
        .recv()
        .map_err(|_| "采集线程异常退出".to_string())??;
    Ok(Capture { stop: Some(stop_tx) })
}

fn build_stream(device_name: &str, tx: Sender<Vec<u8>>) -> Result<cpal::Stream, String> {
    let host = cpal::default_host();
    let device = if device_name.is_empty() {
        host.default_input_device()
    } else {
        host.input_devices()
            .ok()
            .and_then(|mut it| it.find(|d| d.name().map(|n| n == device_name).unwrap_or(false)))
            .or_else(|| host.default_input_device())
    }
    .ok_or("没有可用麦克风")?;

    let config = device.default_input_config().map_err(|e| e.to_string())?;
    let src_rate = config.sample_rate().0;
    let channels = config.channels() as usize;
    let mut resampler = Resampler::new(src_rate, channels, tx);

    let err_fn = |e| log::error!("audio stream error: {e}");
    match config.sample_format() {
        cpal::SampleFormat::F32 => device.build_input_stream(
            &config.into(),
            move |data: &[f32], _| resampler.push_f32(data),
            err_fn,
            None,
        ),
        cpal::SampleFormat::I16 => device.build_input_stream(
            &config.into(),
            move |data: &[i16], _| resampler.push_i16(data),
            err_fn,
            None,
        ),
        f => return Err(format!("不支持的采样格式: {f:?}")),
    }
    .map_err(|e| e.to_string())
}

/// 线性插值重采样 + 分帧。
struct Resampler {
    src_rate: u32,
    channels: usize,
    pos: f64,
    step: f64,
    prev: f32,
    buf: Vec<i16>,
    tx: Sender<Vec<u8>>,
}

impl Resampler {
    fn new(src_rate: u32, channels: usize, tx: Sender<Vec<u8>>) -> Self {
        Self {
            src_rate,
            channels,
            pos: 0.0,
            step: src_rate as f64 / TARGET_RATE as f64,
            prev: 0.0,
            buf: Vec::with_capacity(FRAME_SAMPLES * 2),
            tx,
        }
    }

    fn push_f32(&mut self, data: &[f32]) {
        let mono: Vec<f32> = data
            .chunks(self.channels)
            .map(|c| c.iter().sum::<f32>() / self.channels as f32)
            .collect();
        self.resample(&mono);
    }

    fn push_i16(&mut self, data: &[i16]) {
        let mono: Vec<f32> = data
            .chunks(self.channels)
            .map(|c| c.iter().map(|&s| s as f32 / 32768.0).sum::<f32>() / self.channels as f32)
            .collect();
        self.resample(&mono);
    }

    fn resample(&mut self, mono: &[f32]) {
        if self.src_rate == TARGET_RATE {
            for &s in mono {
                self.emit(s);
            }
            return;
        }
        for &s in mono {
            while self.pos < 1.0 {
                let v = self.prev + (s - self.prev) * self.pos as f32;
                self.emit(v);
                self.pos += self.step;
            }
            self.pos -= 1.0;
            self.prev = s;
        }
    }

    fn emit(&mut self, sample: f32) {
        let v = (sample.clamp(-1.0, 1.0) * 32767.0) as i16;
        self.buf.push(v);
        if self.buf.len() >= FRAME_SAMPLES {
            let frame: Vec<u8> = self.buf[..FRAME_SAMPLES]
                .iter()
                .flat_map(|s| s.to_le_bytes())
                .collect();
            self.buf.drain(..FRAME_SAMPLES);
            let _ = self.tx.send(frame);
        }
    }
}
