use std::thread;
use std::time::Duration;

use calloop::channel::{self, Sender};
use calloop::LoopHandle;
use tracing::{error, info};

use crate::forge::Forge;

/// Events from rfkill monitoring.
#[derive(Debug)]
pub enum RfkillEvent {
    /// Airplane mode state changed.
    AirplaneModeChanged(bool),
}

/// Start the Rfkill D-Bus listener for airplane mode.
pub fn start_listener(event_loop: &LoopHandle<'static, Forge>) {
    let (sender, channel) = channel::channel::<RfkillEvent>();

    event_loop
        .insert_source(channel, |event, _, forge| {
            if let calloop::channel::Event::Msg(ev) = event {
                match ev {
                    RfkillEvent::AirplaneModeChanged(active) => {
                        forge.sys_state.airplane_mode = active;
                        forge.request_redraw();
                    }
                }
            }
        })
        .expect("rfkill channel");

    thread::Builder::new()
        .name("forge-rfkill".into())
        .spawn(move || {
            if let Err(e) = run_rfkill_listener(sender) {
                error!("Rfkill listener failed: {e}");
            }
        })
        .expect("rfkill thread");
}

fn run_rfkill_listener(
    sender: Sender<RfkillEvent>,
) -> Result<(), Box<dyn std::error::Error>> {
    info!("Rfkill D-Bus listener starting");

    let conn = zbus::blocking::Connection::session()?;

    loop {
        let airplane = check_airplane_mode(&conn);
        let _ = sender.send(RfkillEvent::AirplaneModeChanged(airplane));
        thread::sleep(Duration::from_secs(60));
    }
}

fn check_airplane_mode(conn: &zbus::blocking::Connection) -> bool {
    // Try org.gnome.SettingsDaemon.Rfkill first
    let reply = conn.call_method(
        Some("org.gnome.SettingsDaemon.Rfkill"),
        "/org/gnome/SettingsDaemon/Rfkill",
        Some("org.freedesktop.DBus.Properties"),
        "Get",
        &("org.gnome.SettingsDaemon.Rfkill", "AirplaneMode"),
    );

    if let Ok(msg) = reply {
        if let Ok(val) = msg.body().deserialize::<zbus::zvariant::Value>() {
            if let zbus::zvariant::Value::Bool(b) = val {
                return b;
            }
        }
    }

    // Fallback: check rfkill sysfs directly
    check_rfkill_sysfs()
}

fn check_rfkill_sysfs() -> bool {
    // If all wireless devices are soft-blocked, consider airplane mode active
    let Ok(entries) = std::fs::read_dir("/sys/class/rfkill") else {
        return false;
    };

    let mut has_wireless = false;
    let mut all_blocked = true;

    for entry in entries.flatten() {
        let path = entry.path();
        let rfkill_type = std::fs::read_to_string(path.join("type")).unwrap_or_default();
        let rfkill_type = rfkill_type.trim();

        if matches!(rfkill_type, "wlan" | "bluetooth" | "wwan") {
            has_wireless = true;
            let soft_blocked = std::fs::read_to_string(path.join("soft"))
                .unwrap_or_default()
                .trim()
                == "1";
            if !soft_blocked {
                all_blocked = false;
            }
        }
    }

    has_wireless && all_blocked
}
