"""Tests for the TableExtractor Protocol and ExtractedTable model."""

from pathlib import Path

from quber.agents.llm_client import FootnoteDef
from quber.core.extractors import (
    ExtractedTable,
    MockTableExtractor,
    TableExtractor,
)


def test_extractor_protocol_isinstance_with_mock():
    # The annotation makes pyright verify structural conformance (method
    # signatures); isinstance only checks the methods exist at runtime.
    me: TableExtractor = MockTableExtractor()
    assert isinstance(me, TableExtractor)


def test_extracted_table_defaults():
    t = ExtractedTable(markdown="| a |", page=2)
    assert t.title == ""
    assert t.subtitle == ""
    assert t.footnotes == []
    assert t.page == 2
    assert t.bbox is None
    assert t.flavor == "unknown"
    assert t.source is None
    assert t.table_id == ""
    assert t.content_fingerprint == ""


def test_table_address_is_deterministic_and_positional():
    from quber.core.extractors.base import table_address

    assert table_address("/data/67609452.pdf", 14, 2) == "67609452-p14-t2"
    # Purely positional: only the file stem matters, not its directory.
    assert table_address(Path("elsewhere/67609452.pdf"), 14, 2) == "67609452-p14-t2"


def test_grid_fingerprint_tracks_values():
    from quber.core.extractors.base import grid_fingerprint

    cells = [["Region", "2025"], ["US", "1,637"]]
    a = grid_fingerprint(cells)
    assert len(a) == 8 and a == grid_fingerprint([["Region", "2025"], ["US", "1,637"]])
    # A changed value at the same address shows as a different fingerprint.
    assert a != grid_fingerprint([["Region", "2025"], ["US", "1,638"]])
    assert grid_fingerprint([]) == ""


def test_extracted_table_full():
    t = ExtractedTable(
        title="Branded Volume",
        subtitle="For the 3 Months Ended Sep 30, 2025",
        markdown="| a |\n|---|\n| 1 |",
        footnotes=[FootnoteDef(marker="(1)", text="Note")],
        page=4,
        bbox=(10.0, 20.0, 30.0, 40.0),
        flavor="lattice",
        source="/tmp/x.pdf",
    )
    assert t.flavor == "lattice"
    assert t.bbox == (10.0, 20.0, 30.0, 40.0)


def test_legacy_bare_string_footnotes_load_as_unmarked_notes():
    # Artifacts extracted before footnotes carried their marker stored each
    # footnote as a bare string; those must stay readable.
    t = ExtractedTable.model_validate({"markdown": "| a |", "page": 1, "footnotes": ["(1) Restated for FX."]})
    assert t.footnotes == [FootnoteDef(marker="", text="(1) Restated for FX.")]


def test_mock_extractor_returns_injected_list():
    rows = [ExtractedTable(markdown="| a |", page=1)]
    me = MockTableExtractor(tables=rows)
    out = me.extract_tables_sync(Path("x.pdf"))
    assert len(out) == 1
    assert out[0].markdown == "| a |"


def test_mock_extractor_empty_default():
    me = MockTableExtractor()
    assert me.extract_tables_sync(Path("x.pdf")) == []
