use crate::app::AppState;
use crate::ui::safe_viewport::SafeViewport;
use ratatui::prelude::*;
use ratatui::style::Modifier;
use ratatui::text::{Line, Span};
use ratatui::widgets::*;

// === 4RUNR BRAND COLORS ===
const BRAND_PURPLE: Color = Color::Rgb(138, 43, 226);
const BRAND_VIOLET: Color = Color::Rgb(148, 103, 189);
const CYBER_CYAN: Color = Color::Rgb(0, 255, 255);
const NEON_GREEN: Color = Color::Rgb(57, 255, 20);
const AMBER_WARN: Color = Color::Rgb(255, 191, 0);
const TEXT_PRIMARY: Color = Color::Rgb(230, 230, 240);
const TEXT_DIM: Color = Color::Rgb(100, 100, 120);
const TEXT_MUTED: Color = Color::Rgb(60, 60, 80);
#[allow(dead_code)]
const BG_PANEL: Color = Color::Rgb(18, 18, 25);

// === ANIMATION CONSTANTS ===
const SPINNERS: [&str; 8] = ["⣾", "⣽", "⣻", "⢿", "⡿", "⣟", "⣯", "⣷"];
// NOTE: PULSE removed - we use static dots (*, +, -) for status indicators
// to prevent flashing when typing. Instructions: "DON'T use animated pulse for status dots!"

const MIN_COLS: u16 = 80;
const MIN_ROWS: u16 = 24;

/// Render a horizontal separator line that stops before right edge
fn render_separator(f: &mut Frame, area: Rect) {
    // Stop separator at 85% of terminal width (safe zone)
    let safe_width = (area.width * 85 / 100).min(area.width.saturating_sub(10));

    if safe_width > 0 {
        let separator_line = "─".repeat(safe_width as usize);
        f.render_widget(
            Paragraph::new(separator_line).style(Style::default().fg(TEXT_DIM)),
            Rect {
                x: area.x,
                y: area.y,
                width: safe_width,
                height: 1,
            },
        );
    }
}

pub fn render(f: &mut Frame, state: &AppState) {
    // CRITICAL: Hide cursor by default at start of each render
    // Only show it when explicitly set in render_command_box
    // This prevents cursor from appearing in wrong places (like operations log)
    let full_area = f.size();
    f.render_widget(Clear, full_area);

    let viewport = SafeViewport::new(full_area);

    if viewport.is_too_small(MIN_COLS, MIN_ROWS) {
        render_too_small(f, &viewport);
        return;
    }

    let safe = viewport.safe_rect;

    // Dark background
    f.render_widget(
        Block::default().style(Style::default().bg(Color::Rgb(10, 10, 15))),
        full_area,
    );

    // Main layout: Header (3) + Content (flex) + Command (4)
    let main_chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Length(3), // Header
            Constraint::Min(15),   // Content
            Constraint::Length(4), // Command bar
        ])
        .split(safe);

    render_header(f, main_chunks[0], state);

    // === ADD SEPARATOR BELOW HEADER ===
    if main_chunks[1].y > main_chunks[0].y + main_chunks[0].height {
        render_separator(
            f,
            Rect {
                x: safe.x,
                y: main_chunks[0].y + main_chunks[0].height,
                width: safe.width,
                height: 1,
            },
        );
    }

    render_content(f, main_chunks[1], state);

    // === ADD SEPARATOR ABOVE COMMAND BOX ===
    if main_chunks[2].y > main_chunks[1].y + main_chunks[1].height {
        render_separator(
            f,
            Rect {
                x: safe.x,
                y: main_chunks[1].y + main_chunks[1].height,
                width: safe.width,
                height: 1,
            },
        );
    }

    render_command_box(f, main_chunks[2], state);

    // Perf overlay (if enabled)
    if state.perf_overlay {
        render_perf_overlay(f, full_area, state);
    }
}

