use serde::Deserialize;
use crate::payload::SmartMetrics;

#[derive(Deserialize)]
struct SmartJson {
    smart_status: SmartStatus,
    temperature: Option<SmartTemp>,
    ata_smart_attributes: Option<SmartAttrs>,
    nvme_smart_health_information_log: Option<NvmeHealth>,
}

#[derive(Deserialize)]
struct SmartStatus { passed: bool }

#[derive(Deserialize)]
struct SmartTemp { current: i64 }

#[derive(Deserialize)]
struct SmartAttrs { table: Vec<SmartAttr> }

#[derive(Deserialize)]
struct SmartAttr {
    id: u8,
    raw: SmartAttrRaw,
    value: Option<i64>,
}

#[derive(Deserialize)]
struct SmartAttrRaw { value: i64 }

#[derive(Deserialize)]
struct NvmeHealth {
    percentage_used: Option<i64>,
    temperature: Option<i64>,
}

pub fn is_available() -> bool {
    std::process::Command::new("which")
        .arg("smartctl")
        .output()
        .map(|o| o.status.success())
        .unwrap_or(false)
}

pub fn parse_json(json: &str) -> Result<SmartMetrics, serde_json::Error> {
    let s: SmartJson = serde_json::from_str(json)?;

    let temperature = s.temperature.as_ref().map(|t| t.current)
        .or_else(|| s.nvme_smart_health_information_log.as_ref()?.temperature);

    let mut reallocated = None;
    let mut power_hours = None;
    let mut wear = None;

    if let Some(attrs) = &s.ata_smart_attributes {
        for attr in &attrs.table {
            match attr.id {
                5   => reallocated = Some(attr.raw.value),
                9   => power_hours = Some(attr.raw.value),
                177 => wear = attr.value,
                _   => {}
            }
        }
    }

    if wear.is_none() {
        if let Some(nvme) = &s.nvme_smart_health_information_log {
            if let Some(pct) = nvme.percentage_used {
                wear = Some(100 - pct);
            }
        }
    }

    Ok(SmartMetrics {
        passed: s.smart_status.passed,
        temperature,
        reallocated_sectors: reallocated,
        power_on_hours: power_hours,
        wear_level: wear,
    })
}

pub fn collect() -> Option<SmartMetrics> {
    if !is_available() {
        return None;
    }
    // Détecter les disques réels depuis /sys/block (sd*, nvme*)
    let mut devs: Vec<String> = std::fs::read_dir("/sys/block")
        .into_iter()
        .flatten()
        .flatten()
        .map(|e| e.file_name().into_string().unwrap_or_default())
        .filter(|n| n.starts_with("sd") || n.starts_with("nvme"))
        .map(|n| format!("/dev/{}", n))
        .collect();
    devs.sort();

    for dev in &devs {
        let Ok(output) = std::process::Command::new("smartctl")
            .args(["-j", dev])
            .output() else { continue };
        let json = String::from_utf8_lossy(&output.stdout);
        if let Ok(metrics) = parse_json(&json) {
            return Some(metrics);
        }
    }
    None
}
