"""The precedent register and the attention floor (Stream K12.3, K12.4; the plan's B2).

What it cost: attention was a label that gated nothing, and the only precedent record was a set of
keys computed from words in reason text, so a pass that phrased a reason differently invented or
dodged a precedent by accident, and under bulk approval a new kind under-rated as medium would have
sailed through for every row of that kind. Nothing here decides a catalogue question: the fixtures
carry a gendered name because the code has to carry such cases, and the assertions are about
raising, flooring and grouping, never about the answer. SQLite kit, no network."""
from __future__ import annotations

import pytest
from sqlalchemy import select

from app.models import Decision, Listing, Precedent, ProductVariant, Proposal
from app.services import attention, precedents, proposals
from app.services.decisions import undo as undo_service, writer
from tests.test_proposals_load import _file, _key, db  # noqa: F401  (the fixture)


def _v6(db, name="claude/2026-09-18/chanel-v6"):
    """A process-version-6 file: every row names its precedent; row 1 is the lead that sets one."""
    data = _file(db, name=name)
    data["pass"]["process_version"] = "6"
    slugs = ["name-a-product-line:plain", "membership:plain", "attribute:color", "same-or-separate:product"]
    for row, slug in zip(data["proposals"], slugs):
        row["precedent"], row["precedent_status"] = slug, "sets"
    return data


def test_a_row_without_a_precedent_is_refused_from_process_version_6(db):
    data = _v6(db)
    del data["proposals"][1]["precedent"]
    with pytest.raises(proposals.Refused) as refused:
        proposals.load(db, data, check=True)
    assert refused.value.code == "PRECEDENT_MISSING"
    data = _v6(db)
    data["proposals"][1]["precedent"] = data["proposals"][0]["precedent"]
    with pytest.raises(proposals.Refused) as refused:
        proposals.load(db, data, check=True)
    assert refused.value.code == "PRECEDENT_SET_TWICE"


def test_an_unregistered_precedent_is_critical_whatever_the_pass_said(db):
    data = _v6(db)
    for row in data["proposals"]:
        row["attention"] = "low"  # the pass under-rates everything
    proposals.load(db, data)
    rows = list(db.scalars(select(Proposal)))
    levels = attention.explain(db, rows)
    assert {levels[r.id][0] for r in rows} == {"critical"}
    assert "no precedent is registered" in levels[rows[0].id][1]
    assert all(r.shape and r.shape["fields"] == [r.field] for r in rows), "every row's shape is computed at load"
    assert all(r.unlike is None for r in rows), "nothing to be unlike: the slug is new"


def test_approving_a_lead_with_a_note_sets_the_register_row_and_a_follower_under_it_is_high_until_the_streak(db):
    data = _v6(db)
    proposals.load(db, data)
    lead = db.scalar(select(Proposal).where(Proposal.field == "attribute:color"))
    out = proposals.approve(db, "chanel", data["pass"]["name"], scope={"proposal_uids": [str(lead.uid)]}, by="rian",
                            note="The shop's own option field names the shade; read it as the colour attribute.")
    assert out["counts"]["approved"] == 1
    reg = db.scalar(select(Precedent).where(Precedent.slug == "attribute:color"))
    assert reg is not None and reg.status == "active" and reg.decisions_count == 1 and reg.streak == 1
    assert reg.note.startswith("The shop's own option field") and reg.first_case == lead.natural_key
    assert reg.question == lead.reason and reg.answer.startswith("approved: 99 Pirate")
    dec = db.get(Decision, lead.decision_id)
    assert dec.detail["precedent"] == "attribute:color", "the decision carries the precedent it was made under"
    assert precedents.decisions_under(db, "attribute:color") == [dec]
    # A second pass files a like row under the registered slug: high, not critical, until the streak.
    again = _v6(db, name="claude/2026-09-18/chanel-v6-2")
    again["proposals"] = [dict(again["proposals"][2], precedent_status="follows", attention="low")]
    proposals.load(db, again)
    row = db.scalar(select(Proposal).where(Proposal.field == "attribute:color", Proposal.status == "open"))
    level, why = attention.explain(db, [row])[row.id]
    assert level == "high" and "1 consistent decision" in why
    reg.streak = attention.LEAVE_HIGH_AFTER
    db.commit()
    level, why = attention.explain(db, [row])[row.id]
    assert level == "low" and "settled by" in why, "past the streak the confidence-derived level applies"