fn render_header(f: &mut Frame, area: Rect, state: &AppState) {
    // Bug 2 fix: Ensure 15% margin from right edge (use 85% of width max)
    let max_width = (area.width * 85 / 100).max(10); // At least 10 chars, max 85% of width
    let header_area = Rect {
        x: area.x + 2,
        y: area.y,
        width: max_width.saturating_sub(2), // Additional 2 char margin
        height: 3,
    };

    let spinner = SPINNERS[state.spinner_frame];

    // Format uptime
    let uptime_str = format_uptime(state.uptime_secs);

    // Operation mode indicator (Step 7)
    let mode_text = state.operation_mode.as_str();
    let mode_color = match state.operation_mode {
        crate::app::OperationMode::Local => AMBER_WARN,
        crate::app::OperationMode::Connected => NEON_GREEN,
    };

    // Connection status icon - Phase 1.1: Connection Visibility
    let connection_icon = if state.gateway_healthy && state.connected {
        "[●]" // Green dot - verified & healthy
    } else if state.connected {
        "[○]" // Yellow - connected but not verified
    } else {
        "[ ]" // Gray - not connected
    };

    let connection_color = if state.gateway_healthy && state.connected {
        NEON_GREEN
    } else if state.connected {
        AMBER_WARN
    } else {
        TEXT_MUTED
    };

    // Line 1: Brand + version + mode + uptime - Bug 3 fix: Use "4Runr." with dot (matches brand logo)
    // Version from env 4RUNR_CLI_VERSION (set by Node CLI at launch); fallback for dev without CLI
    let ver_env = std::env::var("4RUNR_CLI_VERSION").unwrap_or_else(|_| "2.9.69".to_string());
    let package_version = ver_env.trim();
    let package_version: &str = if package_version.is_empty() {
        "2.9.69"
    } else {
        package_version
    };
    let brand_line = Line::from(vec![
        Span::styled(
            "4Runr.",
            Style::default()
                .fg(BRAND_PURPLE)
                .add_modifier(Modifier::BOLD),
        ),
        Span::styled(" AI AGENT OS", Style::default().fg(BRAND_VIOLET)),
        Span::styled(
            format!(" v{}", package_version),
            Style::default().fg(TEXT_MUTED),
        ),
        Span::styled("    Mode: ", Style::default().fg(TEXT_MUTED)),
        Span::styled(
            mode_text,
            Style::default().fg(mode_color).add_modifier(Modifier::BOLD),
        ),
        Span::styled(" ", Style::default()),
        Span::styled(
            connection_icon,
            Style::default()
                .fg(connection_color)
                .add_modifier(Modifier::BOLD),
        ),
        Span::styled(
            format!("    {} UPTIME: {}", spinner, uptime_str),
            Style::default().fg(TEXT_MUTED),
        ),
    ]);

    // Line 2: Status bar with Gateway URL - Phase 1.1: Connection Visibility
    // NO long lines that touch right edge (causes scrollbars!)
    let mut status_spans = vec![
        Span::styled("      ", Style::default()), // Indent to align
        Span::styled("*", Style::default().fg(NEON_GREEN)),
        Span::styled(
            " SYSTEM ONLINE ",
            Style::default().fg(NEON_GREEN).add_modifier(Modifier::BOLD),
        ),
        Span::styled("*", Style::default().fg(NEON_GREEN)),
    ];

    // Add Gateway info if connected
    if state.connected {
        if let Some(gateway_url) = &state.gateway_url {
            // Extract just the host:port from the URL
            let gateway_display = gateway_url
                .replace("http://", "")
                .replace("https://", "")
                .split('/')
                .next()
                .unwrap_or(gateway_url)
                .to_string();

            status_spans.push(Span::styled(
                "    Gateway: ",
                Style::default().fg(TEXT_MUTED),
            ));
            status_spans.push(Span::styled(
                gateway_display,
                Style::default().fg(CYBER_CYAN).add_modifier(Modifier::BOLD),
            ));

            // Add health status if verified
            if state.gateway_healthy {
                status_spans.push(Span::styled(" [✓]", Style::default().fg(NEON_GREEN)));
            }
        }
    }

    let status_line = Line::from(status_spans);

    f.render_widget(
        Paragraph::new(brand_line),
        Rect {
            x: header_area.x,
            y: header_area.y,
            width: header_area.width,
            height: 1,
        },
    );
    f.render_widget(
        Paragraph::new(status_line),
        Rect {
            x: header_area.x,
            y: header_area.y + 1,
            width: header_area.width,
            height: 1,
        },
    );

    // Bug 6 fix: Add separator line below header (but stop before right edge)
    let max_sep_width = (header_area.width * 85 / 100).max(20); // Max 85% of width
    let separator = "-".repeat(max_sep_width as usize);
    f.render_widget(
        Paragraph::new(Line::from(Span::styled(
            separator,
            Style::default().fg(TEXT_MUTED),
        ))),
        Rect {
            x: header_area.x,
            y: header_area.y + 2,
            width: max_sep_width,
            height: 1,
        },
    );
}

