use super::*;

#[test]
fn test_extract_visible_spans_no_scroll() {
    let spans = vec![
        Span::styled("Hello", Style::default().fg(Color::Red)),
        Span::styled(" ", Style::default()),
        Span::styled("World", Style::default().fg(Color::Blue)),
    ];

    let visible = extract_visible_spans(&spans, 0, 20);

    assert_eq!(visible.len(), 3);
    assert_eq!(visible[0].content, "Hello");
    assert_eq!(visible[2].content, "World");
}

#[test]
fn test_extract_visible_spans_with_scroll() {
    let spans = vec![
        Span::styled("0123456789", Style::default().fg(Color::Red)),
        Span::styled("ABCDEFGHIJ", Style::default().fg(Color::Blue)),
    ];

    let visible = extract_visible_spans(&spans, 5, 10);

    assert_eq!(visible.len(), 2);
    assert_eq!(visible[0].content, "56789");
    assert_eq!(visible[1].content, "ABCDE");
}

#[test]
fn test_extract_visible_spans_beyond_text() {
    let spans = vec![Span::styled("Short", Style::default())];

    let visible = extract_visible_spans(&spans, 10, 20);

    assert_eq!(visible.len(), 0);
}

#[test]
fn test_insert_cursor_at_start() {
    let spans = vec![Span::styled("Hello", Style::default().fg(Color::Red))];

    let result = insert_cursor_into_spans(spans, 0);

    assert_eq!(result.len(), 2);
    assert_eq!(result[0].content, "H");
    assert!(result[0].style.add_modifier.contains(Modifier::REVERSED));
    assert_eq!(result[1].content, "ello");
}

#[test]
fn test_insert_cursor_in_middle() {
    let spans = vec![Span::styled("Hello", Style::default().fg(Color::Red))];

    let result = insert_cursor_into_spans(spans, 2);

    assert_eq!(result.len(), 3);
    assert_eq!(result[0].content, "He");
    assert_eq!(result[1].content, "l");
    assert!(result[1].style.add_modifier.contains(Modifier::REVERSED));
    assert_eq!(result[2].content, "lo");
}

#[test]
fn test_insert_cursor_at_end() {
    let spans = vec![Span::styled("Hi", Style::default().fg(Color::Red))];

    let result = insert_cursor_into_spans(spans, 2);

    assert_eq!(result.len(), 2);
    assert_eq!(result[0].content, "Hi");
    assert_eq!(result[1].content, " ");
    assert!(result[1].style.add_modifier.contains(Modifier::REVERSED));
}

#[test]
fn test_insert_cursor_across_spans() {
    let spans = vec![
        Span::styled("Hello", Style::default().fg(Color::Red)),
        Span::styled("World", Style::default().fg(Color::Blue)),
    ];

    let result = insert_cursor_into_spans(spans, 5);

    assert!(result.len() >= 2);
    assert_eq!(result[0].content, "Hello");
    assert_eq!(result[1].content, "W");
    assert!(result[1].style.add_modifier.contains(Modifier::REVERSED));
}

#[test]
fn test_insert_cursor_empty_spans() {
    let spans = vec![];

    let result = insert_cursor_into_spans(spans, 0);

    assert_eq!(result.len(), 1);
    assert_eq!(result[0].content, " ");
    assert!(result[0].style.add_modifier.contains(Modifier::REVERSED));
}

#[test]
fn test_extract_visible_spans_unicode() {
    let spans = vec![Span::styled("Hello👋World", Style::default())];

    let visible = extract_visible_spans(&spans, 3, 5);

    assert_eq!(visible.len(), 1);
    assert_eq!(visible[0].content, "lo👋Wo");
}