def test_a_row_unlike_every_case_decided_under_its_precedent_is_floored_high_and_names_the_element(db):
    """The worked example, as a process fact only: a listing whose name carries an audience word
    is filed under the plain membership slug. No plain membership decision has carried that hint,
    so the row is unlike its precedent and the sheet says why. What the answer should be is not
    asserted anywhere: that is rian's at the review."""
    data = _v6(db)
    proposals.load(db, data)
    member = db.scalar(select(Proposal).where(Proposal.field == "product_line"))
    header = db.scalar(select(Proposal).where(Proposal.entity_type == "product_line", Proposal.field == "name"))
    out = proposals.approve(db, "chanel", data["pass"]["name"], scope={"proposal_uids": [str(header.uid), str(member.uid)]}, by="rian",
                            note="A shade written loose in the name is a member of the line it names.")
    assert out["counts"]["approved"] == 2, out
    listing = db.get(Listing, 4)
    listing.listed_name = "Rouge Allure 99 Pirate for men"
    db.commit()
    again = _v6(db, name="claude/2026-09-18/chanel-v6-3")
    row = dict(again["proposals"][1], precedent_status="follows", attention="medium")
    row["evidence"] = [{"listing": _key(db, Listing, 4), "source": "listed_name", "span": [0, 30], "text": "Rouge Allure 99 Pirate for men"}]
    again["proposals"] = [row]
    proposals.load(db, again)
    loaded = db.scalar(select(Proposal).where(Proposal.field == "product_line", Proposal.status == "open"))
    assert loaded.unlike and "audience" in loaded.unlike.get("hints", []), loaded.unlike
    level, why = attention.explain(db, [loaded])[loaded.id]
    assert level == "high" and "unlike every case" in why and "audience" in why


def test_something_else_on_a_registered_kind_resets_its_streak(db):
    data = _v6(db)
    proposals.load(db, data)
    lead = db.scalar(select(Proposal).where(Proposal.field == "attribute:color"))
    proposals.approve(db, "chanel", data["pass"]["name"], scope={"proposal_uids": [str(lead.uid)]}, by="rian", note="read the option field")
    reg = db.scalar(select(Precedent).where(Precedent.slug == "attribute:color"))
    reg.streak = 5
    db.commit()
    again = _v6(db, name="claude/2026-09-18/chanel-v6-4")
    again["proposals"] = [dict(again["proposals"][2], precedent_status="follows")]
    proposals.load(db, again)
    row = db.scalar(select(Proposal).where(Proposal.field == "attribute:color", Proposal.status == "open"))
    proposals.approve(db, "chanel", again["pass"]["name"], scope=None, by="rian", counter=[str(row.uid)], note="not like that")
    db.refresh(reg)
    assert reg.streak == 0 and reg.resets_count == 1