fn format_uptime(secs: u64) -> String {
    let hours = secs / 3600;
    let mins = (secs % 3600) / 60;
    let secs = secs % 60;

    if hours > 0 {
        format!("{}h {}m {}s", hours, mins, secs)
    } else if mins > 0 {
        format!("{}m {}s", mins, secs)
    } else {
        format!("{}s", secs)
    }
}

fn render_content(f: &mut Frame, area: Rect, state: &AppState) {
    // Two-column layout: Left (system) + Right (logs & capabilities)
    let cols = Layout::default()
        .direction(Direction::Horizontal)
        .constraints([
            Constraint::Percentage(35), // Left panel
            Constraint::Percentage(65), // Right panel
        ])
        .split(area);

    render_left_column(f, cols[0], state);

    // Right column: Operations Log + Capabilities
    // Bug 2 fix: Ensure 15% margin from right edge (use 85% of width max)
    let max_width = (cols[1].width * 85 / 100).max(10); // At least 10 chars, max 85% of width
    let right_chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([
            Constraint::Percentage(70), // Operations log (main focus)
            Constraint::Percentage(30), // Capabilities
        ])
        .split(Rect {
            x: cols[1].x,
            y: cols[1].y,
            width: max_width.saturating_sub(2), // Additional 2 char margin for safety
            height: cols[1].height,
        });

    render_center_column(f, right_chunks[0], state);

    // === ADD SEPARATOR BETWEEN OPERATIONS LOG AND CAPABILITIES ===
    // IMPORTANT: Stop separator well before right edge (don't go too far on x-axis)
    if right_chunks[1].y > right_chunks[0].y + right_chunks[0].height {
        // Use the operations log panel width, not the full column width
        let ops_panel_width = right_chunks[0].width;
        let safe_sep_width = (ops_panel_width * 80 / 100).min(ops_panel_width.saturating_sub(15)); // Stop well before right edge
        render_separator(
            f,
            Rect {
                x: right_chunks[0].x,
                y: right_chunks[0].y + right_chunks[0].height,
                width: safe_sep_width,
                height: 1,
            },
        );
    }

    render_right_column(f, right_chunks[1], state);
}

