use flate2::read::ZlibDecoder;
use pdfmake_rust::{
    Document, DocumentNode, ListNode, OrderedMarkerType, PdfMake, UnorderedMarkerType,
};
use std::io::Read;

fn decompress_pdf_content(pdf: &[u8]) -> String {
    let mut result = String::new();
    let mut pos = 0usize;
    while let Some(stream_start) = pdf[pos..]
        .windows(8)
        .position(|w| w == b"\nstream\n" || w == b"\rstream\n")
    {
        let abs_start = pos + stream_start;
        let data_start = abs_start + 8;
        let remaining = &pdf[data_start..];
        let end_marker_pos = remaining
            .windows(10)
            .position(|w| w == b"\nendstream" || w == b"\rendstream");
        let data_end = match end_marker_pos {
            Some(p) => data_start + p,
            None => data_start + remaining.len(),
        };
        if data_end > data_start {
            let compressed = &pdf[data_start..data_end];
            let mut decoder = ZlibDecoder::new(compressed);
            let mut decompressed = String::new();
            if decoder.read_to_string(&mut decompressed).is_ok() {
                if !decompressed.is_empty() {
                    result.push_str(&decompressed);
                }
            }
        }
        pos = data_end + 10;
    }
    result
}

#[test]
fn ordered_list_lower_alpha_renders() {
    let document = Document::builder()
        .content(DocumentNode::list(
            ListNode::ordered(vec![
                DocumentNode::text("first"),
                DocumentNode::text("second"),
                DocumentNode::text("third"),
            ])
            .marker_type("lower-alpha"),
        ))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    let content = decompress_pdf_content(&pdf);
    assert!(
        content.contains("(a. )"),
        "Should contain 'a.' marker, got: {}",
        content
    );
    assert!(
        content.contains("(b. )"),
        "Should contain 'b.' marker"
    );
    assert!(
        content.contains("(c. )"),
        "Should contain 'c.' marker"
    );
}

#[test]
fn ordered_list_upper_alpha_renders() {
    let document = Document::builder()
        .content(DocumentNode::list(
            ListNode::ordered(vec![
                DocumentNode::text("first"),
                DocumentNode::text("second"),
            ])
            .marker_type("upper-alpha"),
        ))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    let content = decompress_pdf_content(&pdf);
    assert!(
        content.contains("(A. )"),
        "Should contain 'A.' marker, got: {}",
        content
    );
    assert!(
        content.contains("(B. )"),
        "Should contain 'B.' marker"
    );
}

#[test]
fn ordered_list_lower_roman_renders() {
    let document = Document::builder()
        .content(DocumentNode::list(
            ListNode::ordered(vec![
                DocumentNode::text("one"),
                DocumentNode::text("two"),
                DocumentNode::text("three"),
            ])
            .marker_type("lower-roman"),
        ))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    let content = decompress_pdf_content(&pdf);
    assert!(
        content.contains("(i. )"),
        "Should contain 'i.' marker, got: {}",
        content
    );
    assert!(
        content.contains("(ii. )"),
        "Should contain 'ii.' marker"
    );
    assert!(
        content.contains("(iii. )"),
        "Should contain 'iii.' marker"
    );
}

#[test]
fn ordered_list_upper_roman_renders() {
    let document = Document::builder()
        .content(DocumentNode::list(
            ListNode::ordered(vec![
                DocumentNode::text("one"),
                DocumentNode::text("two"),
            ])
            .marker_type("upper-roman"),
        ))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    let content = decompress_pdf_content(&pdf);
    assert!(
        content.contains("(I. )"),
        "Should contain 'I.' marker, got: {}",
        content
    );
    assert!(
        content.contains("(II. )"),
        "Should contain 'II.' marker"
    );
}

#[test]
fn ordered_type_enum_works() {
    let list = ListNode::ordered(vec![DocumentNode::text("item")])
        .ordered_type(OrderedMarkerType::LowerAlpha);
    assert_eq!(list.marker_type, Some("lower-alpha".to_string()));
    assert!(list.ordered);
}

