//! Centralized theme and color scheme for TUI.
//!
//! This module provides consistent styling across all TUI views and modes.

use ratatui::prelude::*;
use std::sync::RwLock;

/// Color scheme for the TUI application.
/// Provides semantic colors for different UI elements.
#[derive(Debug, Clone, Copy)]
pub struct ColorScheme {
    // Change status colors
    pub added: Color,
    pub removed: Color,
    pub modified: Color,
    pub unchanged: Color,

    // Severity colors
    pub critical: Color,
    pub high: Color,
    pub medium: Color,
    pub low: Color,
    pub info: Color,

    // License category colors
    pub permissive: Color,
    pub copyleft: Color,
    pub weak_copyleft: Color,
    pub proprietary: Color,
    pub unknown_license: Color,

    // UI element colors
    pub primary: Color,
    pub secondary: Color,
    pub accent: Color,
    pub muted: Color,
    pub border: Color,
    pub border_focused: Color,
    pub background: Color,
    pub background_alt: Color,
    pub text: Color,
    pub text_muted: Color,
    pub selection: Color,
    pub highlight: Color,

    // Status colors
    pub success: Color,
    pub warning: Color,
    pub error: Color,

    // Badge foreground colors (for text on colored backgrounds)
    pub badge_fg_dark: Color, // For badges on bright backgrounds (yellow, cyan)
    pub badge_fg_light: Color, // For badges on dark backgrounds (magenta, red, blue)

    // Side-by-side view colors
    pub selection_bg: Color,        // Background for selected row
    pub search_highlight_bg: Color, // Background for search matches
    pub error_bg: Color,            // Background for removed/error highlights
    pub success_bg: Color,          // Background for added/success highlights

    // Source view scope highlighting
    pub scope_bg: Color, // Subtle background for enclosing bracket scope
}

impl Default for ColorScheme {
    fn default() -> Self {
        Self::dark()
    }
}

impl ColorScheme {
    /// Const dark theme for static initialization
    const fn dark_const() -> Self {
        Self {
            // Change status
            added: Color::Green,
            removed: Color::Red,
            modified: Color::Yellow,
            unchanged: Color::Gray,

            // Severity
            critical: Color::Magenta,
            high: Color::Red,
            medium: Color::Yellow,
            low: Color::Cyan,
            info: Color::Blue,

            // License categories
            permissive: Color::Green,
            copyleft: Color::Yellow,
            weak_copyleft: Color::Cyan,
            proprietary: Color::Red,
            unknown_license: Color::DarkGray,

            // UI elements
            primary: Color::Cyan,
            secondary: Color::Blue,
            accent: Color::Yellow,
            muted: Color::DarkGray,
            border: Color::DarkGray,
            border_focused: Color::Cyan,
            background: Color::Reset,
            background_alt: Color::Rgb(30, 30, 40),
            text: Color::White,
            text_muted: Color::Gray,
            selection: Color::Rgb(50, 50, 70),
            highlight: Color::Yellow,

            // Status
            success: Color::Green,
            warning: Color::Yellow,
            error: Color::Red,

            // Badge foregrounds
            badge_fg_dark: Color::Black,
            badge_fg_light: Color::White,

            // Side-by-side view colors
            selection_bg: Color::Rgb(60, 60, 80),
            search_highlight_bg: Color::Rgb(100, 80, 0),
            error_bg: Color::Rgb(80, 30, 30),
            success_bg: Color::Rgb(30, 80, 30),

            // Source view scope highlighting
            scope_bg: Color::Rgb(35, 35, 50),
        }
    }

