haj 0.2.1

fast, quiet, beautiful package managemer and tui for Arch Linux
use super::{App, InputMode, PackageFilter};
use ratatui::{
    Frame,
    layout::{Alignment, Constraint, Direction, Layout},
    style::{Color, Modifier, Style},
    text::{Line, Span},
    widgets::{Block, Borders, List, ListItem, Paragraph, Wrap},
};

pub fn render(f: &mut Frame, app: &mut App) {
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .margin(1)
        .constraints([Constraint::Length(3), Constraint::Min(0)].as_ref())
        .split(f.area());

    let (border_color, cursor) = match app.input_mode {
        InputMode::Editing => (Color::Cyan, ""),
        InputMode::Normal => (Color::DarkGray, ""),
    };

    let filter_display = match app.filter {
        PackageFilter::All => "all",
        PackageFilter::Installed => "installed",
        PackageFilter::NotInstalled => "not installed",
    };

    let search_display = format!(" search (/): {}{} ", app.search_query, cursor);
    let search_bar = Paragraph::new(search_display)
        .style(Style::default().fg(border_color))
        .block(
            Block::default()
                .borders(Borders::ALL)
                .border_style(Style::default().fg(border_color))
                .title_bottom(format!(" [filter: {}] (tab) ", filter_display))
                .title_alignment(Alignment::Right),
        );
    f.render_widget(search_bar, chunks[0]);

    let content_chunks = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([Constraint::Percentage(30), Constraint::Percentage(70)].as_ref())
        .split(chunks[1]);

    let items: Vec<ListItem> = app
        .filtered_packages
        .iter()
        .map(|pkg| {
            let (icon, color) = if pkg.is_installed {
                ("", Color::Green)
            } else {
                (" ", Color::White)
            };

            ListItem::new(Line::from(vec![
                Span::styled(
                    format!("{} ", icon),
                    Style::default().fg(color).add_modifier(Modifier::BOLD),
                ),
                Span::styled(pkg.name.clone(), Style::default().fg(color)),
            ]))
        })
        .collect();

    let list_title = format!(" packages ({}) ", app.filtered_packages.len());

    let list = List::new(items)
        .block(Block::default().borders(Borders::ALL).title(list_title))
        .highlight_style(
            Style::default()
                .fg(Color::Black)
                .bg(Color::Cyan)
                .add_modifier(Modifier::BOLD),
        )
        .highlight_symbol(">> ");

    f.render_stateful_widget(list, content_chunks[0], &mut app.list_state);

    if let Some(selected_idx) = app.list_state.selected() {
        if let Some(selected_pkg) = app.filtered_packages.get(selected_idx) {
            let details_text = vec![
                Line::from(vec![
                    Span::styled(
                        selected_pkg.name.clone(),
                        Style::default()
                            .fg(Color::Cyan)
                            .add_modifier(Modifier::BOLD),
                    ),
                    Span::raw(format!(" v{}", selected_pkg.version)),
                ]),
                Line::from(""),
                Line::from(format!("repository: {}", selected_pkg.repo)),
                Line::from(""),
                Line::from(Span::styled(
                    "description:",
                    Style::default().fg(Color::DarkGray),
                )),
                Line::from(selected_pkg.desc.clone()),
                Line::from(""),
                Line::from(Span::styled(
                    "[i] install  [r] remove  [u] update",
                    Style::default().fg(Color::DarkGray),
                )),
            ];

            let details = Paragraph::new(details_text)
                .block(
                    Block::default()
                        .borders(Borders::ALL)
                        .title(" details ")
                        .title_bottom(" j/k:nav gg/G:jump f:search x:del esc:back q:quit ")
                        .title_alignment(Alignment::Right),
                )
                .wrap(Wrap { trim: true });

            f.render_widget(details, content_chunks[1]);
        }
    } else {
        let empty_state = Paragraph::new("no packages found.")
            .block(Block::default().borders(Borders::ALL).title(" details "))
            .style(Style::default().fg(Color::DarkGray));
        f.render_widget(empty_state, content_chunks[1]);
    }
}