"""Vision detection of footnote annotation markers in a table image.

Text/regex cannot carry superscript markers (¹²³) or image tables (no text
layer). A vision model looking at the cropped table image sees the markers
regardless. This probe crops each target table by its som_region and asks the
model for a simple answer: does the table carry footnote reference markers, and
which ones, as written. The intended home is a `footnote_refs: list[str]` field
on ExtractedTable.

Run:
    uv run python experiments/que270/footnote_ref_vision.py
"""

from __future__ import annotations

import asyncio
import glob
import json
import sys
import tempfile
from pathlib import Path
from typing import List, Tuple

import fitz
from pydantic import BaseModel, Field

sys.path.insert(0, str(Path(__file__).resolve().parent))
import footnote_finder_probe as ffp  # noqa: E402  (reuse the agent builder)

DPI = 200

# (doc-id used in strip_test_corpus dir, page, note about expectation)
# In-scope TEXT tables only — image tables are out of scope.
TARGETS = [
    ("Q1-2026-Earnings-Release_vF", 11, "superscript (1)(2) on headers — expect 1,2"),
    ("116212765", 18, "reference (1) — expect 1"),
    ("TMUS_992_Q324", 9, "operational metrics — expect NO footnote refs"),
    ("100377849", 2, "reconciliation table — mixed"),
]


class FootnoteAnnotations(BaseModel):
    has_footnotes: bool = Field(description="True if any footnote reference marker is visible in the table")
    markers: List[str] = Field(
        default_factory=list,
        description="Each distinct footnote reference marker, written as it appears (e.g. '1','2' or '(1)' or '*')",
    )


SYSTEM = """\
You are shown a cropped image of a single table from a financial document.

Some column headers or cells may carry a FOOTNOTE REFERENCE MARKER: a small
superscript or parenthetical number, letter, or symbol that points to a footnote
defined elsewhere — e.g. a superscript ¹ ² ³, a "(1)", a "*", a dagger, or a
letter "a". Report every DISTINCT marker that appears in the table, written as
you see it.

Do NOT report:
- a parenthesized NEGATIVE VALUE such as (84) or (4.7) — that is a number, not a
  marker;
- ordinary cell values, units like (%) or (£m), or the column years.

Return has_footnotes=false with an empty list if the table carries no footnote
reference markers.
"""


def _crop(tables_json: Path, page: int) -> List[Tuple[int, bytes]]:
    """Crop each table on the page by its som_region (small upward pad to catch
    superscripts). Returns (ordinal, png_bytes) per table."""
    tables = [t for t in json.loads(tables_json.read_text()) if t.get("page") == page and t.get("som_region")]
    pdf = Path(tables[0]["source"])
    doc = fitz.open(str(pdf))
    pg = doc[page - 1]
    w, h = pg.rect.width, pg.rect.height
    out = []
    zoom = DPI / 72.0
    for i, t in enumerate(tables, 1):
        x0, y0, x1, y1 = t["som_region"]
        rect = fitz.Rect(min(x0, x1) * w, max(0.0, min(y0, y1) - 0.01) * h, max(x0, x1) * w, max(y0, y1) * h)
        pix = pg.get_pixmap(matrix=fitz.Matrix(zoom, zoom), clip=rect)
        out.append((i, pix.tobytes("png")))
    doc.close()
    return out


async def main() -> None:
    from pydantic_ai import BinaryContent

    agent = ffp._build_agent(SYSTEM, FootnoteAnnotations)
    for stem, page, note in TARGETS:
        tjs = glob.glob(f"experiments/que270/out/strip_test_corpus/*/{stem}.tables.json")
        if not tjs:
            print(f"!! no tables.json for {stem}")
            continue
        print(f"\n==== {stem} p{page} — {note} ====")
        for ordinal, png in _crop(Path(tjs[0]), page):
            result = await agent.run(["List the footnote reference markers in this table.",
                                      BinaryContent(data=png, media_type="image/png")])
            r = result.output
            print(f"  table {ordinal}: has_footnotes={r.has_footnotes}  markers={r.markers}")


if __name__ == "__main__":
    asyncio.run(main())
