//! Centered modal listing keybindings for the current screen.

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::Screen;

/// Render a centered help overlay listing keybindings for the current screen.
///
/// The overlay is a bordered modal that lists all commands from the
/// registry that are available on the current screen.
#[allow(clippy::too_many_arguments)]
pub fn render_help_overlay(
    frame: &mut Frame<'_>,
    area: Rect,
    registry: &CommandRegistry,
    screen: &Screen,
    border_color: PackedRgba,
    text_color: PackedRgba,
    muted_color: PackedRgba,
    scroll_offset: usize,
) {
    if area.height < 5 || area.width < 20 {
        return;
    }

    // Overlay dimensions: 60% of screen, capped.
    let overlay_width = (area.width * 3 / 5).clamp(30, 70);
    let overlay_height = (area.height * 3 / 5).clamp(8, 30);

    let overlay_x = area.x + (area.width.saturating_sub(overlay_width)) / 2;
    let overlay_y = area.y + (area.height.saturating_sub(overlay_height)) / 2;
    let overlay_rect = Rect::new(overlay_x, overlay_y, overlay_width, overlay_height);

    // Draw border.
    let border_cell = Cell {
        fg: border_color,
        ..Cell::default()
    };
    frame.draw_border(
        overlay_rect,
        ftui::render::drawing::BorderChars::ROUNDED,
        border_cell,
    );

    // Title.
    let title = " Help (? to close) ";
    let title_x = overlay_x + (overlay_width.saturating_sub(title.len() as u16)) / 2;
    let title_cell = Cell {
        fg: border_color,
        ..Cell::default()
    };
    frame.print_text_clipped(title_x, overlay_y, title, title_cell, overlay_rect.right());

    // Inner content area (inside border).
    let inner = Rect::new(
        overlay_x + 2,
        overlay_y + 1,
        overlay_width.saturating_sub(4),
        overlay_height.saturating_sub(2),
    );

    // Get commands for this screen.
    let commands = registry.help_entries(screen);
    let visible_lines = inner.height as usize;

    let key_cell = Cell {
        fg: text_color,
        ..Cell::default()
    };
    let desc_cell = Cell {
        fg: muted_color,
        ..Cell::default()
    };

    for (i, cmd) in commands.iter().skip(scroll_offset).enumerate() {
        if i >= visible_lines {
            break;
        }
        let y = inner.y + i as u16;

        // Key binding label (left).
        let key_label = cmd
            .keybinding
            .as_ref()
            .map_or_else(String::new, |kb| kb.display());
        let label_end = frame.print_text_clipped(inner.x, y, &key_label, key_cell, inner.right());

        // Spacer + description (right).
        let desc_x = label_end.saturating_add(2);
        if desc_x < inner.right() {
            frame.print_text_clipped(desc_x, y, cmd.help_text, desc_cell, inner.right());
        }
    }

    // Scroll indicator if needed.
    if commands.len() > visible_lines + scroll_offset {
        let indicator = format!("({}/{})", scroll_offset + visible_lines, commands.len());
        let ind_x = inner.right().saturating_sub(indicator.len() as u16);
        let ind_y = overlay_rect.bottom().saturating_sub(1);
        frame.print_text_clipped(ind_x, ind_y, &indicator, desc_cell, overlay_rect.right());
    }
}

#[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_help_overlay_renders_border() {
        with_frame!(80, 24, |frame| {
            let registry = build_registry();
            render_help_overlay(
                &mut frame,
                Rect::new(0, 0, 80, 24),
                &registry,
                &Screen::Dashboard,
                gray(),
                white(),
                gray(),
                0,
            );

            // The overlay should have non-empty cells in the center area.
            let has_content = (20..60u16).any(|x| {
                (8..16u16).any(|y| {
                    let cell = frame.buffer.get(x, y).unwrap();
                    !cell.is_empty()
                })
            });
            assert!(has_content, "Expected help overlay in center area");
        });
    }

    #[test]
    fn test_help_overlay_tiny_terminal_noop() {
        with_frame!(15, 4, |frame| {
            let registry = build_registry();
            render_help_overlay(
                &mut frame,
                Rect::new(0, 0, 15, 4),
                &registry,
                &Screen::Dashboard,
                gray(),
                white(),
                gray(),
                0,
            );
        });
    }
}
