"""Unit tests for background-note injection into the session (Agent._drain_task_notes)."""

from types import SimpleNamespace

import pytest

from navi.core import task_notes
from navi.core.agent import Agent


class FakeKv:
    def __init__(self):
        self.data = {}

    async def get(self, user_id, session_id, scope, key):
        return self.data.get((user_id, session_id, scope, key))

    async def set(self, user_id, session_id, scope, key, value):
        self.data[(user_id, session_id, scope, key)] = value


class FakeStore:
    def __init__(self):
        self.saved = []

    async def save(self, session):
        self.saved.append(session)


@pytest.fixture(autouse=True)
def kv(monkeypatch):
    store = FakeKv()
    task_notes.set_kv_store(store)
    yield store
    task_notes.set_kv_store(None)


def make_agent_with_store():
    agent = object.__new__(Agent)
    agent._sessions = FakeStore()
    return agent


def make_session():
    return SimpleNamespace(context=[], messages=[])


class TestDrainTaskNotes:
    async def test_note_injected_as_system_message_and_saved(self):
        agent = make_agent_with_store()
        session = make_session()
        job = SimpleNamespace(
            task_id="bt-ab12", session_id="s1", tool="terminal", status="completed",
            subagent_tokens=None, preview=lambda limit=800: "done 42",
        )
        await task_notes.add_note(job)

        await agent._drain_task_notes("s1", session)

        assert len(session.context) == 1
        note = session.context[0]
        assert note.role == "system"
        assert "[Background task results]" in note.content
        assert "bt-ab12" in note.content
        assert note.metadata.get("source") == "task_note"
        # note did NOT go into the display history
        assert session.messages == []
        # session was persisted
        assert agent._sessions.saved == [session]

    async def test_note_survives_context_build_system_filter(self):
        """Regression: build() used to drop ALL system-role history, so a
        drained note was logged as delivered but never reached the LLM."""
        from navi.core.context_builder import ContextBuilder
        from tests.conftest_factory import make_profile, make_profile_registry

        agent = make_agent_with_store()
        session = make_session()
        job = SimpleNamespace(
            task_id="bt-ab12", session_id="s1", tool="terminal", status="completed",
            subagent_tokens=None, preview=lambda limit=800: "BG-DONE-42",
        )
        await task_notes.add_note(job)
        await agent._drain_task_notes("s1", session)

        builder = ContextBuilder(profile_registry=make_profile_registry())
        built = builder.build(session.context, make_profile("test"), None)

        joined = "\n".join((m.content or "") for m in built)
        assert "[Background task results]" in joined
        assert "bt-ab12" in joined

    async def test_no_notes_nothing_injected(self):
        agent = make_agent_with_store()
        session = make_session()

        await agent._drain_task_notes("s1", session)

        assert session.context == []
        assert agent._sessions.saved == []

    async def test_drain_failure_is_swallowed(self, monkeypatch):
        agent = make_agent_with_store()
        session = make_session()

        async def broken_drain(session_id):
            raise RuntimeError("kv down")

        monkeypatch.setattr(task_notes, "drain", broken_drain)
        await agent._drain_task_notes("s1", session)  # must not raise
        assert session.context == []