#![deny(warnings)]
#![allow(dead_code)]
//! [TSM.ID].[11031972] -- Platform X Ecosystem
//! xcu-thermo -- Thermal Monitoring & Throttle Manager
use std::collections::VecDeque;

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

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ThermalZone { Cpu, Gpu, Battery, Skin, Ambient }

#[derive(Debug, Clone)]
pub struct ThermalReading { pub zone: ThermalZone, pub temp_celsius: f64, pub timestamp: u64 }

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum ThrottleLevel { None, Light, Medium, Heavy, Emergency }

pub struct ThermoManager {
    history: VecDeque<ThermalReading>,
    thresholds: ThermalThresholds,
    max_history: usize,
}

#[derive(Debug, Clone)]
pub struct ThermalThresholds {
    pub warning: f64, pub throttle_light: f64, pub throttle_medium: f64,
    pub throttle_heavy: f64, pub emergency: f64,
}
impl Default for ThermalThresholds {
    fn default() -> Self { Self { warning: 50.0, throttle_light: 60.0, throttle_medium: 70.0, throttle_heavy: 80.0, emergency: 90.0 } }
}

impl ThermoManager {
    pub fn new(thresholds: ThermalThresholds, max_history: usize) -> Self {
        Self { history: VecDeque::with_capacity(max_history), thresholds, max_history }
    }

    pub fn record(&mut self, reading: ThermalReading) -> ThrottleLevel {
        let level = self.get_throttle_level(reading.temp_celsius);
        if self.history.len() >= self.max_history { self.history.pop_front(); }
        self.history.push_back(reading);
        level
    }

    pub fn get_throttle_level(&self, temp: f64) -> ThrottleLevel {
        if temp >= self.thresholds.emergency { ThrottleLevel::Emergency }
        else if temp >= self.thresholds.throttle_heavy { ThrottleLevel::Heavy }
        else if temp >= self.thresholds.throttle_medium { ThrottleLevel::Medium }
        else if temp >= self.thresholds.throttle_light { ThrottleLevel::Light }
        else { ThrottleLevel::None }
    }

    /// Get performance multiplier based on throttle level
    pub fn performance_multiplier(level: ThrottleLevel) -> f64 {
        match level { ThrottleLevel::None => 1.0, ThrottleLevel::Light => 0.8, ThrottleLevel::Medium => 0.6, ThrottleLevel::Heavy => 0.3, ThrottleLevel::Emergency => 0.1 }
    }

    /// Predict time to overheat based on temperature trend
    pub fn predict_overheat_secs(&self, zone: ThermalZone) -> Option<f64> {
        let readings: Vec<&ThermalReading> = self.history.iter().filter(|r| r.zone == zone).collect();
        if readings.len() < 3 { return None; }
        let last = readings.last()?;
        let first = readings.first()?;
        let dt = (last.timestamp as f64 - first.timestamp as f64).max(1.0);
        let d_temp = last.temp_celsius - first.temp_celsius;
        if d_temp <= 0.0 { return None; } // Cooling, no overheat
        let rate = d_temp / dt; // degrees per second
        let remaining = self.thresholds.emergency - last.temp_celsius;
        if remaining <= 0.0 { return Some(0.0); }
        Some(remaining / rate)
    }

    /// Average temperature for a zone
    pub fn avg_temp(&self, zone: ThermalZone) -> f64 {
        let readings: Vec<f64> = self.history.iter().filter(|r| r.zone == zone).map(|r| r.temp_celsius).collect();
        if readings.is_empty() { return 0.0; }
        readings.iter().sum::<f64>() / readings.len() as f64
    }

    pub fn max_temp(&self) -> f64 {
        self.history.iter().map(|r| r.temp_celsius).fold(0.0f64, f64::max)
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_throttle_levels() {
        let mut t = ThermoManager::new(ThermalThresholds::default(), 100);
        assert_eq!(t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 40.0, timestamp: 1 }), ThrottleLevel::None);
        assert_eq!(t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 75.0, timestamp: 2 }), ThrottleLevel::Medium);
        assert_eq!(t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 95.0, timestamp: 3 }), ThrottleLevel::Emergency);
    }
    #[test]
    fn test_predict_overheat() {
        let mut t = ThermoManager::new(ThermalThresholds::default(), 100);
        t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 60.0, timestamp: 0 });
        t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 70.0, timestamp: 10 });
        t.record(ThermalReading { zone: ThermalZone::Cpu, temp_celsius: 80.0, timestamp: 20 });
        let secs = t.predict_overheat_secs(ThermalZone::Cpu).unwrap();
        assert!(secs > 0.0 && secs < 20.0);
    }
}
