//! System tray icon and menu for the agent
//!
//! Provides a tray icon with menu options:
//! - Connection status
//! - Machine name
//! - End session

use anyhow::Result;
use muda::{Menu, MenuEvent, MenuItem, PredefinedMenuItem};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use tracing::info;
use tray_icon::{Icon, TrayIcon, TrayIconBuilder, TrayIconEvent};

#[cfg(windows)]
use windows::Win32::UI::WindowsAndMessaging::{
    DispatchMessageW, PeekMessageW, TranslateMessage, MSG, PM_REMOVE,
};

/// Events that can be triggered from the tray menu
#[derive(Debug, Clone)]
pub enum TrayAction {
    EndSession,
    ShowDetails,
    ShowDebugWindow,
}

/// Tray icon controller
pub struct TrayController {
    _tray_icon: TrayIcon,
    // Kept alive for the lifetime of the tray icon; not read directly.
    _menu: Menu,
    end_session_item: MenuItem,
    debug_item: MenuItem,
    status_item: MenuItem,
    exit_requested: Arc<AtomicBool>,
}

impl TrayController {
    /// Create a new tray controller
    /// `allow_end_session` - If true, show "End Session" menu item (only for support sessions)
    pub fn new(
        machine_name: &str,
        support_code: Option<&str>,
        allow_end_session: bool,
    ) -> Result<Self> {
        // Create menu items
        let status_text = if let Some(code) = support_code {
            format!("Support Session: {}", code)
        } else {
            "Persistent Agent".to_string()
        };

        let status_item = MenuItem::new(&status_text, false, None);
        let machine_item = MenuItem::new(format!("Machine: {}", machine_name), false, None);
        let separator = PredefinedMenuItem::separator();

        // Only show "End Session" for support sessions
        // Persistent agents can only be removed by admin
        let end_session_item = if allow_end_session {
            MenuItem::new("End Session", true, None)
        } else {
            MenuItem::new("Managed by Administrator", false, None)
        };

        // Debug window option (always available)
        let debug_item = MenuItem::new("Show Debug Window", true, None);

        // Build menu
        let menu = Menu::new();
        menu.append(&status_item)?;
        menu.append(&machine_item)?;
        menu.append(&separator)?;
        menu.append(&debug_item)?;
        menu.append(&end_session_item)?;

        // Create tray icon
        let icon = create_default_icon()?;

        let tray_icon = TrayIconBuilder::new()
            .with_menu(Box::new(menu.clone()))
            .with_tooltip(format!("GuruConnect - {}", machine_name))
            .with_icon(icon)
            .build()?;

        let exit_requested = Arc::new(AtomicBool::new(false));

        Ok(Self {
            _tray_icon: tray_icon,
            _menu: menu,
            end_session_item,
            debug_item,
            status_item,
            exit_requested,
        })
    }

    /// Check if exit has been requested
    pub fn exit_requested(&self) -> bool {
        self.exit_requested.load(Ordering::SeqCst)
    }

    /// Update the connection status display
    pub fn update_status(&self, status: &str) {
        self.status_item.set_text(status);
    }

    /// Process pending menu events (call this from the main loop)
    pub fn process_events(&self) -> Option<TrayAction> {
        // Pump Windows message queue to process tray icon events
        #[cfg(windows)]
        pump_windows_messages();

        // Check for menu events
        if let Ok(event) = MenuEvent::receiver().try_recv() {
            if event.id == self.end_session_item.id() {
                info!("End session requested from tray menu");
                self.exit_requested.store(true, Ordering::SeqCst);
                return Some(TrayAction::EndSession);
            }
            if event.id == self.debug_item.id() {
                info!("Debug window requested from tray menu");
                return Some(TrayAction::ShowDebugWindow);
            }
        }

        // Check for tray icon events (like double-click)
        if let Ok(TrayIconEvent::DoubleClick { .. }) = TrayIconEvent::receiver().try_recv() {
            info!("Tray icon double-clicked");
            return Some(TrayAction::ShowDetails);
        }

        None
    }
}

/// Pump the Windows message queue to process tray icon events
#[cfg(windows)]
fn pump_windows_messages() {
    unsafe {
        let mut msg = MSG::default();
        // Process all pending messages
        while PeekMessageW(&mut msg, None, 0, 0, PM_REMOVE).as_bool() {
            let _ = TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }
    }
}

/// Create a simple default icon (green circle for connected)
fn create_default_icon() -> Result<Icon> {
    // Create a simple 32x32 green icon
    let size = 32u32;
    let mut rgba = vec![0u8; (size * size * 4) as usize];

    let center = size as f32 / 2.0;
    let radius = size as f32 / 2.0 - 2.0;

    for y in 0..size {
        for x in 0..size {
            let dx = x as f32 - center;
            let dy = y as f32 - center;
            let dist = (dx * dx + dy * dy).sqrt();

            let idx = ((y * size + x) * 4) as usize;

            if dist <= radius {
                // Green circle
                rgba[idx] = 76; // R
                rgba[idx + 1] = 175; // G
                rgba[idx + 2] = 80; // B
                rgba[idx + 3] = 255; // A
            } else if dist <= radius + 1.0 {
                // Anti-aliased edge
                let alpha = ((radius + 1.0 - dist) * 255.0) as u8;
                rgba[idx] = 76;
                rgba[idx + 1] = 175;
                rgba[idx + 2] = 80;
                rgba[idx + 3] = alpha;
            }
        }
    }

    let icon = Icon::from_rgba(rgba, size, size)?;
    Ok(icon)
}

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

    #[test]
    fn test_create_icon() {
        let icon = create_default_icon();
        assert!(icon.is_ok());
    }
}
