from masfactory.adapters.context.composer import ContextComposer
from masfactory.adapters.context.policy import DefaultContextPolicy
from masfactory.adapters.context.renderer import DefaultContextRenderer
from masfactory.adapters.context.types import ContextBlock, ContextQuery


class _Provider:
    def __init__(self, label: str, blocks: list[ContextBlock]):
        self.context_label = label
        self._blocks = blocks

    def get_blocks(self, query: ContextQuery, *, top_k: int = 8) -> list[ContextBlock]:
        return self._blocks[:top_k]


class _FailProvider:
    context_label = "FAIL"

    def get_blocks(self, query: ContextQuery, *, top_k: int = 8) -> list[ContextBlock]:
        raise RuntimeError("boom")


def test_composer_collects_policy_renders():
    providers = [
        _Provider("A", [ContextBlock(text="a1", score=0.2), ContextBlock(text="a2", score=0.9)]),
        _Provider("B", [ContextBlock(text="b1", score=0.1)]),
    ]
    composer = ContextComposer(
        providers=providers,
        policy=DefaultContextPolicy(),
        renderer=DefaultContextRenderer(),
    )

    user_payload = {"MESSAGE TO YOU": "hello"}
    injected = composer.inject_user_payload(user_payload, ContextQuery(query_text="q"), top_k=3)

    assert "CONTEXT" in injected
    # provider A order preserved; within provider sorted by score desc
    assert injected["CONTEXT"].splitlines()[1:] == ["(A) a2", "(A) a1", "(B) b1"]


def test_composer_provider_failure_isolated():
    providers = [
        _FailProvider(),
        _Provider("OK", [ContextBlock(text="ok")]),
    ]
    composer = ContextComposer(providers=providers)
    injected = composer.inject_user_payload({"MESSAGE TO YOU": "hi"}, ContextQuery(query_text="q"), top_k=10)
    assert "CONTEXT" in injected
    assert "(OK) ok" in injected["CONTEXT"]

