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

/// Extracts and decompresses all FlateDecode content streams from a PDF byte vector.
/// Returns the concatenated decompressed content from all streams.
fn decompress_pdf_content(pdf: &[u8]) -> String {
    let mut result = String::new();
    let mut pos = 0usize;
    // Search for "stream\n" markers that follow "/Filter /FlateDecode"
    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; // after "\nstream\n"

        // Find the corresponding "endstream"
        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; // move past "endstream"
    }
    result
}

#[test]
fn unordered_list_renders_pdf() {
    let document = Document::builder()
        .content(DocumentNode::list(ListNode::unordered(vec![
            DocumentNode::text("first item"),
            DocumentNode::text("second item"),
            DocumentNode::text("third item"),
        ])))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();

    // Should be a valid PDF
    assert!(pdf.starts_with(b"%PDF"), "Output should start with PDF header");

    // Decompress content stream and check text
    let content = decompress_pdf_content(&pdf);
    assert!(content.contains("first item"), "PDF should contain 'first item', got: {}", content);
    assert!(content.contains("second item"), "PDF should contain 'second item'");
}

#[test]
fn ordered_list_renders_pdf() {
    let document = Document::builder()
        .content(DocumentNode::list(ListNode::ordered(vec![
            DocumentNode::text("alpha"),
            DocumentNode::text("beta"),
            DocumentNode::text("gamma"),
        ])))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    let content = decompress_pdf_content(&pdf);

    assert!(content.contains("alpha"), "PDF should contain 'alpha', got: {}", content);
    assert!(content.contains("(1. )"), "PDF should contain '(1. )' counter, got: {}", content);
    assert!(content.contains("(2. )"), "PDF should contain '(2. )' counter, got: {}", content);
    assert!(content.contains("(3. )"), "PDF should contain '(3. )' counter, got: {}", content);
}

#[test]
fn list_with_stack_items_renders() {
    let document = Document::builder()
        .content(DocumentNode::list(ListNode::unordered(vec![
            DocumentNode::stack(vec![
                DocumentNode::text("line one"),
                DocumentNode::text("line two"),
            ]),
            DocumentNode::text("simple item"),
        ])))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    let content = decompress_pdf_content(&pdf);

    assert!(content.contains("line one"), "PDF should contain 'line one', got: {}", content);
    assert!(content.contains("line two"), "PDF should contain 'line two', got: {}", content);
    assert!(content.contains("simple item"), "PDF should contain 'simple item', got: {}", content);
}

#[test]
fn ordered_list_with_start() {
    let document = Document::builder()
        .content(DocumentNode::list(ListNode::ordered(vec![
            DocumentNode::text("first"),
            DocumentNode::text("second"),
        ]).start(5)))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    let content = decompress_pdf_content(&pdf);

    assert!(content.contains("(5. )"), "PDF should contain '(5. )', got: {}", content);
    assert!(content.contains("(6. )"), "PDF should contain '(6. )', got: {}", content);
}

#[test]
fn empty_list_renders_without_crash() {
    let document = Document::builder()
        .content(DocumentNode::list(ListNode::unordered(vec![])))
        .content(DocumentNode::text("after list"))
        .build();

    let pdf = PdfMake::new().render(&document).unwrap();
    assert!(pdf.len() > 0);
}