fn render_left_column(f: &mut Frame, area: Rect, state: &AppState) {
    let panel_area = Rect {
        x: area.x + 1,
        y: area.y,
        width: area.width.saturating_sub(2),
        height: area.height,
    };

    // Split into System Status and Resources
    let chunks = Layout::default()
        .direction(Direction::Vertical)
        .constraints([Constraint::Percentage(70), Constraint::Percentage(30)])
        .split(panel_area);

    // === SYSTEM STATUS PANEL ===
    render_panel_border(f, chunks[0], "SYSTEM STATUS", BRAND_PURPLE);

    let status_content = inner_rect(chunks[0], 2);
    let mut lines = vec![];

    // Use STATIC dots for status indicators (not animated - prevents flashing when typing)
    // Instructions: "DON'T use animated pulse for status dots - they flash weirdly when typing!"

    // Posture status - Use ASCII * instead of Unicode ◉
    let posture_color = if state.posture_status == "Healthy" || state.connected {
        NEON_GREEN
    } else {
        AMBER_WARN
    };
    lines.push(Line::from(vec![
        Span::styled("* ", Style::default().fg(posture_color)),
        Span::styled("POSTURE    ", Style::default().fg(TEXT_DIM)),
        Span::styled(
            &state.posture_status,
            Style::default()
                .fg(posture_color)
                .add_modifier(Modifier::BOLD),
        ),
    ]));

    // Shield status
    let shield_color = match state.shield_mode.as_str() {
        "enforce" => NEON_GREEN,
        "monitor" => AMBER_WARN,
        _ => TEXT_MUTED,
    };
    lines.push(Line::from(vec![
        Span::styled("* ", Style::default().fg(shield_color)),
        Span::styled("SHIELD     ", Style::default().fg(TEXT_DIM)),
        Span::styled(
            state.shield_mode.to_uppercase(),
            Style::default()
                .fg(shield_color)
                .add_modifier(Modifier::BOLD),
        ),
        Span::styled(
            format!(" ({} active)", state.shield_detectors.len()),
            Style::default().fg(TEXT_DIM),
        ),
    ]));
    if state.shield_blocks_total > 0 || state.shield_masks_total > 0 {
        lines.push(Line::from(vec![
            Span::raw("  "),
            Span::styled(
                format!(
                    "↳ {} block(s) · {} mask(s) (Gateway metrics)",
                    state.shield_blocks_total, state.shield_masks_total
                ),
                Style::default().fg(TEXT_DIM),
            ),
        ]));
    }

    // Sentinel status
    let sentinel_color = match state.sentinel_state.as_str() {
        "watching" => CYBER_CYAN,
        "triggered" => Color::Rgb(255, 69, 58),
        _ => TEXT_DIM,
    };
    let mut sentinel_line = vec![
        Span::styled("* ", Style::default().fg(sentinel_color)),
        Span::styled("SENTINEL   ", Style::default().fg(TEXT_DIM)),
        Span::styled(
            state.sentinel_state.to_uppercase(),
            Style::default()
                .fg(sentinel_color)
                .add_modifier(Modifier::BOLD),
        ),
    ];
    if state.sentinel_active_runs > 0 {
        sentinel_line.push(Span::styled(
            format!(" ({} runs)", state.sentinel_active_runs),
            Style::default().fg(TEXT_DIM),
        ));
    }
    lines.push(Line::from(sentinel_line));

    // Bug 6 fix: Add visual separator between sections (but stop before right edge)
    // Use ASCII dashes, max 85% of width to avoid scrollbars
    let max_sep_width = (status_content.width * 85 / 100).max(10).min(30); // Max 30 chars or 85% of width
    let separator = "-".repeat(max_sep_width as usize);
    lines.push(Line::from(Span::styled(
        separator,
        Style::default().fg(TEXT_MUTED),
    )));

    // Show enabled detectors with STATIC dots (not animated)
    for detector in &state.shield_detectors {
        let name = match detector.as_str() {
            "pii" => "PII Detection",
            "injection" => "Injection Block",
            "hallucination" => "Hallucination Check",
            _ => detector.as_str(),
        };
        lines.push(Line::from(vec![
            Span::styled("* ", Style::default().fg(NEON_GREEN)), // Static asterisk
            Span::styled(name, Style::default().fg(TEXT_PRIMARY)),
        ]));
    }

    // Connection status
    if !state.connected {
        lines.push(Line::from(""));
        lines.push(Line::from(vec![
            Span::styled("* ", Style::default().fg(AMBER_WARN)), // Use ASCII * instead of Unicode ⚠
            Span::styled("Demo Mode - Not connected", Style::default().fg(AMBER_WARN)),
        ]));
    }

    f.render_widget(Paragraph::new(lines), status_content);

    // Bug 6 fix: Add separator between System Status and Resources sections
    let max_sep_width = (panel_area.width * 85 / 100).max(10).min(30);
    let separator = "-".repeat(max_sep_width as usize);
    let sep_y = chunks[0].y + chunks[0].height;
    f.render_widget(
        Paragraph::new(Line::from(Span::styled(
            separator,
            Style::default().fg(TEXT_MUTED),
        ))),
        Rect {
            x: panel_area.x,
            y: sep_y,
            width: max_sep_width,
            height: 1,
        },
    );

    // === RESOURCES PANEL ===
    render_panel_border(f, chunks[1], "RESOURCES", TEXT_DIM);
    let resources_content = inner_rect(chunks[1], 2);

    let network_color = if state.connected {
        NEON_GREEN
    } else {
        TEXT_MUTED
    };

    let mut lines = vec![
        render_progress_bar("CPU", state.cpu, cpu_color(state.cpu)),
        render_progress_bar("MEM", state.mem, mem_color(state.mem)),
        Line::from(""),
    ];

    // Network info - Use ASCII * instead of Unicode ◉
    lines.push(Line::from(vec![
        Span::styled("NET ", Style::default().fg(TEXT_DIM)),
        Span::styled("* ", Style::default().fg(network_color)),
        Span::styled(&state.network_status, Style::default().fg(network_color)),
    ]));
    if state.connected {
        lines.push(Line::from(vec![
            Span::styled("  Runs: ", Style::default().fg(TEXT_DIM)),
            Span::styled(
                format!("{}", state.total_runs),
                Style::default().fg(TEXT_PRIMARY),
            ),
        ]));
    }
    lines.push(Line::from(""));
    lines.push(Line::from(vec![
        Span::styled("Uptime: ", Style::default().fg(TEXT_DIM)),
        Span::styled(
            format_uptime(state.uptime_secs),
            Style::default().fg(TEXT_PRIMARY),
        ),
    ]));

    f.render_widget(Paragraph::new(lines), resources_content);
}

