/// Screen types and navigation system
///
/// This module defines the screen/mode system for the TUI.
/// Screens can be:
/// - Base screens (Boot, Main) - always visible
/// - Overlay screens (Agent Builder, Run Manager, Settings) - full-screen modals
/// - Popup screens (Confirmations, Alerts) - small overlays
use serde::{Deserialize, Serialize};

/// Screen enum - represents all possible screens in the TUI
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum Screen {
    // Base screens
    Boot,
    Main,

    // Overlay screens (full-screen modals)
    AgentBuilder,
    RunManager,
    SentinelConfig,
    ShieldDashboard,
    Settings,
    AgentList,
    ConnectionPortal,
    SetupPortal,
    /// Gateway traffic / server-style observability (scaffold; live stream TBD)
    PortalMonitoring,

    // Popup screens (small overlays)
    Confirmation {
        message: String,
        action: String,
    },
    Alert {
        message: String,
    },
}

impl Screen {
    /// Returns true if this screen is an overlay (covers base screen)
    pub fn is_overlay(&self) -> bool {
        matches!(
            self,
            Screen::AgentBuilder | Screen::RunManager | Screen::SentinelConfig | Screen::ShieldDashboard | Screen::Settings | Screen::AgentList
        )
    }

    /// Returns true if this screen is a popup (small overlay)
    pub fn is_popup(&self) -> bool {
        matches!(self, Screen::Confirmation { .. } | Screen::Alert { .. })
    }

    /// Returns true if this screen is a base screen (full-screen standalone)
    pub fn is_base(&self) -> bool {
        matches!(
            self,
            Screen::Boot
                | Screen::Main
                | Screen::ConnectionPortal
                | Screen::SetupPortal
                | Screen::PortalMonitoring
        )
    }

    /// Returns the screen name for display
    #[allow(dead_code)]
    pub fn name(&self) -> &str {
        match self {
            Screen::Boot => "Boot",
            Screen::Main => "Main",
            Screen::AgentBuilder => "Agent Builder",
            Screen::RunManager => "Run Manager",
            Screen::SentinelConfig => "Sentinel Config",
            Screen::ShieldDashboard => "Shield",
            Screen::Settings => "Settings",
            Screen::AgentList => "Agent List",
            Screen::ConnectionPortal => "Connection Portal",
            Screen::SetupPortal => "Setup Portal",
            Screen::PortalMonitoring => "Portal Monitoring",
            Screen::Confirmation { .. } => "Confirmation",
            Screen::Alert { .. } => "Alert",
        }
    }
}

/// Navigation state - manages screen stack and transitions
#[derive(Debug, Clone)]
pub struct NavigationState {
    /// Current base screen (Boot or Main)
    pub base_screen: Screen,

    /// Overlay stack (full-screen modals)
    /// Last item is the currently visible overlay
    pub overlay_stack: Vec<Screen>,

    /// Popup stack (small overlays on top of everything)
    /// Last item is the currently visible popup
    pub popup_stack: Vec<Screen>,
}

impl Default for NavigationState {
    fn default() -> Self {
        Self {
            base_screen: Screen::Boot,
            overlay_stack: Vec::new(),
            popup_stack: Vec::new(),
        }
    }
}

impl NavigationState {
    /// Create a new navigation state starting at Boot
    pub fn new() -> Self {
        Self::default()
    }

    /// Get the currently visible screen (topmost in hierarchy)
    pub fn current_screen(&self) -> &Screen {
        // Priority: Popup > Overlay > Base
        if let Some(popup) = self.popup_stack.last() {
            popup
        } else if let Some(overlay) = self.overlay_stack.last() {
            overlay
        } else {
            &self.base_screen
        }
    }

    /// Navigate to a base screen (Boot or Main)
    pub fn navigate_to_base(&mut self, screen: Screen) {
        if screen.is_base() {
            self.base_screen = screen;
            // Clear overlays and popups when changing base screen
            self.overlay_stack.clear();
            self.popup_stack.clear();
        }
    }

    /// Push an overlay screen (Agent Builder, Run Manager, Settings)
    pub fn push_overlay(&mut self, screen: Screen) {
        if screen.is_overlay() {
            self.overlay_stack.push(screen);
        }
    }

    /// Pop the current overlay and return to previous screen
    pub fn pop_overlay(&mut self) -> Option<Screen> {
        self.overlay_stack.pop()
    }

    /// Push a popup screen (Confirmation, Alert, Help)
    pub fn push_popup(&mut self, screen: Screen) {
        if screen.is_popup() {
            self.popup_stack.push(screen);
        }
    }

    /// Pop the current popup
    pub fn pop_popup(&mut self) -> Option<Screen> {
        self.popup_stack.pop()
    }

    /// Close all overlays and popups (return to base screen)
    #[allow(dead_code)]
    pub fn close_all(&mut self) {
        self.overlay_stack.clear();
        self.popup_stack.clear();
    }

    /// Check if we're currently on the base screen (no overlays/popups)
    #[allow(dead_code)]
    pub fn is_on_base(&self) -> bool {
        self.overlay_stack.is_empty() && self.popup_stack.is_empty()
    }

    /// Check if we have any overlays open
    pub fn has_overlay(&self) -> bool {
        !self.overlay_stack.is_empty()
    }

    /// Check if we have any popups open
    pub fn has_popup(&self) -> bool {
        !self.popup_stack.is_empty()
    }
}

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

    #[test]
    fn test_screen_classification() {
        assert!(Screen::Boot.is_base());
        assert!(Screen::Main.is_base());
        assert!(Screen::AgentBuilder.is_overlay());
        assert!(Screen::RunManager.is_overlay());
        assert!(Screen::Settings.is_overlay());
        assert!(Screen::Help.is_popup());
    }

    #[test]
    fn test_navigation_state() {
        let mut nav = NavigationState::new();

        // Start at Boot
        assert_eq!(nav.current_screen(), &Screen::Boot);
        assert!(nav.is_on_base());

        // Navigate to Main
        nav.navigate_to_base(Screen::Main);
        assert_eq!(nav.current_screen(), &Screen::Main);

        // Push overlay
        nav.push_overlay(Screen::AgentBuilder);
        assert_eq!(nav.current_screen(), &Screen::AgentBuilder);
        assert!(nav.has_overlay());
        assert!(!nav.is_on_base());

        // Push popup
        nav.push_popup(Screen::Alert {
            message: "Test".to_string(),
        });
        assert_eq!(
            nav.current_screen(),
            &Screen::Alert {
                message: "Test".to_string()
            }
        );
        assert!(nav.has_popup());

        // Pop popup
        nav.pop_popup();
        assert_eq!(nav.current_screen(), &Screen::AgentBuilder);

        // Pop overlay
        nav.pop_overlay();
        assert_eq!(nav.current_screen(), &Screen::Main);
        assert!(nav.is_on_base());
    }

    #[test]
    fn test_close_all() {
        let mut nav = NavigationState::new();
        nav.navigate_to_base(Screen::Main);
        nav.push_overlay(Screen::AgentBuilder);
        nav.push_popup(Screen::Alert {
            message: "Test".to_string(),
        });

        nav.close_all();
        assert!(nav.is_on_base());
        assert_eq!(nav.current_screen(), &Screen::Main);
    }
}