#[test]
fn test_highlight_bracket_pairs_simple() {
    let spans = vec![Span::styled("map(.)", Style::default().fg(Color::Magenta))];

    let result = highlight_bracket_pairs(spans, (3, 5));

    assert_eq!(result[0].content, "map");
    assert_eq!(result[1].content, "(");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, ".");
    assert_eq!(result[3].content, ")");
    assert!(result[3].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_across_spans() {
    let spans = vec![
        Span::styled("map", Style::default().fg(Color::Blue)),
        Span::styled("(", Style::default().fg(Color::Magenta)),
        Span::styled(".", Style::default()),
        Span::styled(")", Style::default().fg(Color::Magenta)),
    ];

    let result = highlight_bracket_pairs(spans, (3, 5));

    assert_eq!(result[0].content, "map");
    assert_eq!(result[1].content, "(");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, ".");
    assert_eq!(result[3].content, ")");
    assert!(result[3].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_at_start() {
    let spans = vec![Span::styled("(.)", Style::default())];

    let result = highlight_bracket_pairs(spans, (0, 2));

    assert_eq!(result[0].content, "(");
    assert!(result[0].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[1].content, ".");
    assert_eq!(result[2].content, ")");
    assert!(result[2].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_at_end() {
    let spans = vec![Span::styled("test()", Style::default())];

    let result = highlight_bracket_pairs(spans, (4, 5));

    assert_eq!(result[0].content, "test");
    assert_eq!(result[1].content, "(");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, ")");
    assert!(result[2].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_nested() {
    let spans = vec![Span::styled("map(select(.))", Style::default())];

    let result = highlight_bracket_pairs(spans, (3, 13));

    assert_eq!(result[0].content, "map");
    assert_eq!(result[1].content, "(");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, "select(.)");
    assert_eq!(result[3].content, ")");
    assert!(result[3].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_preserves_existing_style() {
    let spans = vec![Span::styled(
        "map(.)",
        Style::default()
            .fg(Color::Blue)
            .add_modifier(Modifier::BOLD),
    )];

    let result = highlight_bracket_pairs(spans, (3, 5));

    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert!(result[1].style.add_modifier.contains(Modifier::BOLD));
    assert_eq!(result[1].style.fg, Some(Color::Blue));
}

#[test]
fn test_highlight_bracket_pairs_square_brackets() {
    let spans = vec![Span::styled(".items[]", Style::default())];

    let result = highlight_bracket_pairs(spans, (6, 7));

    assert_eq!(result[0].content, ".items");
    assert_eq!(result[1].content, "[");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, "]");
    assert!(result[2].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_curly_braces() {
    let spans = vec![Span::styled("{name}", Style::default())];

    let result = highlight_bracket_pairs(spans, (0, 5));

    assert_eq!(result[0].content, "{");
    assert!(result[0].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[1].content, "name");
    assert_eq!(result[2].content, "}");
    assert!(result[2].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_adjacent_characters() {
    let spans = vec![Span::styled("()", Style::default())];

    let result = highlight_bracket_pairs(spans, (0, 1));

    assert_eq!(result[0].content, "(");
    assert!(result[0].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[1].content, ")");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_highlight_bracket_pairs_multiple_spans_complex() {
    let spans = vec![
        Span::styled("map", Style::default().fg(Color::Blue)),
        Span::styled("(", Style::default().fg(Color::Magenta)),
        Span::styled("select", Style::default().fg(Color::Blue)),
        Span::styled("(", Style::default().fg(Color::Magenta)),
        Span::styled(".", Style::default()),
        Span::styled(")", Style::default().fg(Color::Magenta)),
        Span::styled(")", Style::default().fg(Color::Magenta)),
    ];

    let result = highlight_bracket_pairs(spans, (3, 13));

    let mut found_first_underlined = false;
    let mut found_second_underlined = false;

    for span in &result {
        if span.content == "("
            && span.style.add_modifier.contains(Modifier::UNDERLINED)
            && !found_first_underlined
        {
            found_first_underlined = true;
        }
        if span.content == ")" {
            let underlined_closing_count = result
                .iter()
                .filter(|s| s.content == ")" && s.style.add_modifier.contains(Modifier::UNDERLINED))
                .count();
            if underlined_closing_count > 0 {
                found_second_underlined = true;
            }
        }
    }

    assert!(found_first_underlined);
    assert!(found_second_underlined);
}

#[test]
fn test_highlight_bracket_pairs_unicode_content() {
    let spans = vec![Span::styled("test(👋)", Style::default())];

    let result = highlight_bracket_pairs(spans, (4, 6));

    assert_eq!(result[0].content, "test");
    assert_eq!(result[1].content, "(");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, "👋");
    assert_eq!(result[3].content, ")");
    assert!(result[3].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_apply_modifier_at_positions_empty_positions() {
    let spans = vec![Span::styled("test", Style::default())];

    let result = super::apply_modifier_at_positions(spans.clone(), &[], Modifier::UNDERLINED);

    assert_eq!(result, spans);
}

#[test]
fn test_apply_modifier_at_positions_single_position() {
    let spans = vec![Span::styled("test", Style::default())];

    let result = super::apply_modifier_at_positions(spans, &[1], Modifier::UNDERLINED);

    assert_eq!(result[0].content, "t");
    assert_eq!(result[1].content, "e");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, "st");
}

#[test]
fn test_apply_modifier_at_positions_multiple_positions_same_span() {
    let spans = vec![Span::styled("test", Style::default())];

    let result = super::apply_modifier_at_positions(spans, &[0, 3], Modifier::UNDERLINED);

    assert_eq!(result[0].content, "t");
    assert!(result[0].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[1].content, "es");
    assert_eq!(result[2].content, "t");
    assert!(result[2].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_apply_modifier_at_positions_across_multiple_spans() {
    let spans = vec![
        Span::styled("ab", Style::default()),
        Span::styled("cd", Style::default()),
    ];

    let result = super::apply_modifier_at_positions(spans, &[1, 2], Modifier::BOLD);

    assert_eq!(result[0].content, "a");
    assert_eq!(result[1].content, "b");
    assert!(result[1].style.add_modifier.contains(Modifier::BOLD));
    assert_eq!(result[2].content, "c");
    assert!(result[2].style.add_modifier.contains(Modifier::BOLD));
    assert_eq!(result[3].content, "d");
}

#[test]
fn test_apply_modifier_at_positions_out_of_range() {
    let spans = vec![Span::styled("test", Style::default())];

    let result = super::apply_modifier_at_positions(spans.clone(), &[10, 20], Modifier::UNDERLINED);

    assert_eq!(result, spans);
}

#[test]
fn test_apply_modifier_at_positions_unsorted_positions() {
    let spans = vec![Span::styled("abcd", Style::default())];

    let result = super::apply_modifier_at_positions(spans, &[3, 1, 2], Modifier::UNDERLINED);

    assert_eq!(result[0].content, "a");
    assert_eq!(result[1].content, "b");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, "c");
    assert!(result[2].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[3].content, "d");
    assert!(result[3].style.add_modifier.contains(Modifier::UNDERLINED));
}

#[test]
fn test_apply_modifier_at_positions_consecutive_positions() {
    let spans = vec![Span::styled("abcd", Style::default())];

    let result = super::apply_modifier_at_positions(spans, &[1, 2], Modifier::UNDERLINED);

    assert_eq!(result[0].content, "a");
    assert_eq!(result[1].content, "b");
    assert!(result[1].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[2].content, "c");
    assert!(result[2].style.add_modifier.contains(Modifier::UNDERLINED));
    assert_eq!(result[3].content, "d");
}
