use super::*;
use crate::launcher::state::{BreakoutSizePreset, PreviewSourceSize};

pub(super) fn install_popout_drag(
    window: &gtk::ApplicationWindow,
    widget: &impl IsA<gtk::Widget>,
) {
    let drag = gtk::GestureClick::new();
    drag.set_button(0);
    let native = window.clone();
    drag.connect_pressed(move |gesture, _press, x, y| {
        let Some(device) = gesture.current_event_device() else {
            return;
        };
        let Some(surface) = native.surface() else {
            return;
        };
        let Some(toplevel) = surface.dynamic_cast_ref::<gdk::Toplevel>() else {
            return;
        };
        let timestamp = gesture
            .current_event()
            .map(|event| event.time())
            .unwrap_or(0);
        toplevel.begin_move(&device, 1, x, y, timestamp);
    });
    widget.add_controller(drag);
}

pub(super) fn apply_popout_window_geometry(
    window: &gtk::ApplicationWindow,
    root: &gtk::Box,
    picture: &gtk::Picture,
    size: BreakoutSizeChoice,
    display_limit: PreviewSourceSize,
) {
    picture.set_size_request(size.width, size.height);
    root.set_size_request(size.width, size.height);
    window.set_default_size(size.width, size.height);
    if should_cover_display(size, display_limit) {
        fullscreen_on_largest_monitor(window);
    } else {
        window.unfullscreen();
    }
}

pub(super) fn schedule_popout_window_geometry(
    window: gtk::ApplicationWindow,
    root: gtk::Box,
    picture: gtk::Picture,
    size: BreakoutSizeChoice,
    display_limit: PreviewSourceSize,
) {
    for delay_ms in [0_u64, 25, 150] {
        let window = window.clone();
        let root = root.clone();
        let picture = picture.clone();
        glib::timeout_add_local_once(std::time::Duration::from_millis(delay_ms), move || {
            apply_popout_window_geometry(&window, &root, &picture, size, display_limit);
            window.present();
        });
    }
}

fn fullscreen_on_largest_monitor(window: &gtk::ApplicationWindow) {
    let Some(display) = gdk::Display::default() else {
        window.fullscreen();
        return;
    };
    let monitors = display.monitors();
    let monitor = (0..monitors.n_items())
        .filter_map(|idx| monitors.item(idx))
        .filter_map(|obj| obj.downcast::<gdk::Monitor>().ok())
        .max_by_key(|monitor| {
            let geometry = monitor.geometry();
            let scale = monitor.scale_factor().max(1);
            geometry.width().max(1) as i64
                * scale as i64
                * geometry.height().max(1) as i64
                * scale as i64
        });
    if let Some(monitor) = monitor.as_ref() {
        window.fullscreen_on_monitor(monitor);
    } else {
        window.fullscreen();
    }
}

fn should_cover_display(size: BreakoutSizeChoice, display_limit: PreviewSourceSize) -> bool {
    matches!(size.preset, BreakoutSizePreset::FillDisplay)
        || (size.width >= display_limit.width.max(1) as i32
            && size.height >= display_limit.height.max(1) as i32)
}

pub fn present_popout_windows(popouts: &Rc<RefCell<[Option<PopoutWindowHandle>; 2]>>) {
    for handle in popouts.borrow().iter().flatten() {
        handle.window.present();
    }
}
