//! Direct backlight control via sysfs with brightnessctl fallback.

use std::fs;
use std::path::PathBuf;
use std::process::Command;

use tracing::debug;

/// Find the first available backlight sysfs path.
fn find_backlight() -> Option<PathBuf> {
    let dir = fs::read_dir("/sys/class/backlight").ok()?;
    for entry in dir.flatten() {
        let path = entry.path();
        if path.join("brightness").exists() && path.join("max_brightness").exists() {
            return Some(path);
        }
    }
    None
}

/// Read max brightness from sysfs.
fn sysfs_max() -> Option<u32> {
    let path = find_backlight()?;
    fs::read_to_string(path.join("max_brightness"))
        .ok()?
        .trim()
        .parse()
        .ok()
}

/// Read current brightness from sysfs (0..max).
fn sysfs_current() -> Option<u32> {
    let path = find_backlight()?;
    fs::read_to_string(path.join("brightness"))
        .ok()?
        .trim()
        .parse()
        .ok()
}

/// Set brightness via sysfs (value 0..max).
fn sysfs_set(value: u32) -> bool {
    if let Some(path) = find_backlight() {
        let brightness_path = path.join("brightness");
        // Try direct write first
        if fs::write(&brightness_path, value.to_string()).is_ok() {
            return true;
        }
        debug!("sysfs write failed for {}", brightness_path.display());
    }
    false
}

/// Get current brightness as a fraction 0.0..1.0.
pub fn get() -> f64 {
    // Try sysfs first
    if let (Some(cur), Some(max)) = (sysfs_current(), sysfs_max()) {
        if max > 0 {
            return cur as f64 / max as f64;
        }
    }
    // Fall back to brightnessctl
    Command::new("brightnessctl")
        .args(["get"])
        .output()
        .ok()
        .and_then(|o| String::from_utf8_lossy(&o.stdout).trim().parse::<f64>().ok())
        .and_then(|current| {
            Command::new("brightnessctl")
                .args(["max"])
                .output()
                .ok()
                .and_then(|o| String::from_utf8_lossy(&o.stdout).trim().parse::<f64>().ok())
                .map(|max| if max > 0.0 { current / max } else { 0.5 })
        })
        .unwrap_or(0.5)
}

/// Set brightness as a fraction 0.0..1.0.
pub fn set(fraction: f64) {
    let fraction = fraction.clamp(0.02, 1.0);

    // Try sysfs first
    if let Some(max) = sysfs_max() {
        let value = ((fraction * max as f64) as u32).max(1);
        if sysfs_set(value) {
            debug!("Backlight set to {value}/{max} via sysfs");
            return;
        }
    }

    // Fall back to brightnessctl
    let percent = format!("{}%", (fraction * 100.0) as i32);
    let _ = Command::new("brightnessctl").args(["set", &percent]).spawn();
}

/// Adjust brightness up or down by a step. Returns new percentage 0..100.
pub fn adjust(up: bool) -> u8 {
    let current = get();
    let step = 0.05;
    let new_val = if up {
        (current + step).min(1.0)
    } else {
        (current - step).max(0.02)
    };
    set(new_val);
    (new_val * 100.0) as u8
}