fn render_panel_border(f: &mut Frame, area: Rect, title: &str, color: Color) {
    // Top border with title - KEEP SHORT to avoid scrollbars!
    // Instructions: "Only draw title, no long horizontal lines"
    // Use ASCII characters that work everywhere
    let title_line = Line::from(vec![
        Span::styled("[ ", Style::default().fg(TEXT_MUTED)), // ASCII [ instead of Unicode ┌
        Span::styled(
            title,
            Style::default().fg(color).add_modifier(Modifier::BOLD),
        ),
        Span::styled(" ", Style::default()),
        // Only short dash, not full width - instructions say this causes scrollbars!
        Span::styled("-", Style::default().fg(TEXT_MUTED)), // Just a short dash, not full width
    ]);
    // Make sure width doesn't touch right edge
    let title_width = (title.len() as u16 + 4).min(area.width.saturating_sub(6));
    f.render_widget(
        Paragraph::new(title_line),
        Rect {
            x: area.x,
            y: area.y,
            width: title_width, // Only as wide as needed, not full width
            height: 1,
        },
    );

    // NO bottom border - instructions say it causes scrollbars!
    // The visual separation comes from spacing and color
}

fn inner_rect(area: Rect, padding: u16) -> Rect {
    Rect {
        x: area.x + padding,
        y: area.y + 1,
        width: area.width.saturating_sub(padding * 2 + 2),
        height: area.height.saturating_sub(2),
    }
}

fn render_progress_bar(label: &str, value: f64, color: Color) -> Line<'static> {
    let bar_width = 12;
    let filled = ((value * bar_width as f64) as usize).min(bar_width);
    let empty = bar_width - filled;

    Line::from(vec![
        Span::styled(format!("{} ", label), Style::default().fg(TEXT_DIM)),
        Span::styled("█".repeat(filled), Style::default().fg(color)),
        Span::styled("░".repeat(empty), Style::default().fg(TEXT_MUTED)),
        Span::styled(
            format!(" {:>3.0}%", value * 100.0),
            Style::default().fg(color),
        ),
    ])
}

fn cpu_color(value: f64) -> Color {
    if value > 0.8 {
        Color::Rgb(255, 69, 58)
    }
    // Red
    else if value > 0.5 {
        Color::Rgb(255, 191, 0)
    }
    // Amber
    else {
        NEON_GREEN
    }
}

fn mem_color(value: f64) -> Color {
    if value > 0.8 {
        Color::Rgb(255, 69, 58)
    } else if value > 0.6 {
        Color::Rgb(255, 191, 0)
    } else {
        CYBER_CYAN
    }
}