def test_an_overturn_is_one_undoable_decision_that_regroups_nothing_and_floors_the_slug_high(db):
    data = _v6(db)
    proposals.load(db, data)
    lead = db.scalar(select(Proposal).where(Proposal.field == "attribute:color"))
    proposals.approve(db, "chanel", data["pass"]["name"], scope={"proposal_uids": [str(lead.uid)]}, by="rian", note="read the option field")
    variant = db.get(ProductVariant, 1)
    before = dict(variant.attributes or {})
    reg = db.scalar(select(Precedent).where(Precedent.slug == "attribute:color"))
    reg.streak = attention.LEAVE_HIGH_AFTER
    db.commit()
    with pytest.raises(writer.Refused) as refused:
        precedents.overturn(db, "attribute:color", note="", by="rian")
    assert refused.value.code == "NOTE_REQUIRED"
    out = precedents.overturn(db, "attribute:color", note="A shop's option field is not always the shade; ask per shop.", by="rian")
    assert out["decisions_under"] == 1
    db.refresh(reg)
    assert reg.status == "overturned" and reg.streak == 0 and reg.overturn_note.startswith("A shop's option field")
    assert db.get(ProductVariant, 1).attributes == before, "an overturn regroups nothing"
    again = _v6(db, name="claude/2026-09-18/chanel-v6-5")
    again["proposals"] = [dict(again["proposals"][2], precedent_status="follows", attention="low")]
    proposals.load(db, again)
    row = db.scalar(select(Proposal).where(Proposal.field == "attribute:color", Proposal.status == "open"))
    level, why = attention.explain(db, [row])[row.id]
    assert level == "high" and "overturned" in why
    # Undo the overturn: the register row is active again, its ledger row reversed, nothing deleted.
    proposals.undo_batch(db, out["batch_uid"], "rian", "changed my mind back")
    db.refresh(reg)
    assert reg.status == "active" and reg.overturn_note is None
    assert db.scalar(select(Decision).where(Decision.entity_type == "precedent", Decision.effect == "release")) is not None


def test_the_export_is_generated_markdown_one_heading_per_precedent(db):
    assert "No precedent has been set yet" in precedents.export_markdown(db)
    data = _v6(db)
    proposals.load(db, data)
    lead = db.scalar(select(Proposal).where(Proposal.field == "attribute:color"))
    proposals.approve(db, "chanel", data["pass"]["name"], scope={"proposal_uids": [str(lead.uid)]}, by="rian", note="read the option field")
    text = precedents.export_markdown(db)
    assert "GENERATED" in text and "## attribute:color" in text and "read the option field" in text


def test_the_leave_high_threshold_is_the_one_the_process_document_states():
    import pathlib
    import re

    doc = (pathlib.Path(__file__).resolve().parents[1] / "docs" / "REVIEW-PROCESS.md").read_text(encoding="utf-8")
    match = re.search(r"leaves? `?high`? after \*?\*?(\d+)\*?\*?", doc)
    assert match, "REVIEW-PROCESS.md section 4 states the number of consistent decisions that let a kind leave high"
    assert int(match.group(1)) == attention.LEAVE_HIGH_AFTER


# ----------------------------------------------------------------------------- K12.4: the control


def _with_follower(db, name="claude/2026-09-18/chanel-group"):
    """The v6 file plus a follower: variant 4's colour follows the lead on variant 1."""
    data = _v6(db, name=name)
    lead = data["proposals"][2]
    v4, l4 = _key(db, ProductVariant, 4), _key(db, Listing, 4)
    data["proposals"].append({"position": 4, "entity": {"type": "product_variant", "key": v4, "detail": {"listings": [l4]}},
                              "field": "attribute:color", "value": "99 Pirate", "confidence": 0.95, "reason": "the same shade, written loose",
                              "precedent": "attribute:color", "precedent_status": "follows", "follows": lead["entity"]["key"],
                              "attention": "none",
                              "evidence": [{"listing": l4, "source": "listed_name", "span": [18, 27], "text": "99 Pirate"}]})
    return data


def test_the_rest_is_refused_while_a_lead_is_open_and_a_critical_row_needs_a_note(db):
    data = _with_follower(db)
    proposals.load(db, data)
    with pytest.raises(proposals.Refused) as refused:
        proposals.approve(db, "chanel", data["pass"]["name"], scope="all", by="rian")
    assert refused.value.code == "BULK_BLOCKED_BY_OPEN_LEAD" and "attribute:color" in refused.value.summary
    lead = db.scalar(select(Proposal).where(Proposal.field == "attribute:color", Proposal.precedent_status == "sets"))
    with pytest.raises(proposals.Refused) as refused:
        proposals.approve(db, "chanel", data["pass"]["name"], scope={"proposal_uids": [str(lead.uid)]}, by="rian")
    assert refused.value.code == "NOTE_REQUIRED"
    sheet = proposals.sheet(db, "chanel", data["pass"]["name"])
    assert str(lead.uid) in sheet["bulk_blocked_by"]
    group = next(g for g in sheet["precedent_groups"] if g["precedent"] == "attribute:color")
    assert group["registered"] is False and group["level"] == "critical" and group["lead_uid"] == str(lead.uid)
    assert group["bulk_ready"] is False and "pirate" in group["unseen_words"], "no decided case has carried the word yet"
    row = next(r for g in sheet["groups"] for r in g["rows"] if r["uid"] == str(lead.uid))
    assert row["attention"] == "critical" and "no precedent is registered" in row["attention_why"]


