#![allow(dead_code)] // Phase 3: consumed by view/mod.rs screen dispatch

//! Who (people intelligence) screen view.
//!
//! Layout:
//! ```text
//! +--[ Expert ]--[ Workload ]--[ Reviews ]--[ Active ]--[ Overlap ]--+
//! | > path or username input_                                        |
//! +──────────────────────────────────────────────────────────────────+
//! | alice        score: 142   3A 2R          group/project           |
//! | bob          score:  89   1A 4R          group/project           |
//! +──────────────────────────────────────────────────────────────────+
//! | 1-5: mode  /: focus  c: closed  j/k: nav  Enter: drill-down    |
//! +──────────────────────────────────────────────────────────────────+
//! ```

use ftui::core::geometry::Rect;
use ftui::render::cell::{Cell, PackedRgba};
use ftui::render::drawing::Draw;
use ftui::render::frame::Frame;

use lore::core::who_types::{
    ActiveResult, ExpertResult, OverlapResult, ReviewsResult, WhoResult, WorkloadResult,
};

use crate::state::who::{WhoMode, WhoState};

use super::common::truncate_str;
use super::{ACCENT, BG_SURFACE, BORDER, TEXT, TEXT_MUTED};

/// Muted accent for inactive mode tabs.
const TAB_INACTIVE: PackedRgba = PackedRgba::rgb(0x6F, 0x6E, 0x69); // ui-3

/// Green for bar chart / positive indicators.
const GREEN: PackedRgba = PackedRgba::rgb(0x87, 0x9A, 0x39); // green

/// Cyan for secondary highlights.
const CYAN: PackedRgba = PackedRgba::rgb(0x3A, 0xA9, 0x9F); // cyan

// ---------------------------------------------------------------------------
// render_who (top-level)
// ---------------------------------------------------------------------------

