//! Thermal throttling detection

use super::super::error::ProfilingError;

/// Thermal state detection result
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct ThermalState {
    /// Whether thermal throttling is currently detected
    pub is_throttling: bool,

    /// Thermal pressure severity level
    pub severity: ThermalSeverity,

    /// Current temperature in Celsius (Linux only)
    pub temperature_celsius: Option<f64>,

    /// Throttling threshold temperature in Celsius (Linux only)
    pub trip_point_celsius: Option<f64>,

    /// Number of thermal zones checked (Linux only)
    pub zones_checked: Option<u32>,

    /// Names of zones currently throttling (Linux only)
    pub throttled_zones: Option<Vec<String>>,

    /// Platform that provided this data
    pub platform: ThermalPlatform,
}

/// Thermal severity levels (unified across all platforms)
#[derive(
    Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize,
)]
pub enum ThermalSeverity {
    /// No thermal pressure
    Normal = 0,

    /// Light thermal pressure (system warming up, no throttling)
    Light = 1,

    /// Moderate thermal pressure (active throttling)
    Moderate = 2,

    /// Critical thermal state (severe throttling)
    Critical = 3,
}

/// Platform that provided thermal data
#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum ThermalPlatform {
    /// Linux (detailed temperature data available)
    Linux,

    /// macOS (coarse-grained state only)
    MacOS,

    /// Other/Unknown platform
    Unknown,
}

/// Detect thermal throttling state
///
/// Returns `Ok(Some(state))` if detection is supported and successful.
/// Returns `Ok(None)` if detection is not supported on this platform.
/// Returns `Err(...)` if detection failed (I/O error, etc.).
///
/// # Platform Support
///
/// - **Linux**: Full support with temperature details (all fields populated)
/// - **macOS**: Supported with coarse granularity (only severity populated)
/// - **Windows**: Not supported (returns `None`)
///
/// # Examples
///
/// ```rust
/// match detect_thermal_state()? {
///     Some(state) if state.is_throttling => {
///         println!("⚠️  Throttling! Severity: {:?}", state.severity);
///         
///         // Linux-specific details
///         if let Some(temp) = state.temperature_celsius {
///             println!("Temperature: {:.1}°C", temp);
///         }
///     }
///     Some(state) => {
///         println!("✅ No throttling (severity: {:?})", state.severity);
///     }
///     None => {
///         println!("ℹ️  Detection not supported");
///     }
/// }
/// ```
pub fn detect_thermal_state() -> Result<Option<ThermalState>, ProfilingError> {
    #[cfg(target_os = "linux")]
    {
        detect_thermal_state_linux().map(Some)
    }

    #[cfg(target_os = "macos")]
    {
        detect_thermal_state_macos().map(Some)
    }

    #[cfg(target_os = "windows")]
    {
        Ok(None)
    }

    #[cfg(not(any(target_os = "linux", target_os = "macos", target_os = "windows")))]
    {
        Ok(None)
    }
}

/// Simple check: Is thermal throttling currently happening?
///
/// Returns `Ok(Some(true))` if throttling is detected.
/// Returns `Ok(Some(false))` if no throttling is detected.
/// Returns `Ok(None)` if detection is not supported.
///
/// This is a simplified wrapper around `detect_thermal_state()`.
pub fn is_thermal_throttling() -> Result<Option<bool>, ProfilingError> {
    detect_thermal_state().map(|opt| opt.map(|state| state.is_throttling))
}

/// Check if thermal detection is supported on this platform
pub fn is_thermal_detection_supported() -> bool {
    cfg!(any(target_os = "linux", target_os = "macos"))
}

