import warnings
from pathlib import Path

import pytest
from docling_core.types.doc import (
    PictureClassificationData,
    PictureClassificationMetaField,
)

from docling.datamodel.base_models import InputFormat
from docling.datamodel.document import ConversionResult
from docling.datamodel.pipeline_options import PdfPipelineOptions
from docling.document_converter import DocumentConverter, PdfFormatOption
from docling.pipeline.standard_pdf_pipeline import StandardPdfPipeline

pytestmark = pytest.mark.ml_pdf_model


def get_converter():
    pipeline_options = PdfPipelineOptions()
    pipeline_options.generate_page_images = True

    pipeline_options.do_ocr = False
    pipeline_options.do_table_structure = False
    pipeline_options.do_code_enrichment = False
    pipeline_options.do_formula_enrichment = False
    pipeline_options.generate_picture_images = False
    pipeline_options.generate_page_images = False
    pipeline_options.do_picture_classification = True
    pipeline_options.images_scale = 2

    converter = DocumentConverter(
        format_options={
            InputFormat.PDF: PdfFormatOption(
                pipeline_cls=StandardPdfPipeline,
                pipeline_options=pipeline_options,
            )
        }
    )

    return converter


def test_picture_classifier():
    pdf_path = Path("tests/data/pdf/sources/picture_classification.pdf")
    converter = get_converter()

    print(f"converting {pdf_path}")

    doc_result: ConversionResult = converter.convert(pdf_path)

    results = doc_result.document.pictures

    assert len(results) == 2

    # Test first picture (bar chart)
    res = results[0]

    # Test old format (.annotations) - expect DeprecationWarning
    with warnings.catch_warnings(record=True) as w:
        warnings.simplefilter("always")
        assert len(res.annotations) == 1
        # Verify that a DeprecationWarning was raised
        assert len(w) == 1
        assert issubclass(w[0].category, DeprecationWarning)
        assert "annotations" in str(w[0].message).lower()

    # Now silence the deprecation warnings for the rest of the test
    with warnings.catch_warnings():
        warnings.filterwarnings(
            "ignore", category=DeprecationWarning, message=".*annotations.*"
        )

        assert isinstance(res.annotations[0], PictureClassificationData)
        classification_data = res.annotations[0]
        assert classification_data.provenance == "DocumentPictureClassifier"
        assert len(classification_data.predicted_classes) == 26, (
            "Number of predicted classes is not equal to 26"
        )
        confidences = [
            pred.confidence for pred in classification_data.predicted_classes
        ]
        assert confidences == sorted(confidences, reverse=True), (
            "Predictions are not sorted in descending order of confidence"
        )
        assert classification_data.predicted_classes[0].class_name == "bar_chart", (
            "The prediction is wrong for the bar chart image."
        )

        # Test new format (.meta.classification)
        assert res.meta is not None, "Picture meta should not be None"
        assert res.meta.classification is not None, (
            "Classification meta should not be None"
        )
        assert isinstance(res.meta.classification, PictureClassificationMetaField)
        meta_classification = res.meta.classification
        assert len(meta_classification.predictions) == 26, (
            "Number of predictions in meta is not equal to 26"
        )
        meta_confidences = [pred.confidence for pred in meta_classification.predictions]
        assert meta_confidences == sorted(meta_confidences, reverse=True), (
            "Meta predictions are not sorted in descending order of confidence"
        )
        assert meta_classification.predictions[0].class_name == "bar_chart", (
            "The meta prediction is wrong for the bar chart image."
        )
        assert (
            meta_classification.predictions[0].created_by == "DocumentPictureClassifier"
        ), "The created_by field should be DocumentPictureClassifier"

        # Test second picture (map)
        res = results[1]

        # Test old format (.annotations)
        assert len(res.annotations) == 1
        assert isinstance(res.annotations[0], PictureClassificationData)
        classification_data = res.annotations[0]
        assert classification_data.provenance == "DocumentPictureClassifier"
        assert len(classification_data.predicted_classes) == 26, (
            "Number of predicted classes is not equal to 26"
        )
        confidences = [
            pred.confidence for pred in classification_data.predicted_classes
        ]
        assert confidences == sorted(confidences, reverse=True), (
            "Predictions are not sorted in descending order of confidence"
        )
        assert (
            classification_data.predicted_classes[0].class_name == "geographical_map"
        ), "The prediction is wrong for the map image."

        # Test new format (.meta.classification)
        assert res.meta is not None, "Picture meta should not be None"
        assert res.meta.classification is not None, (
            "Classification meta should not be None"
        )
        assert isinstance(res.meta.classification, PictureClassificationMetaField)
        meta_classification = res.meta.classification
        assert len(meta_classification.predictions) == 26, (
            "Number of predictions in meta is not equal to 26"
        )
        meta_confidences = [pred.confidence for pred in meta_classification.predictions]
        assert meta_confidences == sorted(meta_confidences, reverse=True), (
            "Meta predictions are not sorted in descending order of confidence"
        )
        assert meta_classification.predictions[0].class_name == "geographical_map", (
            "The meta prediction is wrong for the map image."
        )
        assert (
            meta_classification.predictions[0].created_by == "DocumentPictureClassifier"
        ), "The created_by field should be DocumentPictureClassifier"
