mod menu;

use tray_icon::{
    menu::{AboutMetadata, Menu, MenuEvent, MenuItem, PredefinedMenuItem},
    TrayIconBuilder, TrayIconEvent,
};
use winit::event_loop::{ControlFlow, EventLoopBuilder};
use image;

#[cfg(target_os="windows")]
use winit::platform::windows::EventLoopBuilderExtWindows;

use jarvis_core::config;

const TRAY_ICON_BYTES: &[u8] = include_bytes!("../../../resources/icons/32x32.png");

pub fn init_blocking() {
    // load tray icon
    //let icon_path = format!("{}/../../resources/icons/{}", env!("CARGO_MANIFEST_DIR"), config::TRAY_ICON);
    //let icon = load_icon(std::path::Path::new(&icon_path));
    let icon = load_icon_from_bytes(TRAY_ICON_BYTES);

    // form tray menu
    let tray_menu = Menu::with_items(&[
        &MenuItem::new("Перезапуск", true, None),
        &MenuItem::new("Настройки", true, None),
        &MenuItem::new("Выход", true, None),
    ])
    .unwrap();

    let tray_menu = Menu::with_items(&[
        &MenuItem::with_id("restart", "Перезапуск", true, None),
        &MenuItem::with_id("settings", "Настройки", true, None),
        &MenuItem::with_id("exit", "Выход", true, None),
    ]).unwrap();

    let _tray_icon = TrayIconBuilder::new()
        .with_menu(Box::new(tray_menu))
        .with_tooltip(config::TRAY_TOOLTIP)
        .with_icon(icon)
        .build()
        .unwrap();

    let menu_channel = MenuEvent::receiver();
    // let tray_channel = TrayIconEvent::receiver();

    // @TODO: Test on Linux
    // We need gtk for the tray icon to show up, we need to initialize gtk and create the tray_icon
    #[cfg(target_os = "linux")]
    {
        gtk::init().unwrap();
        glib::timeout_add_local(std::time::Duration::from_millis(100), move || {
            if let Ok(event) = menu_channel.try_recv() {
                handle_menu_event(&event);
            }
            glib::ControlFlow::Continue
        });
        gtk::main();
    }

    // @TODO: Test on MacOS
    #[cfg(target_os = "macos")]
    {
        // macOS needs proper run loop - tao or winit on main thread
        use winit::event_loop::{EventLoop, ControlFlow};
        let event_loop = EventLoop::new().unwrap();
        event_loop.run(move |_event, elwt| {
            elwt.set_control_flow(ControlFlow::Wait);
            if let Ok(event) = menu_channel.try_recv() {
                handle_menu_event(&event);
            }
        }).unwrap();
    }

    #[cfg(target_os = "windows")]
    {
        // simple polling works on Windows
        loop {
            if let Ok(event) = menu_channel.try_recv() {
                handle_menu_event(&event);
            }
            
            // pump Windows messages
            unsafe {
                let mut msg: winapi::um::winuser::MSG = std::mem::zeroed();
                while winapi::um::winuser::PeekMessageW(
                    &mut msg, 
                    std::ptr::null_mut(), 
                    0, 0, 
                    winapi::um::winuser::PM_REMOVE
                ) != 0 {
                    winapi::um::winuser::TranslateMessage(&msg);
                    winapi::um::winuser::DispatchMessageW(&msg);
                }
            }
            std::thread::sleep(std::time::Duration::from_millis(50));
        }
    }

    info!("Tray initialized.");
}

fn handle_menu_event(event: &MenuEvent) {
    match event.id.0.as_str() {
        "exit" => std::process::exit(0),
        "restart" => { /* restart logic */ }
        "settings" => { /* open settings */ }
        _ => {}
    }
}

fn load_icon_from_bytes(bytes: &[u8]) -> tray_icon::Icon {
    let image = image::load_from_memory(bytes)
        .expect("Failed to load icon")
        .into_rgba8();
    let (width, height) = image.dimensions();
    let rgba = image.into_raw();
    tray_icon::Icon::from_rgba(rgba, width, height).expect("Failed to create icon")
}

fn load_icon(path: &std::path::Path) -> tray_icon::Icon {
    let (icon_rgba, icon_width, icon_height) = {
        let image = image::open(path)
            .expect("Failed to open icon path")
            .into_rgba8();
        let (width, height) = image.dimensions();
        let rgba = image.into_raw();
        (rgba, width, height)
    };
    tray_icon::Icon::from_rgba(icon_rgba, icon_width, icon_height).expect("Failed to open icon")
}