fn render_center_column(f: &mut Frame, area: Rect, state: &AppState) {
    let panel_area = Rect {
        x: area.x + 1,
        y: area.y,
        width: area.width.saturating_sub(2),
        height: area.height,
    };

    // === OPERATIONS LOG - More contained/closed appearance ===
    // Draw a proper box border for a more "closed up" look
    let border_block = Block::default()
        .title(" OPERATIONS LOG ")
        .title_style(Style::default().fg(CYBER_CYAN).add_modifier(Modifier::BOLD))
        .borders(Borders::ALL)
        .border_style(Style::default().fg(TEXT_MUTED));

    f.render_widget(border_block, panel_area);

    // Content area with padding (inside the border)
    let content_area = Rect {
        x: panel_area.x + 1,
        y: panel_area.y + 1,
        width: panel_area.width.saturating_sub(4), // Leave room for border (2) + scrollbar (2)
        height: panel_area.height.saturating_sub(2), // Top and bottom borders
    };

    let visible_height = content_area.height as usize;
    let total_logs = state.logs.len();
    let max_scroll = total_logs.saturating_sub(visible_height.max(1));

    // Calculate which logs to show (scroll_pos = 0 means newest, higher = older)
    let start_idx = state.log_scroll.min(max_scroll);
    let _end_idx = (start_idx + visible_height).min(total_logs);

    let spinner = SPINNERS[state.spinner_frame];

    let mut lines = vec![Line::from(vec![
        Span::styled(spinner, Style::default().fg(CYBER_CYAN)),
        Span::styled(
            " Monitoring...",
            Style::default().fg(TEXT_DIM).add_modifier(Modifier::ITALIC),
        ),
    ])];

    // Show real logs with proper formatting (reversed order - newest first)
    for log in state.logs.iter().rev().skip(start_idx).take(visible_height) {
        if log.starts_with("[") {
            // Parse log format: [COMPONENT] message
            if let Some(bracket_end) = log.find(']') {
                let component = &log[1..bracket_end];
                let message = log[bracket_end + 1..].trim();

                let comp_color = match component {
                    "GATEWAY" => CYBER_CYAN,
                    "SHIELD" => BRAND_PURPLE,
                    "SENTINEL" => NEON_GREEN,
                    "WORKER" => AMBER_WARN,
                    "SYSTEM" => TEXT_DIM,
                    "HELP" => CYBER_CYAN,
                    _ => TEXT_DIM,
                };

                lines.push(Line::from(vec![
                    Span::styled("> ", Style::default().fg(comp_color)), // Use ASCII > instead of Unicode ▸
                    Span::styled(format!("[{}] ", component), Style::default().fg(comp_color)),
                    Span::styled(message, Style::default().fg(TEXT_PRIMARY)),
                ]));
            } else {
                lines.push(Line::from(Span::styled(
                    log.as_str(),
                    Style::default().fg(TEXT_PRIMARY),
                )));
            }
        } else if log.starts_with(">") {
            // Command echo
            lines.push(Line::from(vec![
                Span::styled("> ", Style::default().fg(BRAND_PURPLE)), // Use ASCII > instead of Unicode ▸
                Span::styled(log, Style::default().fg(BRAND_PURPLE)),
            ]));
        } else {
            lines.push(Line::from(Span::styled(
                log.as_str(),
                Style::default().fg(TEXT_PRIMARY),
            )));
        }
    }

    // Connection status at bottom
    if !state.connected {
        lines.push(Line::from(""));
        lines.push(Line::from(vec![
            Span::styled("* ", Style::default().fg(AMBER_WARN)), // Use ASCII * instead of Unicode ⚠
            Span::styled(
                "Demo Mode - Not connected to Gateway",
                Style::default().fg(AMBER_WARN),
            ),
        ]));
    }

    f.render_widget(Paragraph::new(lines), content_area);

    // === RENDER CLEAN SCROLLBAR (only if scrollable) ===
    // CRITICAL FIX: Only render scrollbar when actually scrollable to prevent flickering
    if total_logs > visible_height && max_scroll > 0 {
        // Scrollbar positioned inside the border, 1 char from right edge
        // Use fixed position to prevent jitter
        let scrollbar_x = panel_area.x + panel_area.width.saturating_sub(3);
        let scrollbar_y = content_area.y;
        let scrollbar_height = content_area.height;

        // CRITICAL: Use integer math to prevent floating point rounding issues
        // Calculate thumb size (minimum 1 char, proportional to visible/total)
        let thumb_height =
            ((visible_height as u32 * scrollbar_height as u32) / total_logs as u32) as u16;
        let thumb_height = thumb_height.max(1).min(scrollbar_height);

        // Calculate thumb position using integer math for stability
        let thumb_start = if max_scroll > 0 {
            // Use integer division to avoid floating point jitter
            ((state.log_scroll as u32 * (scrollbar_height.saturating_sub(thumb_height) as u32))
                / max_scroll as u32) as u16
        } else {
            0
        };

        // Clamp thumb_start to valid range
        let thumb_start = thumb_start.min(scrollbar_height.saturating_sub(thumb_height));
        let thumb_end = (thumb_start + thumb_height).min(scrollbar_height);

        // Render scrollbar track (entire height) as single operation to prevent flicker
        // Build scrollbar string first, then render once
        let mut scrollbar_chars = vec![String::from("│"); scrollbar_height as usize];

        // Fill thumb portion
        for i in thumb_start..thumb_end {
            if i < scrollbar_height {
                scrollbar_chars[i as usize] = String::from("█");
            }
        }

        // Render entire scrollbar at once (prevents flickering from multiple renders)
        for (i, c) in scrollbar_chars.iter().enumerate() {
            let y = scrollbar_y + i as u16;
            if y < scrollbar_y + scrollbar_height {
                let color = if i >= thumb_start as usize && i < thumb_end as usize {
                    CYBER_CYAN
                } else {
                    TEXT_MUTED
                };
                f.render_widget(
                    Paragraph::new(c.as_str()).style(Style::default().fg(color)),
                    Rect {
                        x: scrollbar_x,
                        y,
                        width: 1,
                        height: 1,
                    },
                );
            }
        }
    }
}

