"""The style invariants must actually REACH the writer.

Both tests here cover defects found by the 2026-07-28 model×prompt A/B over the
signed finals: the canonical anti-patterns were present in the prompt but buried
~47K chars into style_context (where they measurably failed to bind), and they
were rendered inside a try/except that an unrelated DB failure could abort.
"""
import pytest

from legal_mcp.services import block_writer
from legal_mcp.services.lessons import ANTI_PATTERNS, anti_pattern_directive


def test_directive_renders_every_canonical_anti_pattern():
    """One source, two renderings — the directive may not drift from the list
    style_distance scores against."""
    text = anti_pattern_directive()
    for ap in ANTI_PATTERNS:
        assert ap["note"] in text, f"missing anti-pattern in directive: {ap['name']}"


def test_both_writer_paths_append_the_directive_last():
    """write_block (in-process) and get_block_context (legal-writer agent) must
    both close with the directive — otherwise the two writers drift (G2)."""
    import inspect
    src = inspect.getsource(block_writer)
    for fn in ("async def write_block(", "async def get_block_context("):
        start = src.index(fn)
        # bound the search to this function: up to the next top-level def
        rest = src[start + len(fn):]
        nxt = rest.find("\nasync def ")
        body = rest[: nxt if nxt != -1 else len(rest)]
        assert "anti_pattern_directive()" in body, f"{fn} does not append the style directive"


@pytest.mark.asyncio
async def test_style_context_keeps_anti_patterns_when_overrides_fail(monkeypatch):
    """A chair-override outage must not silently un-teach the structural style.

    Regression: the canonical list used to be emitted inside the overrides loop,
    so a throw on an EARLIER category (golden_ratios) dropped it entirely.
    """
    async def _boom(*a, **k):
        raise RuntimeError("methodology table unavailable")

    async def _empty(*a, **k):
        return []

    # Every DB accessor this function touches is stubbed — the test must not open
    # a real connection (a live pool here leaks across the shared event loop and
    # breaks unrelated tests later in the run).
    monkeypatch.setattr(block_writer.db, "get_style_patterns", _empty)
    monkeypatch.setattr(block_writer.db, "get_methodology_overrides", _boom)
    monkeypatch.setattr(block_writer.db, "get_recent_decision_lessons", _empty)

    ctx = await block_writer._build_style_context("היטל השבחה")

    assert "נרטיב משפטי רציף" in ctx
    for ap in ANTI_PATTERNS:
        assert ap["note"] in ctx, f"anti-pattern dropped on override failure: {ap['name']}"
