speedtest-tui 0.1.1

A terminal-based network speed test tool with real-time gauges and graphs
use ratatui::{
    layout::{Constraint, Direction, Layout, Rect},
    prelude::*,
    widgets::{Block, Borders, List, ListItem, Paragraph, Row, Table},
    Frame,
};

use super::Theme;
use crate::app::App;

/// Render the diagnostics view
pub fn render(frame: &mut Frame, area: Rect, app: &App, theme: &Theme) {
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(6), // Connection info
            Constraint::Length(5), // DNS info
            Constraint::Min(8),    // Interfaces
        ])
        .split(area);

    render_connection_info(frame, chunks[0], app, theme);
    render_dns_info(frame, chunks[1], app, theme);
    render_interfaces(frame, chunks[2], app, theme);
}

fn render_connection_info(frame: &mut Frame, area: Rect, app: &App, theme: &Theme) {
    let block = Block::default()
        .title(" Connection Info ")
        .title_style(Style::default().fg(theme.primary))
        .borders(Borders::ALL)
        .border_style(Style::default().fg(theme.border))
        .style(Style::default().bg(theme.background));

    let inner = block.inner(area);
    frame.render_widget(block, area);

    let info = if let Some(ref conn) = app.connection_info {
        vec![
            Line::from(vec![
                Span::styled("  Public IP:  ", Style::default().fg(theme.muted)),
                Span::styled(&conn.ip, Style::default().fg(theme.foreground)),
            ]),
            Line::from(vec![
                Span::styled("  ISP:        ", Style::default().fg(theme.muted)),
                Span::styled(
                    conn.isp.as_deref().unwrap_or("Unknown"),
                    Style::default().fg(theme.foreground),
                ),
            ]),
            Line::from(vec![
                Span::styled("  Location:   ", Style::default().fg(theme.muted)),
                Span::styled(
                    conn.location.as_deref().unwrap_or("Unknown"),
                    Style::default().fg(theme.foreground),
                ),
            ]),
        ]
    } else {
        vec![Line::from(vec![Span::styled(
            "  Loading connection info...",
            Style::default().fg(theme.muted),
        )])]
    };

    let paragraph = Paragraph::new(info);
    frame.render_widget(paragraph, inner);
}

fn render_dns_info(frame: &mut Frame, area: Rect, app: &App, theme: &Theme) {
    let block = Block::default()
        .title(" DNS Resolution ")
        .title_style(Style::default().fg(theme.primary))
        .borders(Borders::ALL)
        .border_style(Style::default().fg(theme.border))
        .style(Style::default().bg(theme.background));

    let inner = block.inner(area);
    frame.render_widget(block, area);

    let info = if let Some(ref dns) = app.dns_result {
        vec![
            Line::from(vec![
                Span::styled("  Domain:         ", Style::default().fg(theme.muted)),
                Span::styled(&dns.domain, Style::default().fg(theme.foreground)),
            ]),
            Line::from(vec![
                Span::styled("  Resolution Time:", Style::default().fg(theme.muted)),
                Span::styled(
                    format!(" {:.2} ms", dns.resolution_time_ms),
                    Style::default().fg(theme.success),
                ),
            ]),
        ]
    } else {
        vec![Line::from(vec![Span::styled(
            "  Press 'r' to run DNS test",
            Style::default().fg(theme.muted),
        )])]
    };

    let paragraph = Paragraph::new(info);
    frame.render_widget(paragraph, inner);
}

fn render_interfaces(frame: &mut Frame, area: Rect, app: &App, theme: &Theme) {
    let block = Block::default()
        .title(" Network Interfaces ")
        .title_style(Style::default().fg(theme.primary))
        .borders(Borders::ALL)
        .border_style(Style::default().fg(theme.border))
        .style(Style::default().bg(theme.background));

    let inner = block.inner(area);
    frame.render_widget(block, area);

    if app.interfaces.is_empty() {
        let placeholder =
            Paragraph::new("  Loading interfaces...").style(Style::default().fg(theme.muted));
        frame.render_widget(placeholder, inner);
        return;
    }

    let header = Row::new(vec!["Name", "IP Address", "Status", "MAC"])
        .style(Style::default().fg(theme.primary).bold())
        .bottom_margin(1);

    let rows: Vec<Row> = app
        .interfaces
        .iter()
        .map(|iface| {
            let row_style = if iface.is_up {
                Style::default().fg(theme.foreground)
            } else {
                Style::default().fg(theme.muted)
            };

            Row::new(vec![
                iface.name.clone(),
                iface.ip.clone(),
                if iface.is_up { "UP" } else { "DOWN" }.to_string(),
                iface.mac.clone().unwrap_or_else(|| "-".to_string()),
            ])
            .style(row_style)
        })
        .collect();

    let table = Table::new(
        rows,
        [
            Constraint::Percentage(20),
            Constraint::Percentage(30),
            Constraint::Percentage(15),
            Constraint::Percentage(35),
        ],
    )
    .header(header);

    frame.render_widget(table, inner);
}

#[allow(dead_code)]
pub fn render_traceroute(frame: &mut Frame, area: Rect, app: &App, theme: &Theme) {
    let block = Block::default()
        .title(" Traceroute ")
        .title_style(Style::default().fg(theme.primary))
        .borders(Borders::ALL)
        .border_style(Style::default().fg(theme.border))
        .style(Style::default().bg(theme.background));

    let inner = block.inner(area);
    frame.render_widget(block, area);

    if app.traceroute_hops.is_empty() {
        let placeholder = Paragraph::new("  No traceroute data. Press 't' to trace.")
            .style(Style::default().fg(theme.muted));
        frame.render_widget(placeholder, inner);
        return;
    }

    let items: Vec<ListItem> = app
        .traceroute_hops
        .iter()
        .map(|hop| {
            let text = if let Some(ref addr) = hop.address {
                format!(
                    "{:>2}. {:>15}  {:.2} ms",
                    hop.hop_number, addr, hop.latency_ms
                )
            } else {
                format!("{:>2}. *  Request timed out", hop.hop_number)
            };

            ListItem::new(text).style(Style::default().fg(theme.foreground))
        })
        .collect();

    let list = List::new(items);
    frame.render_widget(list, inner);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_module_compiles() {
        assert!(true);
    }
}