seamless-glance 1.0.0

Fast, read-only AWS TUI for cloud infrastructure visibility and triage
use crate::{
    app::App,
    models::finding::{FindingCategory, FindingSeverity},
};
use ratatui::{
    layout::{Constraint, Direction, Layout, Rect},
    style::{Modifier, Style},
    widgets::{Block, Borders, Cell, Paragraph, Row, Table, Wrap},
    Frame,
};

pub fn render(frame: &mut Frame, area: Rect, app: &mut App) {
    let total_rows = app.findings.len();
    if total_rows == 0 {
        app.selected_row = 0;
        app.scroll_offset = 0;

        let empty = Paragraph::new(
            "No findings detected right now.\n\
             This view will surface incidents, waste, and hygiene issues as they appear.",
        )
        .style(Style::default().fg(app.theme.text))
        .block(
            Block::default()
                .title("Findings")
                .borders(Borders::ALL)
                .border_style(Style::default().fg(app.theme.primary)),
        );

        frame.render_widget(empty, area);
        return;
    }

    app.selected_row = app.selected_row.min(total_rows - 1);

    if app.wrap_mode_active() {
        render_wrapped_detail(frame, area, app);
        return;
    }

    let visible_height = area.height.saturating_sub(3) as usize;

    if app.selected_row < app.scroll_offset as usize {
        app.scroll_offset = app.selected_row as u16;
    } else if app.selected_row >= app.scroll_offset as usize + visible_height {
        app.scroll_offset = (app.selected_row + 1 - visible_height) as u16;
    }

    let rows: Vec<Row> = app
        .findings
        .iter()
        .enumerate()
        .skip(app.scroll_offset as usize)
        .take(visible_height)
        .map(|(i, finding)| {
            let severity_style = match finding.severity {
                FindingSeverity::High => Style::default().fg(app.theme.primary),
                FindingSeverity::Medium => Style::default().fg(app.theme.accent),
            };

            let style = if i == app.selected_row {
                severity_style.add_modifier(Modifier::BOLD)
            } else {
                severity_style
            };

            let category = match finding.category {
                FindingCategory::Incident => "Incident",
                FindingCategory::Waste => "Waste",
                FindingCategory::Hygiene => "Hygiene",
            };

            Row::new(vec![
                Cell::from(finding.severity.as_str()),
                Cell::from(category),
                Cell::from(finding.service.clone()),
                Cell::from(finding.region.clone()),
                Cell::from(finding.summary.clone()),
                Cell::from(finding.next_step.clone()),
            ])
            .style(style)
        })
        .collect();

    let table = Table::new(
        rows,
        [
            ratatui::layout::Constraint::Length(6),
            ratatui::layout::Constraint::Length(10),
            ratatui::layout::Constraint::Length(16),
            ratatui::layout::Constraint::Length(12),
            ratatui::layout::Constraint::Percentage(38),
            ratatui::layout::Constraint::Percentage(34),
        ],
    )
    .header(
        Row::new([
            "SEV",
            "CATEGORY",
            "SERVICE",
            "REGION",
            "SUMMARY",
            "NEXT STEP",
        ])
        .style(
            Style::default()
                .fg(app.theme.accent)
                .add_modifier(Modifier::BOLD),
        ),
    )
    .block(
        Block::default()
            .title("Findings")
            .borders(Borders::ALL)
            .border_style(Style::default().fg(app.theme.primary)),
    );

    frame.render_widget(table, area);
}

fn render_wrapped_detail(frame: &mut Frame, area: Rect, app: &mut App) {
    let finding = &app.findings[app.selected_row];
    let layout = Layout::default()
        .direction(Direction::Vertical)
        .constraints([Constraint::Length(5), Constraint::Min(0)])
        .split(area);

    let metadata = Paragraph::new(format!(
        "Finding {}/{}\n{}  |  {}  |  {}  |  {}",
        app.selected_row + 1,
        app.findings.len(),
        finding.severity.as_str(),
        finding.category.as_str(),
        finding.service,
        finding.region
    ))
    .style(Style::default().fg(app.theme.text))
    .wrap(Wrap { trim: true })
    .block(
        Block::default()
            .title("Findings Detail")
            .borders(Borders::ALL)
            .border_style(Style::default().fg(app.theme.primary)),
    );

    frame.render_widget(metadata, layout[0]);

    let detail = Paragraph::new(format!(
        "Summary\n{}\n\nNext Step\n{}",
        finding.summary, finding.next_step
    ))
    .style(Style::default().fg(app.theme.text))
    .wrap(Wrap { trim: true })
    .scroll((app.detail_scroll_offset, 0))
    .block(
        Block::default()
            .title("Wrapped Detail")
            .borders(Borders::ALL)
            .border_style(Style::default().fg(app.theme.primary)),
    );

    frame.render_widget(detail, layout[1]);
}