//! Terminal lifecycle management
//!
//! Implements R-GRACEFUL-SHUTDOWN: Handle terminal restoration on exit properly
//! using RAII (Resource Acquisition Is Initialization) pattern.

use anyhow::Result;
use crossterm::execute;
use crossterm::terminal::{self, EnterAlternateScreen, LeaveAlternateScreen};
use std::io;

/// RAII guard for terminal setup and cleanup
///
/// Automatically enables raw mode and alternate screen on creation,
/// and restores terminal state on drop. This ensures terminal is always
/// properly restored even if panic occurs.
///
/// # Example
///
/// ```ignore
/// let _guard = TerminalGuard::setup()?;
/// // Terminal is in raw mode with alternate screen
/// // ... application code ...
/// // Terminal automatically restored when _guard is dropped
/// ```
pub struct TerminalGuard;

impl TerminalGuard {
    /// Setup terminal for TUI application
    ///
    /// Enables:
    /// - Raw mode (no echoing, line buffering)
    /// - Alternate screen (doesn't pollute terminal history)
    /// - Mouse capture (for mouse events)
    ///
    /// # Returns
    ///
    /// Result with guard that must be kept in scope for duration of app
    ///
    /// # Errors
    ///
    /// Returns an error if the operation fails
    pub fn setup() -> Result<Self> {
        terminal::enable_raw_mode()?;

        let mut stdout = io::stdout();
        execute!(
            stdout,
            EnterAlternateScreen,
            crossterm::event::EnableMouseCapture,
        )?;

        Ok(Self)
    }
}

impl Drop for TerminalGuard {
    fn drop(&mut self) {
        // Disable raw mode
        let _ = terminal::disable_raw_mode();

        // Restore terminal state
        let mut stdout = io::stdout();
        let _ = execute!(
            stdout,
            LeaveAlternateScreen,
            crossterm::event::DisableMouseCapture,
        );
    }
}

/// Terminal size information
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct TerminalSize {
    /// Terminal width in columns
    pub width: u16,
    /// Terminal height in rows
    pub height: u16,
}

impl TerminalSize {
    /// Get current terminal size
    ///
    /// # Errors
    ///
    /// Returns an error if the operation fails
    pub fn current() -> Result<Self> {
        let (width, height) = terminal::size()?;
        Ok(Self { width, height })
    }

    /// Check if terminal size is valid (non-zero)
    #[must_use]
    pub const fn is_valid(&self) -> bool {
        self.width > 0 && self.height > 0
    }
}

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

    #[test]
    fn test_terminal_size_valid() {
        let size = TerminalSize {
            width: 80,
            height: 24,
        };
        assert!(size.is_valid());
    }

    #[test]
    fn test_terminal_size_invalid() {
        let size = TerminalSize {
            width: 0,
            height: 24,
        };
        assert!(!size.is_valid());
    }

    #[test]
    fn test_terminal_size_clone() {
        let size1 = TerminalSize {
            width: 80,
            height: 24,
        };
        let size2 = size1;
        assert_eq!(size1, size2);
    }
}