/// Render the who screen.
pub fn render_who(frame: &mut Frame<'_>, state: &WhoState, area: Rect) {
    if area.height < 5 || area.width < 30 {
        return;
    }

    let mut y = area.y;
    let max_x = area.right();

    // -- Mode tabs -----------------------------------------------------------
    y = render_mode_tabs(frame, state.mode, area.x, y, area.width, max_x);

    // -- Input bar -----------------------------------------------------------
    if state.mode.needs_path() || state.mode.needs_username() {
        y = render_input_bar(frame, state, area.x, y, area.width, max_x);
    }

    // -- Separator -----------------------------------------------------------
    if y >= area.bottom() {
        return;
    }
    let sep_cell = Cell {
        fg: BORDER,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let sep_line = "\u{2500}".repeat(area.width as usize);
    frame.print_text_clipped(area.x, y, &sep_line, sep_cell, max_x);
    y += 1;

    // -- Content area --------------------------------------------------------
    let bottom_hint_row = area.bottom().saturating_sub(1);
    let content_height = bottom_hint_row.saturating_sub(y) as usize;

    if content_height == 0 {
        return;
    }

    if state.loading {
        render_loading_indicator(frame, area.x + 1, y, max_x);
    } else if let Some(ref result) = state.result {
        render_result(frame, result, state, area.x, y, area.width, content_height);
    } else {
        render_empty_state(frame, state, area.x + 1, y, max_x);
    }

    // -- Include-closed indicator --------------------------------------------
    if state.include_closed && y < area.bottom() {
        let indicator = " [closed: on] ";
        let ind_x = max_x.saturating_sub(indicator.len() as u16);
        let ind_cell = Cell {
            fg: CYAN,
            bg: BG_SURFACE,
            ..Cell::default()
        };
        frame.print_text_clipped(ind_x, area.y, indicator, ind_cell, max_x);
    }

    // -- Bottom hint bar -----------------------------------------------------
    if bottom_hint_row < area.bottom() {
        render_hint_bar(frame, state, area.x, bottom_hint_row, max_x);
    }
}

// ---------------------------------------------------------------------------
// Mode tabs
// ---------------------------------------------------------------------------

fn render_mode_tabs(
    frame: &mut Frame<'_>,
    current: WhoMode,
    x: u16,
    y: u16,
    _width: u16,
    max_x: u16,
) -> u16 {
    let mut cursor_x = x;

    for mode in WhoMode::ALL {
        let is_active = mode == current;
        let label = if is_active {
            format!("[ {} ]", mode.label())
        } else {
            format!("  {}  ", mode.label())
        };

        let cell = Cell {
            fg: if is_active { ACCENT } else { TAB_INACTIVE },
            bg: BG_SURFACE,
            ..Cell::default()
        };

        cursor_x = frame.print_text_clipped(cursor_x, y, &label, cell, max_x);

        if cursor_x >= max_x {
            break;
        }
    }

    y + 1
}

// ---------------------------------------------------------------------------
// Input bar
// ---------------------------------------------------------------------------

fn render_input_bar(
    frame: &mut Frame<'_>,
    state: &WhoState,
    x: u16,
    y: u16,
    _width: u16,
    max_x: u16,
) -> u16 {
    let prompt_cell = Cell {
        fg: ACCENT,
        bg: BG_SURFACE,
        ..Cell::default()
    };

    let (prompt, text, placeholder, focused) = if state.mode.needs_path() {
        (
            "path> ",
            &state.path,
            "src/features/auth/",
            state.path_focused,
        )
    } else {
        (
            "user> ",
            &state.username,
            "@username",
            state.username_focused,
        )
    };

    let after_prompt = frame.print_text_clipped(x, y, prompt, prompt_cell, max_x);

    let (display_text, fg) = if text.is_empty() {
        (placeholder, TEXT_MUTED)
    } else {
        (text.as_str(), TEXT)
    };

    let text_cell = Cell {
        fg,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    frame.print_text_clipped(after_prompt, y, display_text, text_cell, max_x);

    // Cursor rendering when focused.
    if focused && !text.is_empty() {
        let cursor_pos = if state.mode.needs_path() {
            state.path_cursor
        } else {
            state.username_cursor
        };
        let cursor_col = text[..cursor_pos.min(text.len())]
            .chars()
            .count()
            .min(u16::MAX as usize) as u16;
        let cursor_x = after_prompt + cursor_col;
        if cursor_x < max_x {
            let cursor_cell = Cell {
                fg: BG_SURFACE,
                bg: TEXT,
                ..Cell::default()
            };
            let cursor_char = text
                .get(cursor_pos..)
                .and_then(|s| s.chars().next())
                .unwrap_or(' ');
            frame.print_text_clipped(cursor_x, y, &cursor_char.to_string(), cursor_cell, max_x);
        }
    }

    y + 1
}

// ---------------------------------------------------------------------------
// Result dispatch
// ---------------------------------------------------------------------------

fn render_result(
    frame: &mut Frame<'_>,
    result: &WhoResult,
    state: &WhoState,
    x: u16,
    y: u16,
    width: u16,
    height: usize,
) {
    match result {
        WhoResult::Expert(r) => render_expert(frame, r, state, x, y, width, height),
        WhoResult::Workload(r) => render_workload(frame, r, state, x, y, width, height),
        WhoResult::Reviews(r) => render_reviews(frame, r, state, x, y, width, height),
        WhoResult::Active(r) => render_active(frame, r, state, x, y, width, height),
        WhoResult::Overlap(r) => render_overlap(frame, r, state, x, y, width, height),
    }
}

// ---------------------------------------------------------------------------
// Expert mode
// ---------------------------------------------------------------------------

fn render_expert(
    frame: &mut Frame<'_>,
    result: &ExpertResult,
    state: &WhoState,
    x: u16,
    start_y: u16,
    width: u16,
    height: usize,
) {
    let max_x = x + width;

    if result.experts.is_empty() {
        let cell = Cell {
            fg: TEXT_MUTED,
            bg: BG_SURFACE,
            ..Cell::default()
        };
        frame.print_text_clipped(
            x + 1,
            start_y,
            "No experts found for this path.",
            cell,
            max_x,
        );
        frame.print_text_clipped(
            x + 1,
            start_y + 1,
            "Ensure diff notes are synced (lore sync).",
            cell,
            max_x,
        );
        return;
    }

    let max_score = result
        .experts
        .iter()
        .map(|e| e.score)
        .max()
        .unwrap_or(1)
        .max(1);

    let normal = Cell {
        fg: TEXT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let selected_cell = Cell {
        fg: BG_SURFACE,
        bg: ACCENT,
        ..Cell::default()
    };
    let muted = Cell {
        fg: TEXT_MUTED,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let bar_cell = Cell {
        fg: GREEN,
        bg: BG_SURFACE,
        ..Cell::default()
    };

    for (i, expert) in result
        .experts
        .iter()
        .skip(state.scroll_offset)
        .enumerate()
        .take(height)
    {
        let y = start_y + i as u16;
        let is_selected = i + state.scroll_offset == state.selected_index;

        let (label_style, detail_style) = if is_selected {
            (selected_cell, selected_cell)
        } else {
            (normal, muted)
        };

        // Fill background for selected row.
        if is_selected {
            for col in x..max_x {
                frame.buffer.set(col, y, selected_cell);
            }
        }

        // Username (left-aligned, 16 chars).
        let name = truncate_str(&expert.username, 16);
        let after_name = frame.print_text_clipped(x + 1, y, &name, label_style, max_x);

        // Score.
        let score_str = format!("{:>5}", expert.score);
        let after_score =
            frame.print_text_clipped(after_name + 1, y, &score_str, label_style, max_x);

        // Bar chart (proportional to max score).
        let bar_width = 12u16;
        let filled = ((expert.score as f64 / max_score as f64) * bar_width as f64) as u16;
        let bar_str: String = "\u{2588}"
            .repeat(filled as usize)
            .chars()
            .chain(std::iter::repeat_n(
                '\u{2591}',
                (bar_width - filled) as usize,
            ))
            .collect();
        let bar_style = if is_selected { selected_cell } else { bar_cell };
        let after_bar = frame.print_text_clipped(after_score + 1, y, &bar_str, bar_style, max_x);

        // MR counts.
        let counts = format!("{}A {}R", expert.author_mr_count, expert.review_mr_count);
        frame.print_text_clipped(after_bar + 1, y, &counts, detail_style, max_x);
    }

    // Truncation footer.
    render_truncation_footer(
        frame,
        result.truncated,
        result.experts.len(),
        x,
        start_y,
        width,
        height,
    );
}

// ---------------------------------------------------------------------------
// Workload mode
// ---------------------------------------------------------------------------

fn render_workload(
    frame: &mut Frame<'_>,
    result: &WorkloadResult,
    _state: &WhoState,
    x: u16,
    start_y: u16,
    width: u16,
    height: usize,
) {
    let max_x = x + width;
    let mut y = start_y;
    let end_y = start_y + height as u16;

    let header_cell = Cell {
        fg: ACCENT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let normal = Cell {
        fg: TEXT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let muted = Cell {
        fg: TEXT_MUTED,
        bg: BG_SURFACE,
        ..Cell::default()
    };

    // Section: Assigned Issues
    if y < end_y {
        let label = format!(
            "Assigned Issues ({}{})",
            result.assigned_issues.len(),
            if result.assigned_issues_truncated {
                "+"
            } else {
                ""
            }
        );
        frame.print_text_clipped(x + 1, y, &label, header_cell, max_x);
        y += 1;
    }
    for issue in &result.assigned_issues {
        if y >= end_y {
            break;
        }
        let line = format!("  {} {}", issue.ref_, truncate_str(&issue.title, 50));
        frame.print_text_clipped(x, y, &line, normal, max_x);
        y += 1;
    }
    if result.assigned_issues.is_empty() && y < end_y {
        frame.print_text_clipped(x + 2, y, "None", muted, max_x);
        y += 1;
    }

    y += 1; // Blank separator.

    // Section: Authored MRs
    if y < end_y {
        let label = format!(
            "Authored MRs ({}{})",
            result.authored_mrs.len(),
            if result.authored_mrs_truncated {
                "+"
            } else {
                ""
            }
        );
        frame.print_text_clipped(x + 1, y, &label, header_cell, max_x);
        y += 1;
    }
    for mr in &result.authored_mrs {
        if y >= end_y {
            break;
        }
        let draft = if mr.draft { " [DRAFT]" } else { "" };
        let line = format!("  {} {}{}", mr.ref_, truncate_str(&mr.title, 45), draft);
        frame.print_text_clipped(x, y, &line, normal, max_x);
        y += 1;
    }
    if result.authored_mrs.is_empty() && y < end_y {
        frame.print_text_clipped(x + 2, y, "None", muted, max_x);
        y += 1;
    }

    y += 1;

    // Section: Reviewing MRs
    if y < end_y {
        let label = format!(
            "Reviewing MRs ({}{})",
            result.reviewing_mrs.len(),
            if result.reviewing_mrs_truncated {
                "+"
            } else {
                ""
            }
        );
        frame.print_text_clipped(x + 1, y, &label, header_cell, max_x);
        y += 1;
    }
    for mr in &result.reviewing_mrs {
        if y >= end_y {
            break;
        }
        let line = format!("  {} {}", mr.ref_, truncate_str(&mr.title, 50));
        frame.print_text_clipped(x, y, &line, normal, max_x);
        y += 1;
    }
    if result.reviewing_mrs.is_empty() && y < end_y {
        frame.print_text_clipped(x + 2, y, "None", muted, max_x);
        y += 1;
    }

    y += 1;

    // Section: Unresolved Discussions
    if y < end_y {
        let label = format!(
            "Unresolved Discussions ({}{})",
            result.unresolved_discussions.len(),
            if result.unresolved_discussions_truncated {
                "+"
            } else {
                ""
            }
        );
        frame.print_text_clipped(x + 1, y, &label, header_cell, max_x);
        y += 1;
    }
    for disc in &result.unresolved_discussions {
        if y >= end_y {
            break;
        }
        let line = format!("  {} {}", disc.ref_, truncate_str(&disc.entity_title, 50));
        frame.print_text_clipped(x, y, &line, normal, max_x);
        y += 1;
    }
    if result.unresolved_discussions.is_empty() && y < end_y {
        frame.print_text_clipped(x + 2, y, "None", muted, max_x);
    }
}

// ---------------------------------------------------------------------------
// Reviews mode
// ---------------------------------------------------------------------------

fn render_reviews(
    frame: &mut Frame<'_>,
    result: &ReviewsResult,
    state: &WhoState,
    x: u16,
    start_y: u16,
    width: u16,
    height: usize,
) {
    let max_x = x + width;

    // Summary header.
    let header_cell = Cell {
        fg: ACCENT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let summary = format!(
        "{}: {} DiffNotes across {} MRs",
        result.username, result.total_diffnotes, result.mrs_reviewed
    );
    frame.print_text_clipped(x + 1, start_y, &summary, header_cell, max_x);

    if result.categories.is_empty() {
        let muted = Cell {
            fg: TEXT_MUTED,
            bg: BG_SURFACE,
            ..Cell::default()
        };
        frame.print_text_clipped(
            x + 1,
            start_y + 1,
            "No review categories found.",
            muted,
            max_x,
        );
        return;
    }

    let normal = Cell {
        fg: TEXT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let selected_cell = Cell {
        fg: BG_SURFACE,
        bg: ACCENT,
        ..Cell::default()
    };
    let bar_cell = Cell {
        fg: CYAN,
        bg: BG_SURFACE,
        ..Cell::default()
    };

    let remaining_height = height.saturating_sub(1);

    for (i, cat) in result
        .categories
        .iter()
        .skip(state.scroll_offset)
        .enumerate()
        .take(remaining_height)
    {
        let y = start_y + 1 + i as u16;
        let is_selected = i + state.scroll_offset == state.selected_index;

        let style = if is_selected {
            // Fill background.
            for col in x..max_x {
                frame.buffer.set(col, y, selected_cell);
            }
            selected_cell
        } else {
            normal
        };

        // Category name (20 chars).
        let name = format!("{:<20}", truncate_str(&cat.name, 20));
        let after_name = frame.print_text_clipped(x + 1, y, &name, style, max_x);

        // Count.
        let count_str = format!("{:>4}", cat.count);
        let after_count = frame.print_text_clipped(after_name + 1, y, &count_str, style, max_x);

        // Percentage bar.
        let bar_width = 20u16;
        let filled = (cat.percentage / 100.0 * bar_width as f64) as u16;
        let bar: String = "\u{2588}"
            .repeat(filled as usize)
            .chars()
            .chain(std::iter::repeat_n(
                '\u{2591}',
                (bar_width - filled) as usize,
            ))
            .collect();
        let bstyle = if is_selected { selected_cell } else { bar_cell };
        let after_bar = frame.print_text_clipped(after_count + 1, y, &bar, bstyle, max_x);

        // Percentage text.
        let pct_str = format!("{:>5.1}%", cat.percentage);
        frame.print_text_clipped(after_bar + 1, y, &pct_str, style, max_x);
    }
}

// ---------------------------------------------------------------------------
// Active mode
// ---------------------------------------------------------------------------

fn render_active(
    frame: &mut Frame<'_>,
    result: &ActiveResult,
    state: &WhoState,
    x: u16,
    start_y: u16,
    width: u16,
    height: usize,
) {
    let max_x = x + width;

    if result.discussions.is_empty() {
        let muted = Cell {
            fg: TEXT_MUTED,
            bg: BG_SURFACE,
            ..Cell::default()
        };
        frame.print_text_clipped(
            x + 1,
            start_y,
            "No unresolved discussions in the last 7 days.",
            muted,
            max_x,
        );
        return;
    }

    // Summary.
    let header_cell = Cell {
        fg: ACCENT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let summary = format!(
        "{} unresolved discussion{}",
        result.total_unresolved_in_window,
        if result.total_unresolved_in_window == 1 {
            ""
        } else {
            "s"
        }
    );
    frame.print_text_clipped(x + 1, start_y, &summary, header_cell, max_x);

    let normal = Cell {
        fg: TEXT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let selected_cell = Cell {
        fg: BG_SURFACE,
        bg: ACCENT,
        ..Cell::default()
    };
    let muted = Cell {
        fg: TEXT_MUTED,
        bg: BG_SURFACE,
        ..Cell::default()
    };

    let remaining_height = height.saturating_sub(1);

    for (i, disc) in result
        .discussions
        .iter()
        .skip(state.scroll_offset)
        .enumerate()
        .take(remaining_height)
    {
        let y = start_y + 1 + i as u16;
        let is_selected = i + state.scroll_offset == state.selected_index;

        let (label_style, detail_style) = if is_selected {
            for col in x..max_x {
                frame.buffer.set(col, y, selected_cell);
            }
            (selected_cell, selected_cell)
        } else {
            (normal, muted)
        };

        // Entity ref.
        let prefix = if disc.entity_type == "Issue" {
            "#"
        } else {
            "!"
        };
        let ref_str = format!("{}{}", prefix, disc.entity_iid);
        let after_ref = frame.print_text_clipped(x + 1, y, &ref_str, label_style, max_x);

        // Title.
        let title = truncate_str(&disc.entity_title, 40);
        let after_title = frame.print_text_clipped(after_ref + 1, y, &title, label_style, max_x);

        // Note count + participants.
        let participants = disc.participants.join(", ");
        let meta = format!("{}n {}", disc.note_count, truncate_str(&participants, 20));
        frame.print_text_clipped(after_title + 1, y, &meta, detail_style, max_x);
    }

    // Truncation.
    render_truncation_footer(
        frame,
        result.truncated,
        result.discussions.len(),
        x,
        start_y,
        width,
        height,
    );
}

// ---------------------------------------------------------------------------
// Overlap mode
// ---------------------------------------------------------------------------

fn render_overlap(
    frame: &mut Frame<'_>,
    result: &OverlapResult,
    state: &WhoState,
    x: u16,
    start_y: u16,
    width: u16,
    height: usize,
) {
    let max_x = x + width;

    if result.users.is_empty() {
        let muted = Cell {
            fg: TEXT_MUTED,
            bg: BG_SURFACE,
            ..Cell::default()
        };
        frame.print_text_clipped(
            x + 1,
            start_y,
            "No contributors found for this path.",
            muted,
            max_x,
        );
        return;
    }

    // Header row.
    let header_cell = Cell {
        fg: ACCENT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    frame.print_text_clipped(
        x + 1,
        start_y,
        "Username          Author  Review  Total",
        header_cell,
        max_x,
    );

    let normal = Cell {
        fg: TEXT,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    let selected_cell = Cell {
        fg: BG_SURFACE,
        bg: ACCENT,
        ..Cell::default()
    };

    let remaining_height = height.saturating_sub(1);

    for (i, user) in result
        .users
        .iter()
        .skip(state.scroll_offset)
        .enumerate()
        .take(remaining_height)
    {
        let y = start_y + 1 + i as u16;
        let is_selected = i + state.scroll_offset == state.selected_index;

        let style = if is_selected {
            for col in x..max_x {
                frame.buffer.set(col, y, selected_cell);
            }
            selected_cell
        } else {
            normal
        };

        let line = format!(
            "{:<18}{:>6}{:>8}{:>7}",
            truncate_str(&user.username, 16),
            user.author_touch_count,
            user.review_touch_count,
            user.touch_count,
        );
        frame.print_text_clipped(x + 1, y, &line, style, max_x);
    }

    // Truncation.
    render_truncation_footer(
        frame,
        result.truncated,
        result.users.len(),
        x,
        start_y,
        width,
        height,
    );
}

// ---------------------------------------------------------------------------
// Common helpers
// ---------------------------------------------------------------------------

fn render_empty_state(frame: &mut Frame<'_>, state: &WhoState, x: u16, y: u16, max_x: u16) {
    let cell = Cell {
        fg: TEXT_MUTED,
        bg: BG_SURFACE,
        ..Cell::default()
    };

    let msg = match state.mode {
        WhoMode::Expert => "Enter a file path and press Enter to find experts.",
        WhoMode::Workload => "Enter a @username and press Enter to see their workload.",
        WhoMode::Reviews => "Enter a @username and press Enter to see review activity.",
        WhoMode::Active => "Press Enter to find recent unresolved discussions.",
        WhoMode::Overlap => "Enter a file path and press Enter to find contributors.",
    };

    frame.print_text_clipped(x, y, msg, cell, max_x);
}

fn render_loading_indicator(frame: &mut Frame<'_>, x: u16, y: u16, max_x: u16) {
    let cell = Cell {
        fg: TEXT_MUTED,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    frame.print_text_clipped(x, y, "Loading...", cell, max_x);
}

fn render_hint_bar(frame: &mut Frame<'_>, state: &WhoState, x: u16, y: u16, max_x: u16) {
    let cell = Cell {
        fg: TEXT_MUTED,
        bg: BG_SURFACE,
        ..Cell::default()
    };

    let hints = if state.has_text_focus() {
        "Esc: blur  Enter: query"
    } else {
        "1-5: mode  /: focus  c: closed  j/k: nav  Enter: open  q: back"
    };

    frame.print_text_clipped(x + 1, y, hints, cell, max_x);
}

fn render_truncation_footer(
    frame: &mut Frame<'_>,
    truncated: bool,
    visible_count: usize,
    x: u16,
    start_y: u16,
    width: u16,
    height: usize,
) {
    if !truncated || height == 0 {
        return;
    }
    let max_x = x + width;
    let footer_y = start_y + height.saturating_sub(1) as u16;
    let footer = format!(" showing {} of more ", visible_count);
    let footer_x = max_x.saturating_sub(footer.len() as u16);
    let cell = Cell {
        fg: TEXT_MUTED,
        bg: BG_SURFACE,
        ..Cell::default()
    };
    frame.print_text_clipped(footer_x, footer_y, &footer, cell, max_x);
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

#[cfg(test)]
mod tests {
    use super::*;
    use crate::state::who::WhoState;
    use ftui::render::grapheme_pool::GraphemePool;

    macro_rules! with_frame {
        ($width:expr, $height:expr, |$frame:ident| $body:block) => {{
            let mut pool = GraphemePool::new();
            let mut $frame = Frame::new($width, $height, &mut pool);
            $body
        }};
    }

    #[test]
    fn test_render_who_empty_no_panic() {
        with_frame!(80, 24, |frame| {
            let state = WhoState::default();
            render_who(&mut frame, &state, Rect::new(0, 0, 80, 24));
        });
    }

    #[test]
    fn test_render_who_tiny_terminal_noop() {
        with_frame!(20, 4, |frame| {
            let state = WhoState::default();
            render_who(&mut frame, &state, Rect::new(0, 0, 20, 4));
        });
    }

    #[test]
    fn test_render_who_loading() {
        with_frame!(80, 24, |frame| {
            let state = WhoState {
                loading: true,
                ..WhoState::default()
            };
            render_who(&mut frame, &state, Rect::new(0, 0, 80, 24));
        });
    }

    #[test]
    fn test_render_who_with_expert_result() {
        with_frame!(100, 30, |frame| {
            let state = WhoState {
                result: Some(WhoResult::Expert(lore::core::who_types::ExpertResult {
                    path_query: "src/".into(),
                    path_match: "prefix".into(),
                    experts: vec![lore::core::who_types::Expert {
                        username: "alice".into(),
                        score: 142,
                        score_raw: None,
                        components: None,
                        review_mr_count: 3,
                        review_note_count: 5,
                        author_mr_count: 2,
                        last_seen_ms: 1_700_000_000_000,
                        mr_refs: vec!["group/project!42".into()],
                        mr_refs_total: 1,
                        mr_refs_truncated: false,
                        details: None,
                    }],
                    truncated: false,
                })),
                ..WhoState::default()
            };
            render_who(&mut frame, &state, Rect::new(0, 0, 100, 30));
        });
    }

    #[test]
    fn test_render_who_active_mode_no_input_bar() {
        with_frame!(80, 24, |frame| {
            let state = WhoState {
                mode: WhoMode::Active,
                ..WhoState::default()
            };
            render_who(&mut frame, &state, Rect::new(0, 0, 80, 24));
            // Active mode should not render input bar (no path/username needed).
        });
    }

    #[test]
    fn test_render_who_with_include_closed() {
        with_frame!(80, 24, |frame| {
            let state = WhoState {
                include_closed: true,
                ..WhoState::default()
            };
            render_who(&mut frame, &state, Rect::new(0, 0, 80, 24));
        });
    }

    #[test]
    fn test_truncate_str() {
        assert_eq!(truncate_str("hello", 10), "hello");
        assert_eq!(truncate_str("hello world", 8), "hello w\u{2026}");
        assert_eq!(truncate_str("hi", 2), "hi");
        assert_eq!(truncate_str("abc", 3), "abc");
    }

    #[test]
    fn test_render_who_all_modes_no_panic() {
        for mode in WhoMode::ALL {
            with_frame!(80, 24, |frame| {
                let state = WhoState {
                    mode,
                    ..WhoState::default()
                };
                render_who(&mut frame, &state, Rect::new(0, 0, 80, 24));
            });
        }
    }
}