def test_a_precedent_group_confirms_as_one_batch_after_its_lead_with_the_note_on_every_row(db):
    data = _with_follower(db)
    proposals.load(db, data)
    with pytest.raises(proposals.Refused) as refused:
        proposals.approve(db, "chanel", data["pass"]["name"], scope={"precedent": "attribute:color"}, by="rian", note="x")
    assert refused.value.code == "LEAD_NOT_ANSWERED"
    lead = db.scalar(select(Proposal).where(Proposal.field == "attribute:color", Proposal.precedent_status == "sets"))
    proposals.approve(db, "chanel", data["pass"]["name"], scope={"proposal_uids": [str(lead.uid)]}, by="rian", note="read the option field")
    sheet = proposals.sheet(db, "chanel", data["pass"]["name"])
    group = next(g for g in sheet["precedent_groups"] if g["precedent"] == "attribute:color")
    assert group["registered"] and group["lead_status"] == "approved" and group["bulk_ready"] and group["open"] == 1
    assert "pirate" not in group["unseen_words"], "the lead's decision carried the word"
    out = proposals.approve(db, "chanel", data["pass"]["name"], scope={"precedent": "attribute:color"}, by="rian",
                            note="the whole group reads the option field")
    assert out["counts"]["approved"] == 1 and out["mode"] == "bulk"
    follower = db.scalar(select(Proposal).where(Proposal.field == "attribute:color", Proposal.precedent_status == "follows"))
    assert follower.status == "approved" and follower.detail["batch_note"] == "the whole group reads the option field"
    reg = db.scalar(select(Precedent).where(Precedent.slug == "attribute:color"))
    assert reg.decisions_count == 2 and reg.streak == 2


def test_the_second_defer_parks_the_question_to_rian_and_no_pass_asks_it_again_until_unparked(db):
    data = _v6(db)
    proposals.load(db, data)
    lead = db.scalar(select(Proposal).where(Proposal.field == "attribute:color"))
    proposals.approve(db, "chanel", data["pass"]["name"], scope=None, by="rian", defer=[str(lead.uid)], note="not sure yet")
    again = _v6(db, name="claude/2026-09-18/chanel-v6-b")
    again["proposals"] = [dict(again["proposals"][2], answers_deferred=str(lead.uid))]
    proposals.load(db, again)
    row = db.scalar(select(Proposal).where(Proposal.field == "attribute:color", Proposal.status == "open"))
    out = proposals.approve(db, "chanel", again["pass"]["name"], scope=None, by="rian", defer=[str(row.uid)], note="still not sure")
    assert out["counts"]["parked"] == 1
    db.refresh(row)
    assert row.status == "parked" and row.detail["parked_to_rian"]["notes"] == ["not sure yet", "still not sure"]
    assert proposals.parked_questions(db, "chanel")[0]["uid"] == str(row.uid)
    third = _v6(db, name="claude/2026-09-18/chanel-v6-c")
    third["proposals"] = [dict(third["proposals"][2], answers_deferred=str(row.uid))]
    with pytest.raises(proposals.Refused) as refused:
        proposals.load(db, third, check=True)
    assert refused.value.code == "PARKED_TO_RIAN"
    proposals.unpark(db, str(row.uid), note="Read the option field as the shade.", by="rian")
    db.refresh(row)
    assert row.status == "deferred" and row.detail["wants"] == "a different suggestion"
    third["proposals"][0]["answers_deferred"] = str(row.uid)
    assert proposals.load(db, third)["rows"] == 1
