//! Bottom status bar with key hints and mode indicator.

use ftui::core::geometry::Rect;
use ftui::render::cell::{Cell, PackedRgba};
use ftui::render::drawing::Draw;
use ftui::render::frame::Frame;

use crate::commands::CommandRegistry;
use crate::message::{InputMode, Screen};

/// Render the bottom status bar with key hints and mode indicator.
///
/// Layout: `[mode] ─── [key hints]`
///
/// Key hints are sourced from the [`CommandRegistry`] filtered to the
/// current screen, showing only the most important bindings.
#[allow(clippy::too_many_arguments)]
pub fn render_status_bar(
    frame: &mut Frame<'_>,
    area: Rect,
    registry: &CommandRegistry,
    screen: &Screen,
    mode: &InputMode,
    bar_bg: PackedRgba,
    text_color: PackedRgba,
    accent_color: PackedRgba,
) {
    if area.height == 0 || area.width < 5 {
        return;
    }

    // Fill the bar background.
    let bg_cell = Cell {
        bg: bar_bg,
        ..Cell::default()
    };
    frame.draw_rect_filled(area, bg_cell);

    let mode_label = match mode {
        InputMode::Normal => "NORMAL",
        InputMode::Text => "INPUT",
        InputMode::Palette => "PALETTE",
        InputMode::GoPrefix { .. } => "g...",
    };

    // Left side: mode indicator.
    let mode_cell = Cell {
        fg: accent_color,
        bg: bar_bg,
        ..Cell::default()
    };
    let mut x = frame.print_text_clipped(
        area.x.saturating_add(1),
        area.y,
        mode_label,
        mode_cell,
        area.right(),
    );

    // Spacer.
    x = x.saturating_add(2);

    // Right side: key hints from registry (formatted as "key:action").
    let hints = registry.status_hints(screen);
    let hint_cell = Cell {
        fg: text_color,
        bg: bar_bg,
        ..Cell::default()
    };
    let key_cell = Cell {
        fg: accent_color,
        bg: bar_bg,
        ..Cell::default()
    };

    for hint in &hints {
        if x >= area.right().saturating_sub(1) {
            break;
        }
        // Split "q:quit" into key part and description part.
        if let Some((key_part, desc_part)) = hint.split_once(':') {
            x = frame.print_text_clipped(x, area.y, key_part, key_cell, area.right());
            x = frame.print_text_clipped(x, area.y, ":", hint_cell, area.right());
            x = frame.print_text_clipped(x, area.y, desc_part, hint_cell, area.right());
        } else {
            x = frame.print_text_clipped(x, area.y, hint, hint_cell, area.right());
        }
        x = x.saturating_add(2);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::commands::build_registry;
    use crate::message::Screen;
    use ftui::render::grapheme_pool::GraphemePool;

    macro_rules! with_frame {
        ($width:expr, $height:expr, |$frame:ident| $body:block) => {{
            let mut pool = GraphemePool::new();
            let mut $frame = Frame::new($width, $height, &mut pool);
            $body
        }};
    }

    fn white() -> PackedRgba {
        PackedRgba::rgb(0xFF, 0xFF, 0xFF)
    }

    fn gray() -> PackedRgba {
        PackedRgba::rgb(0x80, 0x80, 0x80)
    }

    #[test]
    fn test_status_bar_renders_mode() {
        with_frame!(80, 1, |frame| {
            let registry = build_registry();
            render_status_bar(
                &mut frame,
                Rect::new(0, 0, 80, 1),
                &registry,
                &Screen::Dashboard,
                &InputMode::Normal,
                gray(),
                white(),
                white(),
            );

            let n_cell = frame.buffer.get(1, 0).unwrap();
            assert_eq!(n_cell.content.as_char(), Some('N'));
        });
    }

    #[test]
    fn test_status_bar_text_mode() {
        with_frame!(80, 1, |frame| {
            let registry = build_registry();
            render_status_bar(
                &mut frame,
                Rect::new(0, 0, 80, 1),
                &registry,
                &Screen::Search,
                &InputMode::Text,
                gray(),
                white(),
                white(),
            );

            let i_cell = frame.buffer.get(1, 0).unwrap();
            assert_eq!(i_cell.content.as_char(), Some('I'));
        });
    }

    #[test]
    fn test_status_bar_narrow_terminal() {
        with_frame!(4, 1, |frame| {
            let registry = build_registry();
            render_status_bar(
                &mut frame,
                Rect::new(0, 0, 4, 1),
                &registry,
                &Screen::Dashboard,
                &InputMode::Normal,
                gray(),
                white(),
                white(),
            );
            let cell = frame.buffer.get(0, 0).unwrap();
            assert!(cell.is_empty());
        });
    }
}
