//! Help widget for displaying contextual help information
//!
//! Implements R-WIDGET-COMPOSITION:
//! - Simple, focused widget for help display
//! - Support for keyboard shortcuts and descriptions
//! - Theme-aware styling

use crate::config::Theme;
use ratatui::prelude::*;
use ratatui::widgets::{Block, Borders, Paragraph};

/// A help entry with key binding and description
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct HelpEntry {
    /// Keyboard shortcut (e.g., "Ctrl+S")
    key: String,
    /// Description of what the key does
    description: String,
}

impl HelpEntry {
    /// Create a new help entry
    #[must_use]
    pub const fn new(key: String, description: String) -> Self {
        Self { key, description }
    }

    /// Get the key binding
    #[must_use]
    pub fn key(&self) -> &str {
        &self.key
    }

    /// Get the description
    #[must_use]
    pub fn description(&self) -> &str {
        &self.description
    }
}

/// Help widget for displaying keyboard shortcuts and help text
///
/// # Example
///
/// ```ignore
/// let help = Help::new()
///     .add_entry(HelpEntry::new("Ctrl+S".to_string(), "Save file".to_string()))
///     .add_entry(HelpEntry::new("Ctrl+Q".to_string(), "Quit application".to_string()))
///     .with_title("Help");
///
/// help.render(&theme, frame, area);
/// ```
#[derive(Clone, Debug)]
pub struct Help {
    /// Help entries
    entries: Vec<HelpEntry>,
    /// Optional title
    title: Option<String>,
}

impl Help {
    /// Create a new help widget
    #[must_use]
    pub const fn new() -> Self {
        Self {
            entries: Vec::new(),
            title: None,
        }
    }

    /// Add a help entry
    #[must_use]
    pub fn add_entry(mut self, entry: HelpEntry) -> Self {
        self.entries.push(entry);
        self
    }

    /// Set the title
    #[must_use]
    pub fn with_title(mut self, title: &str) -> Self {
        self.title = Some(title.to_string());
        self
    }

    /// Get help entries
    #[must_use]
    pub fn entries(&self) -> &[HelpEntry] {
        &self.entries
    }

    /// Get the title
    #[must_use]
    pub fn title(&self) -> Option<&str> {
        self.title.as_deref()
    }

    /// Add multiple entries at once
    #[must_use]
    pub fn with_entries(mut self, entries: Vec<HelpEntry>) -> Self {
        self.entries.extend(entries);
        self
    }

    /// Render the help widget
    ///
    /// Displays help entries in two columns: key and description
    pub fn render(&self, theme: &Theme, frame: &mut Frame, area: Rect) {
        if area.height < 1 {
            return;
        }

        let mut lines = Vec::new();

        for entry in &self.entries {
            let key_span = Span::styled(format!("{:<15}", entry.key()), theme.selected_style());

            let desc_span = Span::styled(entry.description().to_string(), theme.normal_style());

            let line = Line::from(vec![key_span, Span::raw(" "), desc_span]);
            lines.push(line);
        }

        let block = Block::default()
            .borders(Borders::ALL)
            .border_style(theme.focused_style());

        let block_title = if let Some(title) = &self.title {
            block.title(title.as_str())
        } else {
            block.title("Help")
        };

        let paragraph = Paragraph::new(lines)
            .block(block_title)
            .style(theme.normal_style());

        frame.render_widget(paragraph, area);
    }
}

impl Default for Help {
    fn default() -> Self {
        Self::new()
            .add_entry(HelpEntry::new("?".to_string(), "Toggle help".to_string()))
            .add_entry(HelpEntry::new(
                "q".to_string(),
                "Quit application".to_string(),
            ))
    }
}

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

    #[test]
    fn test_help_entry_new() {
        let entry = HelpEntry::new("Ctrl+S".to_string(), "Save file".to_string());
        assert_eq!(entry.key(), "Ctrl+S");
        assert_eq!(entry.description(), "Save file");
    }

    #[test]
    fn test_help_entry_clone() {
        let entry1 = HelpEntry::new("Ctrl+S".to_string(), "Save file".to_string());
        let entry2 = entry1.clone();
        assert_eq!(entry1, entry2);
    }

    #[test]
    fn test_help_new() {
        let help = Help::new();
        assert_eq!(help.entries().len(), 0);
        assert_eq!(help.title(), None);
    }

    #[test]
    fn test_help_add_entry() {
        let help = Help::new()
            .add_entry(HelpEntry::new(
                "Ctrl+S".to_string(),
                "Save file".to_string(),
            ))
            .add_entry(HelpEntry::new("Ctrl+Q".to_string(), "Quit".to_string()));

        assert_eq!(help.entries().len(), 2);
    }

    #[test]
    fn test_help_title() {
        let help = Help::new().with_title("Keyboard Shortcuts");
        assert_eq!(help.title(), Some("Keyboard Shortcuts"));
    }

    #[test]
    fn test_help_with_entries() {
        let entries = vec![
            HelpEntry::new("Ctrl+S".to_string(), "Save".to_string()),
            HelpEntry::new("Ctrl+Q".to_string(), "Quit".to_string()),
        ];

        let help = Help::new().with_entries(entries);
        assert_eq!(help.entries().len(), 2);
    }

    #[test]
    fn test_help_default() {
        let help = Help::default();
        assert_eq!(help.entries().len(), 2);
    }

    #[test]
    fn test_help_clone() {
        let help1 = Help::new().add_entry(HelpEntry::new("Ctrl+S".to_string(), "Save".to_string()));
        let help2 = help1.clone();
        assert_eq!(help1.entries().len(), help2.entries().len());
    }

    #[test]
    fn test_help_entry_equality() {
        let entry1 = HelpEntry::new("Ctrl+S".to_string(), "Save".to_string());
        let entry2 = HelpEntry::new("Ctrl+S".to_string(), "Save".to_string());
        assert_eq!(entry1, entry2);
    }

    #[test]
    fn test_help_entry_inequality() {
        let entry1 = HelpEntry::new("Ctrl+S".to_string(), "Save".to_string());
        let entry2 = HelpEntry::new("Ctrl+Q".to_string(), "Quit".to_string());
        assert_ne!(entry1, entry2);
    }

    #[test]
    fn test_help_multiple_entries_with_title() {
        let help = Help::new()
            .with_title("Help")
            .add_entry(HelpEntry::new("j".to_string(), "Down".to_string()))
            .add_entry(HelpEntry::new("k".to_string(), "Up".to_string()))
            .add_entry(HelpEntry::new("q".to_string(), "Quit".to_string()));

        assert_eq!(help.entries().len(), 3);
        assert_eq!(help.title(), Some("Help"));
    }

    #[test]
    fn test_help_entry_long_descriptions() {
        let entry = HelpEntry::new(
            "Ctrl+Alt+Shift+S".to_string(),
            "Save with specific options dialog".to_string(),
        );
        assert_eq!(entry.key(), "Ctrl+Alt+Shift+S");
        assert!(entry.description().len() > 20);
    }
}
