"""The product line table a pass emits: the unit of review (K11.5).

Rian's words, walk-through W10: *"the AI pass would present a recommendation that we have one
product line called Rouge Allure. then below that it lists all the listings in a table with
proposed attribute population. The human scans through it, makes any corrections, and approves."*
And W11: grouping and attributes are ONE job, so a table showing the grouping without the
attributes is half a review, and an error in one is an error in both.

Rendered on a copy of dfp-2026-09-17-post-chain.dump from the CHANEL rehearsal file: one line,
12 variants, 24 listings across 2 shops with their prices and source links, `color` the only
column that varies, and the two refill pairs called out as folds with their reasons -- which is
the very question rian has not settled (REVIEW-PROCESS.md v4 section 2.1).
"""

from __future__ import annotations

import pytest

from app.services import proposals
from app.services.decisions.writer import Refused
from tests.test_proposals_load import _file, db  # noqa: F401 (the fixture)

REF = "line:new:chanel-rouge-allure"


def _table(db, **kw):
    proposals.load(db, _file(db))
    return proposals.line_table(db, "chanel", REF, **kw)


def test_the_table_is_one_product_line_with_its_listings_beneath_it(db):
    t = _table(db)
    assert t["ref"] == REF and t["line"]["proposed_name"] == "Rouge Allure"
    assert t["line"]["reason"] == "the head words every shade shares"
    assert t["line"]["confidence"] == pytest.approx(0.97)
    assert t["counts"]["variants"] >= 1 and t["counts"]["listings"] >= 1


def test_every_variant_carries_its_proposed_attribute_population(db):
    """Grouping and attributes are one job: the membership and the shade sit on the same row."""
    t = _table(db)
    with_shade = [v for v in t["variants"] if "color" in v["attributes"]]
    assert with_shade, t["variants"]
    cell = with_shade[0]["attributes"]["color"]
    assert cell["proposed"] == "99 Pirate" and cell["reason"] == "the shop's option field"
    assert cell["uid"] and cell["status"] == "open"
    assert any(v["membership"] is not None for v in t["variants"]), "the membership is on the row too"


def test_the_shops_carry_their_price_and_a_link_to_the_source(db):
    """A spot-check is one click: the person reads the listed words beside the proposal."""
    t = _table(db)
    listings = [listing for v in t["variants"] for listing in v["listings"]]
    assert listings
    assert all("url" in listing and "price" in listing for listing in listings)
    assert any(listing["shop"] for listing in listings)
    assert any(listing["listed_name"] for listing in listings)


def test_only_the_kinds_that_vary_inside_the_line_are_columns(db):
    """A kind with one value everywhere tells a reviewer nothing, so it is not a column."""
    t = _table(db)
    assert "color" not in t["columns"] or len({
        v["attributes"]["color"]["proposed"] for v in t["variants"] if "color" in v["attributes"]}) > 1


def test_each_proposed_fold_is_called_out_with_its_reason_and_both_sides(db):
    t = _table(db)
    assert t["folds"], "a pair is a claim about two things and is never buried in a variant row"
    fold = t["folds"][0]
    assert fold["kind"] == "decision" and fold["reason"] == "same shade and weight, two shops"
    assert len(fold["sides"]) == 2 and all(side["key"] for side in fold["sides"])
    # ...and it is NOT also listed as one of the variants' own cells.
    assert all(fold["uid"] not in [c["uid"] for c in v["rows"]] for v in t["variants"])


def test_an_unknown_line_is_refused_by_name(db):
    proposals.load(db, _file(db))
    with pytest.raises(Refused) as exc:
        proposals.line_table(db, "chanel", "line:new:not-a-line")
    assert exc.value.code == "LINE_NOT_FOUND"


def test_the_table_writes_nothing(db):
    """A GET must never write (agents.md): a listing endpoint that created rows on read once
    deadlocked against a running collection and the page simply hung."""
    proposals.load(db, _file(db))
    db.commit()
    proposals.line_table(db, "chanel", REF)
    assert not db.new and not db.dirty and not db.deleted
