// src/textarea/highlight/chunks.rs
use ratatui::text::{Line, Span};
use ratatui::style::Style;
use unicode_width::UnicodeWidthChar;

#[derive(Debug, Clone)]
pub struct StyledChunk {
    pub text: String,
    pub style: Style,
}

pub fn display_width_chunks(chunks: &[StyledChunk]) -> u16 {
    chunks
        .iter()
        .map(|c| {
            c.text
                .chars()
                .map(|ch| UnicodeWidthChar::width(ch).unwrap_or(0) as u16)
                .sum::<u16>()
        })
        .sum()
}

pub fn slice_chunks_by_display_cols(
    chunks: &[StyledChunk],
    start_cols: u16,
    max_cols: u16,
) -> Vec<StyledChunk> {
    if max_cols == 0 {
        return Vec::new();
    }

    let mut skipped: u16 = 0;
    let mut taken: u16 = 0;
    let mut out: Vec<StyledChunk> = Vec::new();

    for ch in chunks {
        if taken >= max_cols {
            break;
        }

        let mut acc = String::new();

        for c in ch.text.chars() {
            let w = UnicodeWidthChar::width(c).unwrap_or(0) as u16;
            if skipped + w <= start_cols {
                skipped += w;
                continue;
            }
            if taken + w > max_cols {
                break;
            }
            acc.push(c);
            taken = taken.saturating_add(w);
            if taken >= max_cols {
                break;
            }
        }

        if !acc.is_empty() {
            out.push(StyledChunk {
                text: acc,
                style: ch.style,
            });
        }
    }

    out
}

pub fn clip_chunks_window_with_indicator_padded(
    chunks: &[StyledChunk],
    view_width: u16,
    indicator: char,
    start_cols: u16,
) -> Line<'static> {
    if view_width == 0 {
        return Line::from("");
    }

    let total = display_width_chunks(chunks);
    let show_left = start_cols > 0;
    let left_cols: u16 = if show_left { 1 } else { 0 };

    let cap_with_right = view_width.saturating_sub(left_cols + 1);
    let remaining = total.saturating_sub(start_cols);
    let show_right = remaining > cap_with_right;

    let max_visible = if show_right {
        cap_with_right
    } else {
        view_width.saturating_sub(left_cols)
    };

    let visible = slice_chunks_by_display_cols(chunks, start_cols, max_visible);
    let used_cols = left_cols + display_width_chunks(&visible);

    let mut spans: Vec<Span> = Vec::new();
    if show_left {
        spans.push(Span::raw(indicator.to_string()));
    }
    for v in visible {
        spans.push(Span::styled(v.text, v.style));
    }
    if show_right {
        let right_pos = view_width.saturating_sub(1);
        let filler = right_pos.saturating_sub(used_cols);
        if filler > 0 {
            spans.push(Span::raw(" ".repeat(filler as usize)));
        }
        spans.push(Span::raw(indicator.to_string()));
    }

    Line::from(spans)
}

pub fn wrap_chunks_indented(
    chunks: &[StyledChunk],
    width: u16,
    indent: u16,
) -> Vec<Line<'static>> {
    if width == 0 {
        return vec![Line::from("")];
    }
    let indent = indent.min(width.saturating_sub(1));
    let cont_cap = width.saturating_sub(indent);
    let indent_str = " ".repeat(indent as usize);

    let mut lines: Vec<Line> = Vec::new();
    let mut current_spans: Vec<Span> = Vec::new();
    let mut used: u16 = 0;
    let mut first_line = true;

    // Fixed: Restructure to avoid borrow checker issues
    for chunk in chunks {
        let mut buf = String::new();
        let mut buf_style = chunk.style;

        for ch in chunk.text.chars() {
            let w = UnicodeWidthChar::width(ch).unwrap_or(0) as u16;
            let cap = if first_line { width } else { cont_cap };

            if used > 0 && used.saturating_add(w) >= cap {
                if !buf.is_empty() {
                    current_spans.push(Span::styled(buf.clone(), buf_style));
                    buf.clear();
                }
                lines.push(Line::from(current_spans));
                current_spans = Vec::new();
                first_line = false;
                used = 0;
                
                // Add indent directly instead of using closure
                if !first_line && indent > 0 {
                    current_spans.push(Span::raw(indent_str.clone()));
                    used = indent;
                }
            }

            if !buf.is_empty() && buf_style != chunk.style {
                current_spans.push(Span::styled(buf.clone(), buf_style));
                buf.clear();
            }
            buf_style = chunk.style;
            
            // Add indent if needed
            if used == 0 && !first_line && indent > 0 {
                current_spans.push(Span::raw(indent_str.clone()));
                used = indent;
            }
            
            buf.push(ch);
            used = used.saturating_add(w);
        }

        if !buf.is_empty() {
            current_spans.push(Span::styled(buf, buf_style));
        }
    }

    lines.push(Line::from(current_spans));
    lines
}
