"""The status inspector verifies proposed gap conditions against the table
image, and the deterministic gate only ever downgrades: confirmed conditions
keep their status with the evidence noted, everything else becomes
`unverified` for user inspection."""

from __future__ import annotations

from pathlib import Path

import pytest

import quber.core.extractors.set_of_mark.inspection as inspection
from quber.agents.status_inspector import CellFinding, MockStatusInspector
from quber.core.extractors.base import GroundedCell


def _grid():
    return [
        [GroundedCell(text="Item", box=(0.1, 0.1, 0.2, 0.12), status="reconciled")],
        [GroundedCell(text="Coverage Data", status="header_printed_unlocated")],
        [GroundedCell(text="Total", status="total_label_added")],
        [GroundedCell(text="9,999", status="unverified")],
        [GroundedCell(text="$", status="single_character")],
    ]


@pytest.fixture
def patched(monkeypatch):
    monkeypatch.setattr(inspection, "page_words", lambda source, page: (612.0, 792.0, []))
    monkeypatch.setattr(inspection, "crop_region_png", lambda image, box, dpi: b"png")
    monkeypatch.setattr(inspection, "table_crop_box", lambda bbox, page_h: bbox)


async def _run(grid, inspector):
    await inspection.inspect_gap_cells(
        grid, "| Item |", "doc.pdf", 9, Path("page.png"), (10.0, 10.0, 100.0, 100.0), 200, inspector
    )


@pytest.mark.asyncio
async def test_confirmed_conditions_keep_status_with_evidence(patched):
    grid = _grid()
    inspector = MockStatusInspector(
        findings=[
            CellFinding(row=1, col=0, verdict="holds", evidence="printed as a band over two columns"),
            CellFinding(row=2, col=0, verdict="holds", evidence="blank label on a totals row"),
            CellFinding(row=3, col=0, verdict="holds", evidence="not visible anywhere"),
        ]
    )
    await _run(grid, inspector)
    assert grid[1][0].status == "header_printed_unlocated"
    assert grid[1][0].note == "printed as a band over two columns"
    assert grid[2][0].status == "total_label_added"
    assert grid[3][0].status == "unverified"  # stays; only gains evidence
    # reconciled and single-character cells are never sent for inspection
    sent = {(f["row"], f["col"]) for f in inspector.calls[0]["flagged"]}
    assert sent == {(1, 0), (2, 0), (3, 0)}


@pytest.mark.asyncio
async def test_contradicted_unmentioned_and_unsettled_conditions_reassign(patched):
    grid = _grid()
    inspector = MockStatusInspector(
        findings=[
            # row 1 contradicted; row 2 unmentioned entirely
            CellFinding(
                row=1, col=0, verdict="contradicted", evidence="the band there reads 'Coverage Ratio'"
            ),
            CellFinding(row=3, col=0, verdict="holds", evidence="not visible anywhere"),
        ]
    )
    await _run(grid, inspector)
    # positive contrary evidence is a DEFECT, not an open question
    assert grid[1][0].status == "defect"
    assert grid[1][0].note == "the band there reads 'Coverage Ratio'"
    assert grid[2][0].status == "unverified"
    assert grid[2][0].note == "not confirmed by inspection"


@pytest.mark.asyncio
async def test_cannot_tell_lands_in_unverified_not_defect(patched):
    grid = _grid()
    inspector = MockStatusInspector(
        findings=[
            CellFinding(row=1, col=0, verdict="cannot_tell", evidence="header area is cropped"),
            CellFinding(row=2, col=0, verdict="holds", evidence="blank label on a totals row"),
            CellFinding(row=3, col=0, verdict="holds", evidence="not visible anywhere"),
        ]
    )
    await _run(grid, inspector)
    assert grid[1][0].status == "unverified"
    assert grid[1][0].note == "header area is cropped"


@pytest.mark.asyncio
async def test_no_inspector_leaves_proposed_statuses(patched):
    grid = _grid()
    await _run(grid, None)
    assert grid[1][0].status == "header_printed_unlocated"
    assert grid[2][0].status == "total_label_added"
    assert grid[1][0].note is None


@pytest.mark.asyncio
async def test_nothing_flagged_makes_no_call(patched):
    grid = [[GroundedCell(text="Item", box=(0.1, 0.1, 0.2, 0.12), status="reconciled")]]
    inspector = MockStatusInspector()
    await _run(grid, inspector)
    assert inspector.calls == []


@pytest.mark.asyncio
async def test_missing_image_downgrades_everything_flagged(patched):
    grid = _grid()
    inspector = MockStatusInspector()
    await inspection.inspect_gap_cells(
        grid, "| Item |", "doc.pdf", 9, None, (10.0, 10.0, 100.0, 100.0), 200, inspector
    )
    assert grid[1][0].status == "unverified"
    assert grid[2][0].status == "unverified"
    assert inspector.calls == []  # nothing to look at, nothing to ask