fn render_right_column(f: &mut Frame, area: Rect, state: &AppState) {
    // This now only renders CAPABILITIES (Network is shown in left panel)
    let panel_area = Rect {
        x: area.x + 1,
        y: area.y,
        width: area.width.saturating_sub(4), // Extra margin on right
        height: area.height,
    };

    // === CAPABILITIES PANEL ===
    render_panel_border(f, panel_area, "CAPABILITIES", BRAND_PURPLE);
    let caps_content = inner_rect(panel_area, 2);

    // Use STATIC indicators (not animated pulse)
    let mut cap_lines: Vec<Line> = vec![];

    if state.capabilities.is_empty() {
        cap_lines.push(Line::from(vec![
            Span::styled("- ", Style::default().fg(TEXT_MUTED)),
            Span::styled("No agents registered", Style::default().fg(TEXT_DIM)),
        ]));
        cap_lines.push(Line::from(vec![
            Span::styled("  ", Style::default()),
            Span::styled(
                "Use DevKit to register agents",
                Style::default().fg(TEXT_MUTED),
            ),
        ]));
    } else {
        for cap in state
            .capabilities
            .iter()
            .take(caps_content.height.saturating_sub(1) as usize)
        {
            cap_lines.push(Line::from(vec![
                Span::styled("+ ", Style::default().fg(BRAND_PURPLE)), // Static plus sign
                Span::styled(cap.as_str(), Style::default().fg(TEXT_PRIMARY)),
                Span::styled("  ", Style::default()),
                Span::styled("* READY", Style::default().fg(NEON_GREEN)), // Static asterisk
            ]));
        }
        cap_lines.push(Line::from(vec![Span::styled(
            format!("{} agents", state.capabilities.len()),
            Style::default().fg(TEXT_DIM),
        )]));
    }

    f.render_widget(Paragraph::new(cap_lines), caps_content);
}

