import unittest
from unittest import mock

from doc2md import ocr as ocr_mod


class OcrParseTest(unittest.TestCase):
    def test_ocr_parse_predict_shape_v3(self) -> None:
        result = [
            {
                "ocr_result": [
                    {
                        "bbox": [[0, 0], [10, 0], [10, 10], [0, 10]],
                        "text": "Hola",
                        "score": 0.9,
                    }
                ]
            }
        ]

        pages = ocr_mod._parse_ocr_result(result)

        self.assertEqual(len(pages), 1)
        self.assertEqual(len(pages[0]), 1)
        self.assertEqual(pages[0][0].text, "Hola")
        self.assertAlmostEqual(pages[0][0].score, 0.9, places=3)

    def test_ocr_parse_ocr_shape_v2_compat(self) -> None:
        result = [
            [
                [[[0, 0], [10, 0], [10, 10], [0, 10]], ("Hello", 0.8)],
                [[[20, 0], [30, 0], [30, 10], [20, 10]], ("World", 0.7)],
            ]
        ]

        pages = ocr_mod._parse_ocr_result(result)

        self.assertEqual([line.text for line in pages[0]], ["Hello", "World"])


class OcrOrderingTest(unittest.TestCase):
    def test_ocr_ordering_stable_rows_then_columns(self) -> None:
        lines = [
            ocr_mod.OcrLine(
                text="B",
                score=0.9,
                bbox=[[10, 0], [20, 0], [20, 10], [10, 10]],
            ),
            ocr_mod.OcrLine(
                text="A",
                score=0.9,
                bbox=[[0, 0], [9, 0], [9, 10], [0, 10]],
            ),
            ocr_mod.OcrLine(
                text="D",
                score=0.9,
                bbox=[[10, 20], [20, 20], [20, 30], [10, 30]],
            ),
            ocr_mod.OcrLine(
                text="C",
                score=0.9,
                bbox=[[0, 20], [9, 20], [9, 30], [0, 30]],
            ),
        ]

        ordered = ocr_mod._order_lines(lines)

        self.assertEqual([line.text for line in ordered], ["A", "B", "C", "D"])

    def test_ocr_pages_to_text_filters_by_score(self) -> None:
        pages = [
            [
                ocr_mod.OcrLine(
                    text="High",
                    score=0.9,
                    bbox=[[0, 0], [1, 0], [1, 1], [0, 1]],
                ),
                ocr_mod.OcrLine(
                    text="Low",
                    score=0.1,
                    bbox=[[0, 10], [1, 10], [1, 11], [0, 11]],
                ),
            ]
        ]

        text = ocr_mod._pages_to_text(pages, min_score=0.5)

        self.assertEqual(text.strip(), "High")

    def test_ocr_engine_cached_by_config(self) -> None:
        class DummyOCR:
            init_count = 0

            def __init__(self, **_kwargs):
                DummyOCR.init_count += 1

        ocr_mod._OCR_CACHE.clear()
        with mock.patch("doc2md.ocr._load_paddleocr", return_value=DummyOCR):
            first = ocr_mod._get_ocr_engine(
                lang="es",
                ocr_version="PP-OCRv5",
                device=None,
            )
            second = ocr_mod._get_ocr_engine(
                lang="es",
                ocr_version="PP-OCRv5",
                device=None,
            )
        self.assertIs(first, second)
        self.assertEqual(DummyOCR.init_count, 1)


if __name__ == "__main__":
    unittest.main()