    /// Dark theme (default)
    #[must_use]
    pub const fn dark() -> Self {
        Self {
            // Change status
            added: Color::Green,
            removed: Color::Red,
            modified: Color::Yellow,
            unchanged: Color::Gray,

            // Severity
            critical: Color::Magenta,
            high: Color::Red,
            medium: Color::Yellow,
            low: Color::Cyan,
            info: Color::Blue,

            // License categories
            permissive: Color::Green,
            copyleft: Color::Yellow,
            weak_copyleft: Color::Cyan,
            proprietary: Color::Red,
            unknown_license: Color::DarkGray,

            // UI elements
            primary: Color::Cyan,
            secondary: Color::Blue,
            accent: Color::Yellow,
            muted: Color::DarkGray,
            border: Color::DarkGray,
            border_focused: Color::Cyan,
            background: Color::Reset,
            background_alt: Color::Rgb(30, 30, 40),
            text: Color::White,
            text_muted: Color::Gray,
            selection: Color::Rgb(50, 50, 70),
            highlight: Color::Yellow,

            // Status
            success: Color::Green,
            warning: Color::Yellow,
            error: Color::Red,

            // Badge foregrounds
            badge_fg_dark: Color::Black,
            badge_fg_light: Color::White,

            // Side-by-side view colors
            selection_bg: Color::Rgb(60, 60, 80),
            search_highlight_bg: Color::Rgb(100, 80, 0),
            error_bg: Color::Rgb(80, 30, 30),
            success_bg: Color::Rgb(30, 80, 30),

            // Source view scope highlighting
            scope_bg: Color::Rgb(35, 35, 50),
        }
    }

    /// Light theme
    #[must_use]
    pub const fn light() -> Self {
        Self {
            // Change status
            added: Color::Rgb(0, 128, 0),
            removed: Color::Rgb(200, 0, 0),
            modified: Color::Rgb(180, 140, 0),
            unchanged: Color::Rgb(100, 100, 100),

            // Severity
            critical: Color::Rgb(128, 0, 128),
            high: Color::Rgb(200, 0, 0),
            medium: Color::Rgb(180, 140, 0),
            low: Color::Rgb(0, 128, 128),
            info: Color::Rgb(0, 0, 200),

            // License categories
            permissive: Color::Rgb(0, 128, 0),
            copyleft: Color::Rgb(180, 140, 0),
            weak_copyleft: Color::Rgb(0, 128, 128),
            proprietary: Color::Rgb(200, 0, 0),
            unknown_license: Color::Rgb(100, 100, 100),

            // UI elements
            primary: Color::Rgb(0, 100, 150),
            secondary: Color::Rgb(0, 0, 150),
            accent: Color::Rgb(180, 140, 0),
            muted: Color::Rgb(150, 150, 150),
            border: Color::Rgb(180, 180, 180),
            border_focused: Color::Rgb(0, 100, 150),
            background: Color::Rgb(255, 255, 255),
            background_alt: Color::Rgb(240, 240, 245),
            text: Color::Rgb(30, 30, 30),
            text_muted: Color::Rgb(100, 100, 100),
            selection: Color::Rgb(200, 220, 240),
            highlight: Color::Rgb(180, 140, 0),

            // Status
            success: Color::Rgb(0, 128, 0),
            warning: Color::Rgb(180, 140, 0),
            error: Color::Rgb(200, 0, 0),

            // Badge foregrounds (reversed for light theme)
            badge_fg_dark: Color::Rgb(30, 30, 30),
            badge_fg_light: Color::White,

            // Side-by-side view colors (lighter for light theme)
            selection_bg: Color::Rgb(200, 220, 240),
            search_highlight_bg: Color::Rgb(255, 230, 150),
            error_bg: Color::Rgb(255, 200, 200),
            success_bg: Color::Rgb(200, 255, 200),

            // Source view scope highlighting
            scope_bg: Color::Rgb(235, 240, 250),
        }
    }