fn render_command_box(f: &mut Frame, area: Rect, state: &AppState) {
    // Bug 2 fix: Ensure 15% margin from right edge (use 85% of width max)
    let max_width = (area.width * 85 / 100).max(10); // At least 10 chars, max 85% of width
    let bar_area = Rect {
        x: area.x + 2,
        y: area.y,
        width: max_width.saturating_sub(2), // Additional 2 char margin
        height: area.height,
    };

    // NO separator line - instructions say it causes scrollbars!
    // Just use spacing for visual separation

    // Command prompt - Use ASCII > instead of Unicode ▶
    // Note: We show a visual cursor character "_" in the text, but the real cursor
    // position is handled separately below
    let prompt_line = Line::from(vec![
        Span::styled("> ", Style::default().fg(BRAND_PURPLE)), // ASCII > instead of Unicode ▶
        Span::styled(
            "4runr",
            Style::default()
                .fg(BRAND_VIOLET)
                .add_modifier(Modifier::BOLD),
        ),
        Span::styled(": ", Style::default().fg(TEXT_DIM)), // ASCII : instead of Unicode ›
        Span::styled(&state.command_input, Style::default().fg(TEXT_PRIMARY)),
        Span::styled("_", Style::default().fg(CYBER_CYAN)), // Visual cursor indicator
    ]);
    f.render_widget(
        Paragraph::new(prompt_line),
        Rect {
            x: bar_area.x,
            y: bar_area.y + 1,
            width: bar_area.width,
            height: 1,
        },
    );

    // Help hints - Use ASCII | instead of Unicode │
    let help_line = Line::from(vec![
        Span::styled("Ctrl+C", Style::default().fg(BRAND_VIOLET)),
        Span::styled(" exit  |  ", Style::default().fg(TEXT_MUTED)), // ASCII | instead of Unicode │
        Span::styled("F10", Style::default().fg(BRAND_VIOLET)),
        Span::styled(" quit  |  ", Style::default().fg(TEXT_MUTED)), // ASCII | instead of Unicode │
        Span::styled("help", Style::default().fg(BRAND_VIOLET)),
        Span::styled(" commands", Style::default().fg(TEXT_MUTED)),
    ]);
    f.render_widget(
        Paragraph::new(help_line),
        Rect {
            x: bar_area.x,
            y: bar_area.y + 2,
            width: bar_area.width,
            height: 1,
        },
    );

    // CRITICAL FIX: Only set cursor position when user is actively typing
    // This prevents cursor from appearing in wrong places (operations log, etc.)
    // IMPORTANT: In Ratatui, set_cursor() shows the cursor, so we only call it here
    if state.command_focused || !state.command_input.is_empty() {
        // Calculate correct cursor position: "> 4runr: " = 9 chars
        let prompt_len = 9u16; // "> 4runr: " = 9 characters ("> " + "4runr" + ": " = 2+5+2 = 9)
        let input_len = state.command_input.len() as u16;
        let cursor_x = bar_area.x + prompt_len + input_len;
        let cursor_y = bar_area.y + 1;

        // Ensure cursor doesn't go beyond the safe area (respects 15% margin)
        let max_x = (bar_area.x + bar_area.width).saturating_sub(1);
        let final_x = cursor_x.min(max_x);

        // Only set cursor if we're actually at the input field
        // This prevents cursor from appearing elsewhere (operations log, etc.)
        f.set_cursor(final_x, cursor_y);
    }
    // IMPORTANT: If not focused and no input, we don't call set_cursor()
    // This keeps the cursor hidden (hidden at start of main loop)
}

fn render_too_small(f: &mut Frame, viewport: &SafeViewport) {
    let msg = vec![
        Line::from(Span::styled(
            "4Runr.",
            Style::default()
                .fg(BRAND_PURPLE)
                .add_modifier(Modifier::BOLD),
        )), // Bug 3 fix: Use "4Runr." with dot
        Line::from(""),
        Line::from(Span::styled(
            "Terminal too small",
            Style::default().fg(Color::Rgb(255, 69, 58)),
        )),
        Line::from(""),
        Line::from(Span::styled(
            format!("Current: {}x{}", viewport.safe_cols, viewport.safe_rows),
            Style::default().fg(TEXT_DIM),
        )),
        Line::from(Span::styled(
            format!("Required: {}x{}", MIN_COLS, MIN_ROWS),
            Style::default().fg(TEXT_PRIMARY),
        )),
    ];

    f.render_widget(
        Paragraph::new(msg).alignment(Alignment::Center),
        viewport.safe_rect,
    );
}

fn render_perf_overlay(f: &mut Frame, area: Rect, state: &AppState) {
    // Calculate RPS from recent render durations
    let rps = if !state.render_durations.is_empty() {
        let avg_ms: f64 =
            state.render_durations.iter().sum::<u64>() as f64 / state.render_durations.len() as f64;
        if avg_ms > 0.0 {
            (1000.0 / avg_ms) as u64
        } else {
            0
        }
    } else {
        0
    };

    let last_render_ms = if !state.render_durations.is_empty() {
        *state.render_durations.back().unwrap()
    } else {
        0
    };

    let overlay_text = format!(
        "PERF OVERLAY (F12 to toggle)\n\
        RPS: {} | Last render: {}ms | Total renders: {}\n\
        Render scheduled: {} | Log writes: {}",
        rps,
        last_render_ms,
        state.render_count,
        state.render_scheduled_count,
        state.log_write_count
    );

    let overlay_area = Rect {
        x: area.width.saturating_sub(60),
        y: 2,
        width: 58,
        height: 5,
    };

    let block = Block::default()
        .borders(Borders::ALL)
        .border_style(Style::default().fg(Color::Yellow))
        .title(" Performance ");

    let paragraph = Paragraph::new(overlay_text)
        .block(block)
        .style(Style::default().fg(Color::White))
        .wrap(Wrap { trim: true });

    f.render_widget(paragraph, overlay_area);
}
