// client/src/output/display.rs

use gtk::gdk;
use gtk::prelude::ListModelExt;
use gtk::prelude::*;
use tracing::debug;

#[derive(Clone, Debug)]
pub struct MonitorInfo {
    pub geometry: gdk::Rectangle,
    pub scale_factor: i32,
    pub is_internal: bool,
}

/// Enumerate monitors sorted by our desired priority.
///
/// Inputs: none; the function reads the current GTK display if one is
/// available.
/// Outputs: a priority-ordered monitor list, or a single fallback monitor when
/// no display is attached.
/// Why: window placement should still have a sane default in headless tests
/// and on fresh boots before the desktop session has fully settled.
pub fn enumerate_monitors() -> Vec<MonitorInfo> {
    let Some(display) = gdk::Display::default() else {
        tracing::warn!("⚠️  no GDK display - falling back to single-monitor 0,0");
        return vec![MonitorInfo {
            geometry: gdk::Rectangle::new(0, 0, 1920, 1080),
            scale_factor: 1,
            is_internal: false,
        }];
    };
    let model = display.monitors(); // gio::ListModel

    let mut list: Vec<_> = (0..model.n_items())
        .filter_map(|i| model.item(i))
        .filter_map(|obj| obj.downcast::<gdk::Monitor>().ok())
        .map(|m| {
            // -------- internal vs external ----------------------------------
            let connector = m.connector().unwrap_or_default(); // e.g. "eDP-1"
            let is_internal = connector.starts_with("eDP")
                || connector.starts_with("LVDS")
                || connector.starts_with("DSI")
                || connector.to_ascii_lowercase().contains("internal");

            // -------- geometry / scale --------------------------------------
            let geometry = m.geometry();
            let scale_factor = m.scale_factor();

            debug!(
                "🖥️  monitor: {:?}, connector={:?}, geom={:?}, scale={}",
                m.model(),
                connector,
                geometry,
                scale_factor
            );
            MonitorInfo {
                geometry,
                scale_factor,
                is_internal,
            }
        })
        .collect();

    // external first, built-in last
    list.sort_by_key(|m| m.is_internal);
    debug!("🖥️  sorted monitors = {:?}", list);
    list
}

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

    #[test]
    fn enumerate_monitors_returns_fallback_when_headless() {
        let monitors = enumerate_monitors();
        assert!(!monitors.is_empty());
        assert!(monitors[0].geometry.width() > 0);
        assert!(monitors[0].geometry.height() > 0);
    }
}
