use std::collections::HashMap;
use std::process::Command;
use std::os::windows::process::CommandExt;

const CREATE_NO_WINDOW: u32 = 0x08000000;
// const DETACHED_PROCESS: u32 = 0x00000008;

pub struct PowerPlan {
    power_plan_map: HashMap<i32, String>,
}

impl PowerPlan {
    pub fn new() -> Self {
        let mut power_plan_map = HashMap::new();
        power_plan_map.insert(
            PowerPlanMode::PowerSaving as i32,
            "a1841308-3541-4fab-bc81-f71556f20b4a".to_string(),
        );
        power_plan_map.insert(
            PowerPlanMode::Balanced as i32,
            "381b4222-f694-41f0-9685-ff5bb260df2e".to_string(),
        );
        power_plan_map.insert(
            PowerPlanMode::HighPerformance as i32,
            "8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c".to_string(),
        );
        power_plan_map.insert(
            PowerPlanMode::Extreme as i32,
            "e9a42b02-d5df-448d-aa00-03f14749eb61".to_string(),
        );

        PowerPlan { power_plan_map }
    }

    pub fn set(&self, mode: i32) -> Result<(), String> {
        let guid = self
            .power_plan_map
            .get(&mode)
            .ok_or("Invalid power plan number (expect from 1 to 4)")?;

        let output = Command::new("powercfg")
            .arg("/S")
            .arg(guid)
            .creation_flags(CREATE_NO_WINDOW)
            .output()
            .map_err(|e| format!("Failed to execute powercfg command: {}", e))?;

        if !output.status.success() {
            return Err(format!(
                "Powercfg command failed: {}",
                String::from_utf8_lossy(&output.stderr)
            ));
        }

        Ok(())
    }

    pub fn get(&self) -> Result<i32, String> {
        let output = Command::new("powercfg")
            .arg("/L")
            .creation_flags(CREATE_NO_WINDOW)
            .output()
            .map_err(|e| format!("Failed to execute powercfg command: {}", e))?;

        let output_str = String::from_utf8_lossy(&output.stdout);
        let re = regex::Regex::new(r"GUID:\s+(\S+)\s+\(\S+\)\s+\*")
            .map_err(|e| format!("Failed to compile regex: {}", e))?;

        let res = re
            .captures(&output_str)
            .ok_or("No matching power plan found")?;
        let guid = res
            .get(1)
            .ok_or("No GUID found in power plan output")?
            .as_str();

        for (k, v) in &self.power_plan_map {
            if guid == v {
                return Ok(*k);
            }
        }

        Err("No matching power plan found in map".to_string())
    }
}

#[allow(dead_code)]
pub enum PowerPlanMode {
    Other = 0,
    PowerSaving = 1,
    Balanced = 2,
    HighPerformance = 3,
    Extreme = 4,
}

pub fn get_powerplan() -> Result<i32, String> {
    let power_plan = PowerPlan::new();
    let mode = power_plan.get()?;
    Ok(mode)
}

pub fn set_powerplan(plan: i32) -> Result<(), String> {
    if plan < 0 || plan > 4 {
        return Err("Invalid power plan mode".to_string());
    }
    let power_plan = PowerPlan::new();
    power_plan.set(plan)?;
    Ok(())
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_set_power_plan() {
        let power_plan = PowerPlan::new();
        // 测试设置节能模式
        let result = power_plan.set(PowerPlanMode::PowerSaving as i32);
        assert!(result.is_ok(), "Failed to set power saving plan");

        // 测试设置无效模式
        let result = power_plan.set(99);
        assert!(result.is_err(), "Setting invalid power plan should fail");
    }

    #[test]
    fn test_get_power_plan() {
        let power_plan = PowerPlan::new();
        // 测试获取当前电源计划
        let result = power_plan.get();
        assert!(result.is_ok(), "Failed to get current power plan");

        // 验证返回的模式是否在有效范围内
        let mode = result.unwrap();
        assert!((1..=4).contains(&mode), "Invalid power plan mode returned");
        println!(
            "Mode: {} - {}",
            mode,
            PowerPlan::new().power_plan_map[&mode]
        );
    }
}
