"""Tests for scripts/reading_order.py — struct-tree reading-order extraction.

CI-light: pure pikepdf fixtures built in-memory, no vendored ODL/java/verapdf.
"""
import os
import sys

import pikepdf

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))

import reading_order as ro  # noqa: E402


def _struct_elem(pdf, **kw):
    return pdf.make_indirect(pikepdf.Dictionary(Type=pikepdf.Name.StructElem, **kw))


def _two_page_tagged_pdf():
    """page 1: MCID0 'Hello', MCID1 'World'; page 2: MCID0 'Foo'. Struct
    order (document order) is Hello, World, Foo — not sorted by MCID."""
    pdf = pikepdf.new()
    page1 = pdf.add_blank_page(page_size=(200, 200))
    page1.Contents = pdf.make_stream(
        b"/P <</MCID 0>> BDC BT (Hello) Tj ET EMC\n"
        b"/Span <</MCID 1>> BDC BT (World) Tj ET EMC\n")

    page2 = pdf.add_blank_page(page_size=(200, 200))
    page2.Contents = pdf.make_stream(b"/P <</MCID 0>> BDC BT (Foo) Tj ET EMC\n")

    p1a = _struct_elem(pdf, S=pikepdf.Name.P, Pg=page1.obj, K=0)
    p1b = _struct_elem(pdf, S=pikepdf.Name.Span, Pg=page1.obj, K=1)
    p2a = _struct_elem(pdf, S=pikepdf.Name.P, Pg=page2.obj, K=0)
    doc = _struct_elem(pdf, S=pikepdf.Name.Document, K=[p1a, p1b, p2a])
    pdf.Root.StructTreeRoot = pdf.make_indirect(
        pikepdf.Dictionary(Type=pikepdf.Name.StructTreeRoot, K=[doc]))
    return pdf


def test_struct_order_text_is_document_order(tmp_path):
    pdf = _two_page_tagged_pdf()
    p = tmp_path / "t.pdf"
    pdf.save(p)
    assert ro.struct_order_text(p) == ["Hello", "World", "Foo"]


def test_struct_order_runs_page_and_mcid_identity(tmp_path):
    pdf = _two_page_tagged_pdf()
    p = tmp_path / "t.pdf"
    pdf.save(p)
    assert ro.struct_order_runs(p) == [(1, 0, "Hello"), (1, 1, "World"), (2, 0, "Foo")]


def test_accepts_already_open_pdf_object_no_disk_roundtrip():
    pdf = _two_page_tagged_pdf()
    assert ro.struct_order_text(pdf) == ["Hello", "World", "Foo"]


def test_untagged_pdf_returns_empty_list():
    pdf = pikepdf.new()
    pdf.add_blank_page(page_size=(200, 200))
    assert ro.struct_order_text(pdf) == []
    assert ro.struct_order_runs(pdf) == []


def test_cycle_does_not_hang():
    pdf = _two_page_tagged_pdf()
    doc = pdf.Root.StructTreeRoot.K[0]
    p1a = doc.K[0]
    p1a["/K"] = pikepdf.Array([doc])  # cycle: doc -> p1a -> doc
    runs = ro.struct_order_runs(pdf)  # must terminate, not hang or raise
    assert isinstance(runs, list)


def test_whitespace_only_runs_are_skipped():
    pdf = pikepdf.new()
    page = pdf.add_blank_page(page_size=(200, 200))
    page.Contents = pdf.make_stream(
        b"/P <</MCID 0>> BDC BT (   ) Tj ET EMC\n"
        b"/Span <</MCID 1>> BDC BT (Real) Tj ET EMC\n")
    p0 = _struct_elem(pdf, S=pikepdf.Name.P, Pg=page.obj, K=0)
    p1 = _struct_elem(pdf, S=pikepdf.Name.Span, Pg=page.obj, K=1)
    doc = _struct_elem(pdf, S=pikepdf.Name.Document, K=[p0, p1])
    pdf.Root.StructTreeRoot = pdf.make_indirect(
        pikepdf.Dictionary(Type=pikepdf.Name.StructTreeRoot, K=[doc]))
    assert ro.struct_order_text(pdf) == ["Real"]


def test_unopenable_path_returns_empty_not_raise(tmp_path):
    assert ro.struct_order_text(str(tmp_path / "nope.pdf")) == []
    assert ro.struct_order_runs(str(tmp_path / "nope.pdf")) == []


def test_cli_file_mode_prints_run_count(tmp_path, capsys, monkeypatch):
    pdf = _two_page_tagged_pdf()
    p = tmp_path / "t.pdf"
    pdf.save(p)
    monkeypatch.setattr(sys, "argv", ["reading_order.py", str(p), "2"])
    assert ro.main() == 0
    out = capsys.readouterr().out
    assert "3 struct-order text runs" in out


def test_cli_diff_mode_prints_similarity_ratio(tmp_path, capsys, monkeypatch):
    pdf_before = _two_page_tagged_pdf()
    before_path = tmp_path / "before.pdf"
    pdf_before.save(before_path)

    pdf_after = _two_page_tagged_pdf()
    doc = pdf_after.Root.StructTreeRoot.K[0]
    doc.K[0]["/K"] = 99  # break MCID0 on page 1 -> "Hello" text disappears
    after_path = tmp_path / "after.pdf"
    pdf_after.save(after_path)

    monkeypatch.setattr(sys, "argv",
                         ["reading_order.py", "--diff", str(before_path), str(after_path)])
    assert ro.main() == 0
    out = capsys.readouterr().out
    assert "similarity ratio:" in out
