//! List view widget with fuzzy match highlighting.

use std::collections::HashSet;

use ratatui::{
    prelude::*,
    widgets::{Block, Borders, List, ListItem, ListState},
};

use crate::daemon::tui::app::{App, ViewMode};

/// Style for matched characters in search results
const MATCH_HIGHLIGHT_COLOR: Color = Color::Yellow;
const MATCH_HIGHLIGHT_MODIFIER: Modifier = Modifier::BOLD;

/// Build a Line with highlighted characters based on matched indices
fn build_highlighted_name(name: &str, matched_indices: &[usize]) -> Vec<Span<'static>> {
    if matched_indices.is_empty() {
        return vec![Span::raw(name.to_string())];
    }

    let matched_set: HashSet<usize> = matched_indices.iter().cloned().collect();
    let mut spans = Vec::new();
    let mut current_run = String::new();
    let mut is_highlighted = false;

    for (byte_idx, ch) in name.char_indices() {
        let should_highlight = matched_set.contains(&byte_idx);

        if should_highlight != is_highlighted {
            // Flush current run
            if !current_run.is_empty() {
                if is_highlighted {
                    spans.push(Span::styled(
                        current_run.clone(),
                        Style::default()
                            .fg(MATCH_HIGHLIGHT_COLOR)
                            .add_modifier(MATCH_HIGHLIGHT_MODIFIER),
                    ));
                } else {
                    spans.push(Span::raw(current_run.clone()));
                }
                current_run.clear();
            }
            is_highlighted = should_highlight;
        }

        current_run.push(ch);
    }

    // Flush remaining
    if !current_run.is_empty() {
        if is_highlighted {
            spans.push(Span::styled(
                current_run,
                Style::default()
                    .fg(MATCH_HIGHLIGHT_COLOR)
                    .add_modifier(MATCH_HIGHLIGHT_MODIFIER),
            ));
        } else {
            spans.push(Span::raw(current_run));
        }
    }

    spans
}

/// Get status icon and color for an item
fn get_status_display(status: Option<&str>) -> (&'static str, Color) {
    match status {
        Some("running") => ("▸", Color::Green),
        Some("done") => ("✓", Color::Blue),
        Some("failed") => ("✗", Color::Red),
        Some("pending") => ("○", Color::Yellow),
        Some("paused") => ("⏸", Color::Cyan),
        _ => (" ", Color::Gray),
    }
}

pub fn render(f: &mut Frame, area: Rect, app: &mut App) {
    let items: Vec<ListItem> = app
        .filtered_items
        .iter()
        .map(|filtered_item| {
            let item = &app.items[filtered_item.index];
            let (status_icon, status_color) = get_status_display(item.status.as_deref());

            // Build spans with highlighted matched characters
            let mut spans = vec![Span::styled(
                format!("{} ", status_icon),
                Style::default().fg(status_color),
            )];

            // Add name with match highlighting
            spans.extend(build_highlighted_name(&item.name, &filtered_item.matched_indices));

            ListItem::new(Line::from(spans))
        })
        .collect();

    let view_label = match app.view_mode {
        ViewMode::Tasks => "Tasks",
        ViewMode::Contracts => "Contracts",
        ViewMode::Files => "Files",
    };

    let title = format!(
        " {} ({}{}) ",
        view_label,
        app.filtered_items.len(),
        if app.filtered_items.len() != app.items.len() {
            format!("/{}", app.items.len())
        } else {
            String::new()
        }
    );

    let list = List::new(items)
        .block(Block::default().title(title).borders(Borders::ALL))
        .highlight_style(Style::default().add_modifier(Modifier::REVERSED))
        .highlight_symbol("> ");

    let mut state = ListState::default();
    state.select(Some(app.selected_index));

    f.render_stateful_widget(list, area, &mut state);
}