    /// High contrast theme (accessibility)
    #[must_use]
    pub const fn high_contrast() -> Self {
        Self {
            // Change status
            added: Color::Green,
            removed: Color::LightRed,
            modified: Color::LightYellow,
            unchanged: Color::White,

            // Severity
            critical: Color::LightMagenta,
            high: Color::LightRed,
            medium: Color::LightYellow,
            low: Color::LightCyan,
            info: Color::LightBlue,

            // License categories
            permissive: Color::LightGreen,
            copyleft: Color::LightYellow,
            weak_copyleft: Color::LightCyan,
            proprietary: Color::LightRed,
            unknown_license: Color::Gray,

            // UI elements
            primary: Color::LightCyan,
            secondary: Color::LightBlue,
            accent: Color::LightYellow,
            muted: Color::Gray,
            border: Color::White,
            border_focused: Color::LightCyan,
            background: Color::Black,
            background_alt: Color::Rgb(20, 20, 20),
            text: Color::White,
            text_muted: Color::Gray,
            selection: Color::White,
            highlight: Color::LightYellow,

            // Status
            success: Color::LightGreen,
            warning: Color::LightYellow,
            error: Color::LightRed,

            // Badge foregrounds
            badge_fg_dark: Color::Black,
            badge_fg_light: Color::White,

            // Side-by-side view colors (high contrast)
            selection_bg: Color::Rgb(50, 50, 80),
            search_highlight_bg: Color::Rgb(120, 100, 0),
            error_bg: Color::Rgb(100, 30, 30),
            success_bg: Color::Rgb(30, 100, 30),

            // Source view scope highlighting
            scope_bg: Color::Rgb(25, 25, 40),
        }
    }

    /// Get color for severity level
    #[must_use]
    pub fn severity_color(&self, severity: &str) -> Color {
        match severity.to_lowercase().as_str() {
            "critical" => self.critical,
            "high" => self.high,
            "medium" | "moderate" => self.medium,
            "low" => self.low,
            "info" | "informational" | "none" => self.info,
            _ => self.text_muted,
        }
    }

    /// Get a subtle background tint for severity (used for row highlighting)
    #[must_use]
    pub fn severity_bg_tint(&self, severity: &str) -> Color {
        match severity.to_lowercase().as_str() {
            "critical" => Color::Rgb(50, 15, 50),
            "high" => Color::Rgb(50, 15, 15),
            "medium" => Color::Rgb(45, 40, 10),
            "low" => Color::Rgb(15, 35, 40),
            _ => Color::Reset,
        }
    }

    /// Get color for change status
    #[must_use]
    pub fn change_color(&self, status: &str) -> Color {
        match status.to_lowercase().as_str() {
            "added" | "new" | "introduced" => self.added,
            "removed" | "deleted" | "resolved" => self.removed,
            "modified" | "changed" | "updated" => self.modified,
            _ => self.unchanged,
        }
    }

    /// Get color for license category
    #[must_use]
    pub fn license_color(&self, category: &str) -> Color {
        match category.to_lowercase().as_str() {
            "permissive" => self.permissive,
            "copyleft" | "strong copyleft" => self.copyleft,
            "weak copyleft" => self.weak_copyleft,
            "proprietary" | "commercial" => self.proprietary,
            _ => self.unknown_license,
        }
    }

    /// Get appropriate foreground color for severity badges
    /// Returns light fg for dark backgrounds (critical, high, info) and dark fg for bright backgrounds
    #[must_use]
    pub fn severity_badge_fg(&self, severity: &str) -> Color {
        match severity.to_lowercase().as_str() {
            "critical" | "high" | "info" | "informational" => self.badge_fg_light,
            _ => self.badge_fg_dark,
        }
    }

    /// Get KEV (Known Exploited Vulnerabilities) badge color
    /// Returns a bright red/orange color to indicate active exploitation
    #[must_use]
    pub const fn kev(&self) -> Color {
        Color::Rgb(255, 100, 50) // Bright orange-red for urgency
    }

    /// Get KEV badge foreground color
    #[must_use]
    pub const fn kev_badge_fg(&self) -> Color {
        self.badge_fg_dark
    }

    /// Get direct dependency badge background color (green - easy to fix)
    #[must_use]
    pub const fn direct_dep(&self) -> Color {
        Color::Rgb(46, 160, 67) // GitHub green
    }