#[cfg(target_os = "linux")]
fn detect_thermal_state_linux() -> Result<ThermalState, ProfilingError> {
    use super::super::sanity;
    use std::fs;
    use std::path::Path;

    let thermal_path = Path::new("/sys/class/thermal");

    if !thermal_path.exists() {
        super::super::logging::log_debug("Thermal sysfs not available");
        return Ok(ThermalState {
            is_throttling: false,
            severity: ThermalSeverity::Normal,
            temperature_celsius: None,
            trip_point_celsius: None,
            zones_checked: Some(0),
            throttled_zones: None,
            platform: ThermalPlatform::Linux,
        });
    }

    let entries = fs::read_dir(thermal_path)
        .map_err(|e| ProfilingError::IoError(format!("Failed to read thermal zones: {}", e)))?;

    let mut zones_checked = 0;
    let mut max_temp = 0.0;
    let mut trip_point = None;
    let mut throttled_zones = Vec::new();
    let mut is_throttling = false;

    for entry in entries.flatten() {
        let zone_name = entry.file_name();
        let zone_path = entry.path();

        let trip_point_path = zone_path.join("trip_point_0_temp");
        let current_temp_path = zone_path.join("temp");

        if !trip_point_path.exists() || !current_temp_path.exists() {
            continue;
        }

        zones_checked += 1;

        // Parse trip point temperature
        let trip_temp = match fs::read_to_string(&trip_point_path) {
            Ok(temp_str) => match temp_str.trim().parse::<i32>() {
                Ok(temp_millidegrees) => {
                    let temp_celsius = temp_millidegrees as f64 / 1000.0;
                    if let Err(e) = sanity::SanityChecker::check_temperature(temp_celsius) {
                        super::super::logging::log_warn(&format!(
                            "Invalid trip point temperature in zone {:?}: {} - {}",
                            zone_name, temp_celsius, e
                        ));
                        continue;
                    }
                    temp_celsius
                }
                Err(e) => {
                    super::super::logging::log_warn(&format!(
                        "Failed to parse trip point temperature in zone {:?}: {}",
                        zone_name, e
                    ));
                    continue;
                }
            },
            Err(e) => {
                super::super::logging::log_warn(&format!(
                    "Failed to read trip point temperature in zone {:?}: {}",
                    zone_name, e
                ));
                continue;
            }
        };

        // Parse current temperature
        let current_temp = match fs::read_to_string(&current_temp_path) {
            Ok(temp_str) => match temp_str.trim().parse::<i32>() {
                Ok(temp_millidegrees) => {
                    let temp_celsius = temp_millidegrees as f64 / 1000.0;
                    if let Err(e) = sanity::SanityChecker::check_temperature(temp_celsius) {
                        super::super::logging::log_warn(&format!(
                            "Invalid current temperature in zone {:?}: {} - {}",
                            zone_name, temp_celsius, e
                        ));
                        continue;
                    }
                    temp_celsius
                }
                Err(e) => {
                    super::super::logging::log_warn(&format!(
                        "Failed to parse current temperature in zone {:?}: {}",
                        zone_name, e
                    ));
                    continue;
                }
            },
            Err(e) => {
                super::super::logging::log_warn(&format!(
                    "Failed to read current temperature in zone {:?}: {}",
                    zone_name, e
                ));
                continue;
            }
        };

        max_temp = max_temp.max(current_temp);
        if trip_point.is_none() {
            trip_point = Some(trip_temp);
        }

        if current_temp >= trip_temp {
            is_throttling = true;
            throttled_zones.push(zone_name.to_string_lossy().to_string());
            super::super::logging::log_warn(&format!(
                "Thermal throttling detected in zone {:?}: {:.1}°C (trip at {:.1}°C)",
                zone_name, current_temp, trip_temp
            ));
        }
    }

    // Determine severity based on temperature
    let severity = if is_throttling {
        if let Some(trip) = trip_point {
            let margin = max_temp - trip;
            if margin >= 5.0 {
                ThermalSeverity::Critical
            } else {
                ThermalSeverity::Moderate
            }
        } else {
            ThermalSeverity::Moderate
        }
    } else if max_temp > 70.0 {
        ThermalSeverity::Light
    } else {
        ThermalSeverity::Normal
    };

    if zones_checked == 0 {
        super::super::logging::log_debug("No valid thermal zones found");
    } else {
        super::super::logging::log_info(&format!(
            "Thermal check complete: {} zones checked, max temp: {:.1}°C",
            zones_checked, max_temp
        ));
    }

    Ok(ThermalState {
        is_throttling,
        severity,
        temperature_celsius: Some(max_temp),
        trip_point_celsius: trip_point,
        zones_checked: Some(zones_checked),
        throttled_zones: if throttled_zones.is_empty() {
            None
        } else {
            Some(throttled_zones)
        },
        platform: ThermalPlatform::Linux,
    })
}

#[cfg(target_os = "macos")]
fn detect_thermal_state_macos() -> Result<ThermalState, ProfilingError> {
    use objc::msg_send;
    use objc::runtime::{AnyClass, AnyObject};
    use std::ffi::CString;

    unsafe {
        let class_name = CString::new("NSProcessInfo").map_err(|_| {
            ProfilingError::IoError("Failed to create CString for NSProcessInfo".to_string())
        })?;
        let process_info: *mut AnyObject = msg_send![
            AnyClass::get(class_name.as_c_str()).ok_or_else(|| {
                ProfilingError::IoError("Failed to get NSProcessInfo class".to_string())
            })?,
            processInfo
        ];

        let thermal_state: isize = msg_send![process_info, thermalState];

        // Map macOS states to unified severity levels
        let (severity, is_throttling) = match thermal_state {
            0 => (ThermalSeverity::Normal, false),  // Nominal
            1 => (ThermalSeverity::Light, false),   // Fair
            2 => (ThermalSeverity::Moderate, true), // Serious
            3 => (ThermalSeverity::Critical, true), // Critical
            _ => (ThermalSeverity::Normal, false),
        };

        Ok(ThermalState {
            is_throttling,
            severity,
            temperature_celsius: None,
            trip_point_celsius: None,
            zones_checked: None,
            throttled_zones: None,
            platform: ThermalPlatform::MacOS,
        })
    }
}
