#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-voice-clone -- Anti Voice-Clone Defense with Liveness Detection
#[derive(Debug)] pub enum VoiceError { InsufficientSamples(String), CloneDetected(String) }
impl std::fmt::Display for VoiceError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::InsufficientSamples(e)|Self::CloneDetected(e) => write!(f, "{e}") } } }
impl std::error::Error for VoiceError {}
#[derive(Debug, Clone)] pub struct VoicePrint { pub spectral_centroid: f64, pub pitch_mean: f64, pub pitch_variance: f64, pub formant_ratios: Vec<f64>, pub micro_tremor: f64 }
pub fn spectral_centroid(magnitudes: &[f64]) -> f64 {
    let weighted: f64 = magnitudes.iter().enumerate().map(|(i, &m)| i as f64 * m).sum();
    let total: f64 = magnitudes.iter().sum();
    if total < 1e-10 { 0.0 } else { weighted / total }
}
pub fn pitch_stats(pitches: &[f64]) -> (f64, f64) {
    if pitches.is_empty() { return (0.0, 0.0); }
    let mean = pitches.iter().sum::<f64>() / pitches.len() as f64;
    let var = pitches.iter().map(|p| (p - mean)*(p - mean)).sum::<f64>() / pitches.len() as f64;
    (mean, var)
}
pub fn cosine_similarity(a: &[f64], b: &[f64]) -> f64 {
    let dot: f64 = a.iter().zip(b.iter()).map(|(x,y)| x*y).sum();
    let na: f64 = a.iter().map(|x| x*x).sum::<f64>().sqrt();
    let nb: f64 = b.iter().map(|x| x*x).sum::<f64>().sqrt();
    if na < 1e-10 || nb < 1e-10 { 0.0 } else { dot / (na * nb) }
}
pub struct CloneDetector { pub threshold: f64 }
impl CloneDetector {
    pub fn new(threshold: f64) -> Self { Self { threshold } }
    pub fn is_clone(&self, live: &VoicePrint, stored: &VoicePrint) -> bool {
        let sim = cosine_similarity(&live.formant_ratios, &stored.formant_ratios);
        let tremor_diff = (live.micro_tremor - stored.micro_tremor).abs();
        sim > self.threshold && tremor_diff < 0.01 // too perfect = clone
    }
    pub fn liveness_score(&self, vp: &VoicePrint) -> f64 {
        let tremor_score = (vp.micro_tremor * 100.0).min(1.0); // natural voice has micro tremor
        let variance_score = (vp.pitch_variance / 50.0).min(1.0); // natural has pitch variance
        (tremor_score + variance_score) / 2.0
    }
}
#[cfg(test)] mod tests {
    use super::*;
    #[test] fn test_cosine() { let a = vec![1.0, 0.0]; let b = vec![1.0, 0.0]; assert!((cosine_similarity(&a, &b) - 1.0).abs() < 1e-10); }
    #[test] fn test_liveness() {
        let cd = CloneDetector::new(0.99);
        let real = VoicePrint { spectral_centroid: 2000.0, pitch_mean: 150.0, pitch_variance: 30.0, formant_ratios: vec![1.0,1.5,2.5], micro_tremor: 0.05 };
        assert!(cd.liveness_score(&real) > 0.3);
    }
}