    /// Get transitive dependency badge background color (gray - harder to fix)
    #[must_use]
    pub const fn transitive_dep(&self) -> Color {
        Color::Rgb(110, 118, 129) // Muted gray
    }

    /// Get appropriate foreground color for change status badges
    /// All change colors (green, red, yellow) work best with dark foreground
    #[must_use]
    pub const fn change_badge_fg(&self) -> Color {
        self.badge_fg_dark
    }

    /// Get appropriate foreground color for license category badges
    #[must_use]
    pub fn license_badge_fg(&self, category: &str) -> Color {
        match category.to_lowercase().as_str() {
            "proprietary" | "commercial" => self.badge_fg_light,
            _ => self.badge_fg_dark,
        }
    }

    /// Chart color palette for visualizations
    #[must_use]
    pub const fn chart_palette(&self) -> [Color; 5] {
        [
            self.primary,
            self.success,
            self.warning,
            self.critical,
            self.secondary,
        ]
    }
}

/// Global theme instance (runtime switchable)
static THEME: RwLock<Theme> = RwLock::new(Theme::dark_const());

/// Theme configuration
#[derive(Debug, Clone)]
pub struct Theme {
    pub colors: ColorScheme,
    pub name: &'static str,
}

impl Default for Theme {
    fn default() -> Self {
        Self::dark()
    }
}

impl Theme {
    /// Const dark theme for static initialization
    const fn dark_const() -> Self {
        Self {
            colors: ColorScheme::dark_const(),
            name: "dark",
        }
    }

    #[must_use]
    pub const fn dark() -> Self {
        Self {
            colors: ColorScheme::dark(),
            name: "dark",
        }
    }

    #[must_use]
    pub const fn light() -> Self {
        Self {
            colors: ColorScheme::light(),
            name: "light",
        }
    }

    #[must_use]
    pub const fn high_contrast() -> Self {
        Self {
            colors: ColorScheme::high_contrast(),
            name: "high-contrast",
        }
    }

    #[must_use]
    pub fn from_name(name: &str) -> Self {
        match name.to_lowercase().as_str() {
            "light" => Self::light(),
            "high-contrast" | "highcontrast" | "hc" => Self::high_contrast(),
            _ => Self::dark(),
        }
    }

    /// Get the next theme in the rotation
    #[must_use]
    pub fn next(&self) -> Self {
        match self.name {
            "dark" => Self::light(),
            "light" => Self::high_contrast(),
            _ => Self::dark(),
        }
    }
}

/// Get the current theme name
pub fn current_theme_name() -> &'static str {
    THEME.read().expect("THEME lock not poisoned").name
}

/// Set the current theme
pub fn set_theme(theme: Theme) {
    *THEME.write().expect("THEME lock not poisoned") = theme;
}

/// Toggle to the next theme in rotation (dark -> light -> high-contrast -> dark)
pub fn toggle_theme() -> &'static str {
    let mut theme = THEME.write().expect("THEME lock not poisoned");
    *theme = theme.next();
    theme.name
}

/// Convenience function to get current colors
pub fn colors() -> ColorScheme {
    THEME.read().expect("THEME lock not poisoned").colors
}

// ============================================================================
// Style Helpers
// ============================================================================

/// Common style presets for consistent UI elements
pub struct Styles;

impl Styles {
    /// Header title style
    #[must_use]
    pub fn header_title() -> Style {
        Style::default().fg(colors().primary).bold()
    }

    /// Section title style
    #[must_use]
    pub fn section_title() -> Style {
        Style::default().fg(colors().primary).bold()
    }

    /// Subsection title style
    #[must_use]
    pub fn subsection_title() -> Style {
        Style::default().fg(colors().primary)
    }

    /// Normal text style
    #[must_use]
    pub fn text() -> Style {
        Style::default().fg(colors().text)
    }

    /// Muted/secondary text style
    #[must_use]
    pub fn text_muted() -> Style {
        Style::default().fg(colors().text_muted)
    }

    /// Label text style
    #[must_use]
    pub fn label() -> Style {
        Style::default().fg(colors().muted)
    }

