#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-elysium -- Optimal System State Manager
//! Auto-tune system parameters to maintain peak performance

use std::collections::VecDeque;

#[derive(Debug)]
pub enum ElysiumError { TuningFailed(String), InvalidMetric(String) }
impl std::fmt::Display for ElysiumError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self { Self::TuningFailed(e) => write!(f, "Tune: {e}"), Self::InvalidMetric(e) => write!(f, "Metric: {e}") }
    }
}
impl std::error::Error for ElysiumError {}

#[derive(Debug, Clone)]
pub struct SystemMetrics {
    pub cpu_percent: f64, pub memory_percent: f64,
    pub latency_p50_ms: f64, pub latency_p99_ms: f64,
    pub throughput_rps: f64, pub error_rate: f64,
}

#[derive(Debug, Clone)]
pub struct TuningParams {
    pub max_connections: u32, pub worker_threads: u32,
    pub buffer_size_kb: u32, pub gc_interval_secs: u32,
    pub cache_size_mb: u32,
}
impl Default for TuningParams {
    fn default() -> Self { Self { max_connections: 1000, worker_threads: 4, buffer_size_kb: 64, gc_interval_secs: 30, cache_size_mb: 256 } }
}

#[derive(Debug, Clone)]
pub struct TuningAdvice { pub param: String, pub current: u32, pub recommended: u32, pub reason: String }

pub struct Elysium {
    history: VecDeque<SystemMetrics>,
    current_params: TuningParams,
    max_history: usize,
}

impl Elysium {
    pub fn new(params: TuningParams, max_history: usize) -> Self {
        Self { history: VecDeque::with_capacity(max_history), current_params: params, max_history }
    }

    pub fn record_metrics(&mut self, metrics: SystemMetrics) {
        if self.history.len() >= self.max_history { self.history.pop_front(); }
        self.history.push_back(metrics);
    }

    /// Analyze trends and recommend tuning
    pub fn analyze(&self) -> Result<Vec<TuningAdvice>, ElysiumError> {
        if self.history.len() < 5 {
            return Err(ElysiumError::InvalidMetric("Need at least 5 samples".into()));
        }

        let mut advice = Vec::new();
        let recent: Vec<&SystemMetrics> = self.history.iter().rev().take(10).collect();
        let avg_cpu: f64 = recent.iter().map(|m| m.cpu_percent).sum::<f64>() / recent.len() as f64;
        let avg_mem: f64 = recent.iter().map(|m| m.memory_percent).sum::<f64>() / recent.len() as f64;
        let avg_lat: f64 = recent.iter().map(|m| m.latency_p99_ms).sum::<f64>() / recent.len() as f64;
        let avg_err: f64 = recent.iter().map(|m| m.error_rate).sum::<f64>() / recent.len() as f64;
        let avg_rps: f64 = recent.iter().map(|m| m.throughput_rps).sum::<f64>() / recent.len() as f64;

        // CPU high → increase workers
        if avg_cpu > 80.0 && self.current_params.worker_threads < 16 {
            advice.push(TuningAdvice {
                param: "worker_threads".into(), current: self.current_params.worker_threads,
                recommended: (self.current_params.worker_threads as f64 * 1.5) as u32,
                reason: format!("Avg CPU {avg_cpu:.1}% > 80%"),
            });
        }
        // CPU low → decrease workers to save resources
        if avg_cpu < 20.0 && self.current_params.worker_threads > 2 {
            advice.push(TuningAdvice {
                param: "worker_threads".into(), current: self.current_params.worker_threads,
                recommended: (self.current_params.worker_threads / 2).max(2),
                reason: format!("Avg CPU {avg_cpu:.1}% < 20% — over-provisioned"),
            });
        }
        // Memory high → reduce cache
        if avg_mem > 80.0 {
            advice.push(TuningAdvice {
                param: "cache_size_mb".into(), current: self.current_params.cache_size_mb,
                recommended: (self.current_params.cache_size_mb as f64 * 0.7) as u32,
                reason: format!("Avg Memory {avg_mem:.1}% > 80%"),
            });
        }
        // Latency high → increase buffer
        if avg_lat > 100.0 {
            advice.push(TuningAdvice {
                param: "buffer_size_kb".into(), current: self.current_params.buffer_size_kb,
                recommended: self.current_params.buffer_size_kb * 2,
                reason: format!("Avg P99 latency {avg_lat:.1}ms > 100ms"),
            });
        }
        // Error rate high → reduce connections
        if avg_err > 0.05 {
            advice.push(TuningAdvice {
                param: "max_connections".into(), current: self.current_params.max_connections,
                recommended: (self.current_params.max_connections as f64 * 0.8) as u32,
                reason: format!("Avg error rate {:.2}% > 5%", avg_err * 100.0),
            });
        }
        // High throughput + low latency → can increase connections
        if avg_rps > 1000.0 && avg_lat < 20.0 && avg_err < 0.01 {
            advice.push(TuningAdvice {
                param: "max_connections".into(), current: self.current_params.max_connections,
                recommended: (self.current_params.max_connections as f64 * 1.3) as u32,
                reason: format!("System healthy: {avg_rps:.0} rps, {avg_lat:.1}ms lat, {:.3}% err", avg_err * 100.0),
            });
        }
        // GC pressure
        if avg_mem > 60.0 && avg_lat > 50.0 {
            advice.push(TuningAdvice {
                param: "gc_interval_secs".into(), current: self.current_params.gc_interval_secs,
                recommended: (self.current_params.gc_interval_secs / 2).max(5),
                reason: format!("Memory {avg_mem:.1}% + latency {avg_lat:.1}ms suggests GC pressure"),
            });
        }

        Ok(advice)
    }

    /// Apply recommended tuning
    pub fn apply_advice(&mut self, advice: &TuningAdvice) {
        match advice.param.as_str() {
            "worker_threads" => self.current_params.worker_threads = advice.recommended,
            "max_connections" => self.current_params.max_connections = advice.recommended,
            "buffer_size_kb" => self.current_params.buffer_size_kb = advice.recommended,
            "cache_size_mb" => self.current_params.cache_size_mb = advice.recommended,
            "gc_interval_secs" => self.current_params.gc_interval_secs = advice.recommended,
            _ => {}
        }
    }

    pub fn current_params(&self) -> &TuningParams { &self.current_params }
}

#[cfg(test)]
mod tests {
    use super::*;
    fn high_cpu_metrics() -> SystemMetrics {
        SystemMetrics { cpu_percent: 90.0, memory_percent: 50.0, latency_p50_ms: 10.0, latency_p99_ms: 30.0, throughput_rps: 500.0, error_rate: 0.01 }
    }
    #[test]
    fn test_recommend_more_workers() {
        let mut e = Elysium::new(TuningParams::default(), 100);
        for _ in 0..10 { e.record_metrics(high_cpu_metrics()); }
        let advice = e.analyze().unwrap();
        assert!(advice.iter().any(|a| a.param == "worker_threads" && a.recommended > 4));
    }
    #[test]
    fn test_apply_advice() {
        let mut e = Elysium::new(TuningParams::default(), 100);
        let adv = TuningAdvice { param: "worker_threads".into(), current: 4, recommended: 8, reason: "test".into() };
        e.apply_advice(&adv);
        assert_eq!(e.current_params().worker_threads, 8);
    }
}