#[test]
fn unordered_type_enum_disc_works() {
    let list = ListNode::unordered(vec![DocumentNode::text("item")])
        .unordered_type(UnorderedMarkerType::Disc);
    assert_eq!(list.marker_type, Some("disc".to_string()));
    assert!(!list.ordered);
}

#[test]
fn unordered_type_enum_circle_works() {
    let list = ListNode::unordered(vec![DocumentNode::text("item")])
        .unordered_type(UnorderedMarkerType::Circle);
    assert_eq!(list.marker_type, Some("circle".to_string()));
}

#[test]
fn unordered_type_enum_square_works() {
    let list = ListNode::unordered(vec![DocumentNode::text("item")])
        .unordered_type(UnorderedMarkerType::Square);
    assert_eq!(list.marker_type, Some("square".to_string()));
}

#[test]
fn unordered_type_enum_none_works() {
    let list = ListNode::unordered(vec![DocumentNode::text("item")])
        .unordered_type(UnorderedMarkerType::None);
    assert_eq!(list.marker_type, Some("none".to_string()));
}

#[test]
fn list_marker_color_builder_works() {
    let list = ListNode::unordered(vec![DocumentNode::text("item")]).color("red");
    assert_eq!(list.color, Some("red".to_string()));
}

#[test]
fn circle_marker_renders_without_crash() {
    let document = Document::builder()
        .content(DocumentNode::list(
            ListNode::unordered(vec![
                DocumentNode::text("circle one"),
                DocumentNode::text("circle two"),
            ])
            .unordered_type(UnorderedMarkerType::Circle),
        ))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    assert!(pdf.starts_with(b"%PDF"));
    let content = decompress_pdf_content(&pdf);
    assert!(
        content.contains("circle one"),
        "PDF should contain list text"
    );
}

#[test]
fn square_marker_renders_without_crash() {
    let document = Document::builder()
        .content(DocumentNode::list(
            ListNode::unordered(vec![
                DocumentNode::text("square one"),
                DocumentNode::text("square two"),
            ])
            .unordered_type(UnorderedMarkerType::Square),
        ))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    assert!(pdf.starts_with(b"%PDF"));
    let content = decompress_pdf_content(&pdf);
    assert!(
        content.contains("square one"),
        "PDF should contain list text"
    );
}

#[test]
fn list_with_color_renders_without_crash() {
    let document = Document::builder()
        .content(DocumentNode::list(
            ListNode::unordered(vec![
                DocumentNode::text("colored item"),
            ])
            .color("blue"),
        ))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    assert!(pdf.starts_with(b"%PDF"));
}

#[test]
fn all_ordered_marker_types_render() {
    for marker_type in &[
        OrderedMarkerType::Decimal,
        OrderedMarkerType::LowerAlpha,
        OrderedMarkerType::UpperAlpha,
        OrderedMarkerType::LowerRoman,
        OrderedMarkerType::UpperRoman,
    ] {
        let document = Document::builder()
            .content(DocumentNode::list(
                ListNode::ordered(vec![
                    DocumentNode::text("item one"),
                    DocumentNode::text("item two"),
                ])
                .ordered_type(*marker_type),
            ))
            .build();

        let pdf = PdfMake::new().render(&document).unwrap();
        assert!(
            pdf.starts_with(b"%PDF"),
            "Failed for marker type {:?}",
            marker_type
        );
    }
}

#[test]
fn all_unordered_marker_types_render() {
    for marker_type in &[
        UnorderedMarkerType::Disc,
        UnorderedMarkerType::Circle,
        UnorderedMarkerType::Square,
    ] {
        let document = Document::builder()
            .content(DocumentNode::list(
                ListNode::unordered(vec![
                    DocumentNode::text("item one"),
                    DocumentNode::text("item two"),
                ])
                .unordered_type(*marker_type),
            ))
            .build();

        let pdf = PdfMake::new().render(&document).unwrap();
        assert!(
            pdf.starts_with(b"%PDF"),
            "Failed for marker type {:?}",
            marker_type
        );
    }
}