    /// Value text style (for data values)
    #[must_use]
    pub fn value() -> Style {
        Style::default().fg(colors().text).bold()
    }

    /// Highlighted/accent style
    #[must_use]
    pub fn highlight() -> Style {
        Style::default().fg(colors().highlight).bold()
    }

    /// Selection style (for selected items)
    #[must_use]
    pub fn selected() -> Style {
        Style::default()
            .bg(colors().selection)
            .fg(colors().text)
            .bold()
    }

    /// Border style (unfocused)
    #[must_use]
    pub fn border() -> Style {
        Style::default().fg(colors().border)
    }

    /// Border style (focused)
    #[must_use]
    pub fn border_focused() -> Style {
        Style::default().fg(colors().border_focused)
    }

    /// Status bar background style
    #[must_use]
    pub fn status_bar() -> Style {
        Style::default().bg(colors().background_alt)
    }

    /// Keyboard shortcut style
    #[must_use]
    pub fn shortcut_key() -> Style {
        Style::default().fg(colors().accent)
    }

    /// Shortcut description style
    #[must_use]
    pub fn shortcut_desc() -> Style {
        Style::default().fg(colors().text_muted)
    }

    /// Success style
    #[must_use]
    pub fn success() -> Style {
        Style::default().fg(colors().success)
    }

    /// Warning style
    #[must_use]
    pub fn warning() -> Style {
        Style::default().fg(colors().warning)
    }

    /// Error style
    #[must_use]
    pub fn error() -> Style {
        Style::default().fg(colors().error)
    }

    /// Added item style
    #[must_use]
    pub fn added() -> Style {
        Style::default().fg(colors().added)
    }

    /// Removed item style
    #[must_use]
    pub fn removed() -> Style {
        Style::default().fg(colors().removed)
    }

    /// Modified item style
    #[must_use]
    pub fn modified() -> Style {
        Style::default().fg(colors().modified)
    }

    /// Critical severity style
    #[must_use]
    pub fn critical() -> Style {
        Style::default().fg(colors().critical).bold()
    }

    /// High severity style
    #[must_use]
    pub fn high() -> Style {
        Style::default().fg(colors().high).bold()
    }

    /// Medium severity style
    #[must_use]
    pub fn medium() -> Style {
        Style::default().fg(colors().medium)
    }

    /// Low severity style
    #[must_use]
    pub fn low() -> Style {
        Style::default().fg(colors().low)
    }
}

// ============================================================================
// Badge Rendering Helpers
// ============================================================================

/// Render a status badge with consistent styling
#[must_use]
pub fn status_badge(status: &str) -> Span<'static> {
    let scheme = colors();
    let (label, color, symbol) = match status.to_lowercase().as_str() {
        "added" | "new" | "introduced" => ("ADDED", scheme.added, "+"),
        "removed" | "deleted" | "resolved" => ("REMOVED", scheme.removed, "-"),
        "modified" | "changed" | "updated" => ("MODIFIED", scheme.modified, "~"),
        _ => ("UNCHANGED", scheme.unchanged, "="),
    };

    Span::styled(
        format!(" {symbol} {label} "),
        Style::default()
            .fg(scheme.change_badge_fg())
            .bg(color)
            .bold(),
    )
}

/// Render a severity badge with consistent styling
#[must_use]
pub fn severity_badge(severity: &str) -> Span<'static> {
    let scheme = colors();
    let (label, bg_color, is_unknown) = match severity.to_lowercase().as_str() {
        "critical" => ("CRITICAL", scheme.critical, false),
        "high" => ("HIGH", scheme.high, false),
        "medium" | "moderate" => ("MEDIUM", scheme.medium, false),
        "low" => ("LOW", scheme.low, false),
        "info" | "informational" => ("INFO", scheme.info, false),
        "none" => ("NONE", scheme.muted, false),
        _ => ("UNKNOWN", scheme.muted, true),
    };
    let fg_color = scheme.severity_badge_fg(severity);

    let style = if is_unknown {
        Style::default().fg(fg_color).bg(bg_color).dim()
    } else {
        Style::default().fg(fg_color).bg(bg_color).bold()
    };

    Span::styled(format!(" {label} "), style)
}

