use std::process::Command;
use std::thread;
use std::time::Duration;

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

use crate::forge::Forge;

/// Portal events for the compositor.
#[derive(Debug)]
pub enum PortalEvent {
    CaptivePortalDetected { url: String },
}

pub struct PortalState {
    pub captive_portal_url: Option<String>,
}

impl PortalState {
    pub fn new() -> Self {
        Self {
            captive_portal_url: None,
        }
    }

    /// Start captive portal detection in background.
    pub fn start_detector(event_loop: &LoopHandle<'static, Forge>) {
        let (sender, channel) = channel::channel::<PortalEvent>();

        event_loop
            .insert_source(channel, |event, _, forge| {
                if let channel::Event::Msg(evt) = event {
                    match evt {
                        PortalEvent::CaptivePortalDetected { url } => {
                            tracing::info!("Captive portal detected: {url}");
                            forge.portal.captive_portal_url = Some(url);
                            forge.windows.set_dirty();
                            forge.unstall();
                        }
                    }
                }
            })
            .expect("portal channel");

        thread::Builder::new()
            .name("forge-portal-detect".into())
            .spawn(move || {
                run_captive_portal_detector(sender);
            })
            .expect("portal detector thread");
    }
}

fn run_captive_portal_detector(sender: Sender<PortalEvent>) {
    info!("Captive portal detector started");

    loop {
        // Check NetworkManager connectivity state
        if let Ok(out) = Command::new("nmcli")
            .args(["general", "status"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&out.stdout);
            if stdout.contains("portal") || stdout.contains("limited") {
                // NetworkManager detected a captive portal
                // Try to get the portal URL
                let url = get_captive_portal_url();
                let _ = sender.send(PortalEvent::CaptivePortalDetected {
                    url: url.unwrap_or_else(|| "http://captive.portal".to_string()),
                });
            }
        }

        thread::sleep(Duration::from_secs(30));
    }
}

fn get_captive_portal_url() -> Option<String> {
    // NetworkManager stores captive portal info in connectivity check
    let output = Command::new("sh")
        .args(["-c", "nmcli -t -f CONNECTIVITY general 2>/dev/null"])
        .output()
        .ok()?;

    let stdout = String::from_utf8_lossy(&output.stdout);
    if stdout.trim() == "portal" {
        // Default captive portal test URL that redirects
        Some("http://nmcheck.gnome.org/check_network_status.txt".to_string())
    } else {
        None
    }
}
