use std::fs;
use std::path::Path;
use thiserror::Error;

#[derive(Error, Debug)]
pub enum EntropyError {
    #[error("Could not collect any hardware identifiers")]
    NoIdentifiersFound,
    #[error("IO Error: {0}")]
    IoError(#[from] std::io::Error),
}


#[derive(Debug, Clone)]
pub struct HardwareEntropy {
    identifiers: Vec<String>,
}

impl HardwareEntropy {
    pub fn new(camera_id: Option<String>) -> Result<Self, EntropyError> {
        let mut identifiers: Vec<String> = Vec::new();

        // 1. Camera ID (high-entropy, device-specific)
        if let Some(cid) = camera_id {
            if !cid.is_empty() {
                identifiers.push(format!("camera:{}", cid));
            }
        }

        // 2. CPU Serial from /proc/cpuinfo (Raspberry Pi specific)
        if let Ok(cpuinfo) = fs::read_to_string("/proc/cpuinfo") {
            for line in cpuinfo.lines() {
                if line.starts_with("Serial") {
                    if let Some(serial) = line.split(':').nth(1) {
                        let serial = serial.trim();
                        if !serial.is_empty() {
                            identifiers.push(format!("serial:{}", serial));
                            break;
                        }
                    }
                }
            }
        }

        // 3. MAC address — try common interface names
        for iface in &["wlan0", "eth0", "en0", "eth1"] {
            let path = format!("/sys/class/net/{}/address", iface);
            if let Ok(mac) = fs::read_to_string(Path::new(&path)) {
                let mac = mac.trim();
                // Skip all-zero MACs (virtual/loopback)
                if !mac.is_empty() && mac != "00:00:00:00:00:00" {
                    identifiers.push(format!("mac:{}", mac));
                    break;
                }
            }
        }

        // 4. Machine ID (systemd, Linux)
        if let Ok(machine_id) = fs::read_to_string("/etc/machine-id") {
            let machine_id = machine_id.trim();
            if !machine_id.is_empty() {
                identifiers.push(format!("machine:{}", machine_id));
            }
        }

        // Development fallback: if nothing was found (e.g. running on Windows/macOS host),
        // use a fixed sentinel so unit tests pass. In release mode this is an error.
        if identifiers.is_empty() {
            #[cfg(debug_assertions)]
            {
                eprintln!("⚠ No hardware identifiers found; using dev fallback");
                identifiers.push("dev_fallback:placeholder_hardware_id".to_string());
            }
            #[cfg(not(debug_assertions))]
            return Err(EntropyError::NoIdentifiersFound);
        }

        Ok(HardwareEntropy { identifiers })
    }

    /// Returns all collected hardware identifier strings (for diagnostics).
    pub fn identifiers(&self) -> &[String] {
        &self.identifiers
    }

    pub fn get_hardware_id(&self) -> Vec<u8> {
        self.identifiers.join("|").into_bytes()
    }
}