/// Render a compact severity indicator (single char)
#[must_use]
pub fn severity_indicator(severity: &str) -> Span<'static> {
    let scheme = colors();
    let (symbol, bg_color, is_unknown) = match severity.to_lowercase().as_str() {
        "critical" => ("C", scheme.critical, false),
        "high" => ("H", scheme.high, false),
        "medium" | "moderate" => ("M", scheme.medium, false),
        "low" => ("L", scheme.low, false),
        "info" | "informational" => ("I", scheme.info, false),
        "none" => ("-", scheme.muted, false),
        _ => ("U", scheme.muted, true),
    };
    let fg_color = scheme.severity_badge_fg(severity);

    let style = if is_unknown {
        Style::default().fg(fg_color).bg(bg_color).dim()
    } else {
        Style::default().fg(fg_color).bg(bg_color).bold()
    };

    Span::styled(format!(" {symbol} "), style)
}

/// Render a count badge
#[must_use]
pub fn count_badge(count: usize, bg_color: Color) -> Span<'static> {
    let scheme = colors();
    Span::styled(
        format!(" {count} "),
        Style::default()
            .fg(scheme.badge_fg_dark)
            .bg(bg_color)
            .bold(),
    )
}

/// Render a filter/group badge showing current state
#[must_use]
pub fn filter_badge(label: &str, value: &str) -> Vec<Span<'static>> {
    let scheme = colors();
    vec![
        Span::styled(format!("{label}: "), Style::default().fg(scheme.text_muted)),
        Span::styled(
            format!(" {value} "),
            Style::default()
                .fg(scheme.badge_fg_dark)
                .bg(scheme.accent)
                .bold(),
        ),
    ]
}

// ============================================================================
// Mode Indicator
// ============================================================================

/// Render a mode indicator badge
#[must_use]
pub fn mode_badge(mode: &str) -> Span<'static> {
    let scheme = colors();
    let color = match mode.to_lowercase().as_str() {
        "diff" => scheme.modified,
        "view" => scheme.primary,
        "multi-diff" | "multidiff" => scheme.added,
        "timeline" => scheme.secondary,
        "matrix" => scheme.high,
        _ => scheme.muted,
    };

    Span::styled(
        format!(" {} ", mode.to_uppercase()),
        Style::default().fg(scheme.badge_fg_dark).bg(color).bold(),
    )
}

// ============================================================================
// Footer Hints
// ============================================================================

/// Tab-specific footer hints
pub struct FooterHints;

impl FooterHints {
    /// Get hints for a specific tab in diff mode
    #[must_use]
    pub fn for_diff_tab(tab: &str) -> Vec<(&'static str, &'static str)> {
        let mut hints = Self::global();

        match tab.to_lowercase().as_str() {
            "components" => {
                hints.insert(0, ("f", "filter"));
                hints.insert(1, ("s", "sort"));
            }
            "dependencies" => {
                hints.insert(0, ("f", "filter"));
                hints.insert(1, ("t", "transitive"));
                hints.insert(2, ("h", "highlight"));
                hints.insert(3, ("Enter", "expand"));
                hints.insert(4, ("c", "component"));
            }
            "licenses" => {
                hints.insert(0, ("g", "group"));
                hints.insert(1, ("s", "sort"));
                hints.insert(2, ("r", "risk"));
                hints.insert(3, ("c", "compat"));
                hints.insert(4, ("Tab", "panel"));
            }
            "vulnerabilities" | "vulns" => {
                hints.insert(0, ("f", "filter"));
                hints.insert(1, ("s", "sort"));
                hints.insert(2, ("g", "group"));
            }
            "sidebyside" | "side-by-side" | "diff" => {
                hints.insert(0, ("←→/p", "panel"));
                hints.insert(1, ("J/K", "scroll both"));
            }
            "quality" => {
                hints.insert(0, ("v", "view"));
            }
            "compliance" => {
                hints.insert(0, ("←→", "standard"));
                hints.insert(1, ("v", "view"));
                hints.insert(2, ("g", "group"));
                hints.insert(3, ("↑↓", "select"));
            }
            "source" => {
                hints.insert(0, ("w", "panel"));
                hints.insert(1, ("v", "tree/raw"));
                hints.insert(2, ("↑↓", "scroll"));
            }
            "graphchanges" | "graph" => {
                hints.insert(0, ("↑↓", "select"));
                hints.insert(1, ("PgUp/Dn", "page"));
            }
            _ => {}
        }

        hints
    }

