1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
use std::collections::{HashMap, HashSet};

use ratatui::{
    layout::{Constraint, Layout, Rect},
    style::{Color, Style},
    text::Line,
    widgets::{Block, BorderType, List, ListDirection, Row, Table},
    Frame,
};

use crate::{app::App, update::message::Message};

pub(super) fn render_footer(app: &App, area: Rect, f: &mut Frame) {
    // Footer Layout (Console & Help)
    let [left, right] = Layout::horizontal(Constraint::from_percentages([50, 50])).areas(area);

    // Console Section
    let console = draw_console(app);
    let mut console_state = app.console_state().borrow_mut();
    f.render_stateful_widget(console, left, &mut console_state);

    // Help Menu
    let help_menu = build_help_table(app);
    f.render_widget(help_menu, right);
}

/// Draws the console menu component
fn draw_console(app: &App) -> List {
    let items = app.console().to_owned();
    List::new(items)
        .block(Block::bordered().title("Console"))
        .style(Style::default().fg(Color::White))
        .highlight_symbol(">>")
        .repeat_highlight_symbol(true)
        .direction(ListDirection::TopToBottom)
}

/// Draws the help menu component
fn build_help_table(app: &App) -> Table {
    let key_style = Style::default().fg(Color::LightCyan);
    let message_style = Style::default().fg(Color::Gray);

    let keymaps = app.config().keymap();
    let mut combined_keymaps = combine_keys_by_value(keymaps);
    combined_keymaps.sort_unstable_by_key(|(_, message)| *message);

    let longest_string = longest_combined_keymap(&combined_keymaps);
    let widths = [Constraint::Length(longest_string), Constraint::Min(10)];

    let keymap_rows = combined_keymaps.iter().map(|(keybinds, message)| {
        Row::new([
            Line::styled(keybinds.to_owned(), key_style),
            Line::styled(message.to_string(), message_style),
        ])
    });

    Table::new(keymap_rows, widths).block(
        Block::bordered()
            .border_type(BorderType::Plain)
            .title("Help"),
    )
}

fn longest_combined_keymap(combined_keymaps: &Vec<(String, &Message)>) -> u16 {
    combined_keymaps
        .iter()
        .map(|(keys, _)| keys.len().try_into().unwrap())
        .max()
        .unwrap()
}

fn combine_keys_by_value(map: &HashMap<String, Message>) -> Vec<(String, &Message)> {
    let mut result = Vec::new();
    let mut processed_messages = HashSet::new();

    for (_, message) in map.iter() {
        if !processed_messages.contains(message) {
            let combined_keys = map
                .into_iter()
                .filter(|(_, m)| *m == message)
                .enumerate()
                .map(|(i, (k, _))| {
                    if i == 0 {
                        k.to_owned().to_uppercase()
                    } else {
                        format!(" | {}", k.to_uppercase())
                    }
                })
                .collect::<String>();
            result.push((combined_keys, message));
            processed_messages.insert(message);
        }
    }

    result
}