#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-sentiment -- Bot/Spam Text Detector with Pattern Analysis
use std::collections::HashMap;
#[derive(Debug)] pub enum SentimentError { EmptyText(String) }
impl std::fmt::Display for SentimentError { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { Self::EmptyText(e) => write!(f, "{e}") } } }
impl std::error::Error for SentimentError {}
#[derive(Debug, Clone)] pub struct SpamScore { pub spam_probability: f64, pub caps_ratio: f64, pub url_density: f64, pub repetition_score: f64 }
pub struct SpamDetector { blocked_words: Vec<String> }
impl SpamDetector {
    pub fn new() -> Self { Self { blocked_words: Vec::new() } }
    pub fn add_blocked(&mut self, word: &str) { self.blocked_words.push(word.to_lowercase()); }
    pub fn analyze(&self, text: &str) -> Result<SpamScore, SentimentError> {
        if text.is_empty() { return Err(SentimentError::EmptyText("Empty".into())); }
        let chars: Vec<char> = text.chars().collect();
        let upper = chars.iter().filter(|c| c.is_uppercase()).count();
        let caps_ratio = upper as f64 / chars.len() as f64;
        let words: Vec<&str> = text.split_whitespace().collect();
        let url_count = words.iter().filter(|w| w.contains("http") || w.contains("www.") || w.contains(".com")).count();
        let url_density = if words.is_empty() { 0.0 } else { url_count as f64 / words.len() as f64 };
        let mut freq: HashMap<String, usize> = HashMap::new();
        for w in &words { *freq.entry(w.to_lowercase()).or_insert(0) += 1; }
        let max_freq = freq.values().max().copied().unwrap_or(1) as f64;
        let repetition_score = if words.len() > 1 { max_freq / words.len() as f64 } else { 0.0 };
        let blocked_count = words.iter().filter(|w| self.blocked_words.contains(&w.to_lowercase())).count();
        let spam_probability = (caps_ratio * 0.3 + url_density * 0.3 + repetition_score * 0.2 + blocked_count as f64 * 0.2).min(1.0);
        Ok(SpamScore { spam_probability, caps_ratio, url_density, repetition_score })
    }
}
pub struct BotDetector;
impl BotDetector {
    pub fn check_timing_regularity(intervals_ms: &[u64]) -> f64 {
        if intervals_ms.len() < 2 { return 0.0; }
        let mean = intervals_ms.iter().sum::<u64>() as f64 / intervals_ms.len() as f64;
        let variance = intervals_ms.iter().map(|&i| { let d = i as f64 - mean; d*d }).sum::<f64>() / intervals_ms.len() as f64;
        let cv = if mean > 0.0 { variance.sqrt() / mean } else { 0.0 };
        if cv < 0.05 { 0.95 } else if cv < 0.1 { 0.7 } else { 0.1 } // low variance = bot
    }
}
#[cfg(test)] mod tests {
    use super::*;
    #[test] fn test_spam() { let mut d = SpamDetector::new(); d.add_blocked("buy"); let s = d.analyze("BUY NOW http://spam.com BUY BUY").unwrap(); assert!(s.spam_probability > 0.3); }
    #[test] fn test_bot() { let score = BotDetector::check_timing_regularity(&[1000, 1001, 1000, 999, 1001]); assert!(score > 0.8); }
    #[test] fn test_human() { let score = BotDetector::check_timing_regularity(&[500, 2000, 100, 5000, 300]); assert!(score < 0.5); }
}