    /// Get hints for a specific tab in view mode
    #[must_use]
    pub fn for_view_tab(tab: &str) -> Vec<(&'static str, &'static str)> {
        let mut hints = Self::global();

        match tab.to_lowercase().as_str() {
            "tree" | "components" => {
                // g/f/search already shown in filter bar at top
                hints.insert(0, ("p", "panel"));
                hints.insert(1, ("Enter", "select"));
                hints.insert(2, ("1-4", "detail tabs"));
            }
            "vulnerabilities" | "vulns" => {
                hints.insert(0, ("f", "filter"));
                hints.insert(1, ("s", "sort"));
                hints.insert(2, ("g", "group"));
                hints.insert(3, ("d", "dedup"));
                hints.insert(4, ("Enter", "component"));
            }
            "licenses" => {
                hints.insert(0, ("g", "group"));
                hints.insert(1, ("Enter", "inspect"));
                hints.insert(2, ("K/J", "scroll"));
            }
            "dependencies" => {
                hints.insert(0, ("Enter", "expand/inspect"));
                hints.insert(1, ("←", "collapse"));
                hints.insert(2, ("p", "panel"));
                hints.insert(3, ("J/K", "scroll"));
            }
            "quality" => {
                hints.insert(0, ("v", "view"));
            }
            "compliance" => {
                hints.insert(0, ("f", "filter"));
                hints.insert(1, ("←→", "standard"));
                hints.insert(2, ("↑↓", "select"));
            }
            "source" => {
                hints.insert(0, ("v", "tree/raw"));
                hints.insert(1, ("p", "panel"));
                hints.insert(2, ("H/L", "fold all"));
                hints.insert(3, ("Enter", "select"));
            }
            _ => {}
        }

        hints
    }

    /// Global hints (always shown)
    #[must_use]
    pub fn global() -> Vec<(&'static str, &'static str)> {
        vec![
            ("Tab", "switch"),
            ("/", "search"),
            ("e", "export"),
            ("?", "help"),
            ("q", "quit"),
        ]
    }

    /// Number of global hints (used to insert separator).
    pub const GLOBAL_COUNT: usize = 5;
}

/// Render footer hints as spans with badge-style keys.
///
/// If the hint list contains more items than `FooterHints::GLOBAL_COUNT`,
/// a `│` separator is inserted between tab-specific and global hints.
#[must_use]
pub fn render_footer_hints(hints: &[(&str, &str)]) -> Vec<Span<'static>> {
    let scheme = colors();
    let mut spans = Vec::new();
    let tab_count = hints.len().saturating_sub(FooterHints::GLOBAL_COUNT);

    for (i, (key, desc)) in hints.iter().enumerate() {
        if i > 0 {
            spans.push(Span::raw(" "));
        }
        // Insert separator between tab-specific and global hints
        if i == tab_count && tab_count > 0 {
            spans.push(Span::styled("│ ", Style::default().fg(scheme.muted)));
        }
        spans.push(Span::styled(
            format!(" {key} "),
            Style::default()
                .fg(scheme.badge_fg_dark)
                .bg(scheme.accent)
                .bold(),
        ));
        spans.push(Span::styled(
            desc.to_string(),
            Style::default().fg(scheme.text_muted),
        ));
    }

    spans
}
