"""Verify live-read paths exclude trashed rows.

Strategy: run each service read with a mocked session that CAPTURES the
compiled SQL of every statement passed to execute, then assert the
'deleted_at IS NULL' filter is present. No real DB.
"""
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from tests.helpers import make_mock_session


def _capturing_session(captured: list[str]):
    s = make_mock_session()
    s.commit = AsyncMock()
    s.scalar = AsyncMock(return_value=0)

    async def _exec(stmt, *a, **k):
        captured.append(str(stmt))
        r = MagicMock()
        r.scalars.return_value.all.return_value = []
        r.scalars.return_value.first.return_value = None
        r.scalar_one_or_none.return_value = None
        r.first.return_value = None
        r.all.return_value = []
        r.fetchall.return_value = []
        return r

    s.execute = AsyncMock(side_effect=_exec)
    return s


def _has_filter(captured: list[str]) -> bool:
    return any("deleted_at IS NULL" in s for s in captured)


@pytest.mark.asyncio
async def test_get_note_excludes_trashed():
    cap: list[str] = []
    with patch("scribe.services.notes.async_session") as cls:
        cls.return_value = _capturing_session(cap)
        from scribe.services.notes import get_note
        await get_note(1, 5)
    assert _has_filter(cap)


@pytest.mark.asyncio
async def test_list_notes_excludes_trashed():
    cap: list[str] = []
    with patch("scribe.services.notes.async_session") as cls:
        cls.return_value = _capturing_session(cap)
        from scribe.services.notes import list_notes
        await list_notes(1)
    assert _has_filter(cap)


@pytest.mark.asyncio
async def test_list_projects_excludes_trashed():
    cap: list[str] = []
    with patch("scribe.services.projects.async_session") as cls:
        cls.return_value = _capturing_session(cap)
        from scribe.services.projects import list_projects
        await list_projects(1)
    assert _has_filter(cap)


@pytest.mark.asyncio
async def test_query_knowledge_excludes_trashed():
    cap: list[str] = []
    with patch("scribe.services.knowledge.async_session") as cls:
        cls.return_value = _capturing_session(cap)
        from scribe.services.knowledge import query_knowledge
        await query_knowledge(user_id=1, note_type=None, tags=[], sort="modified", q=None, limit=10, offset=0)
    assert _has_filter(cap)


@pytest.mark.asyncio
async def test_get_applicable_rules_excludes_trashed():
    cap: list[str] = []
    with patch("scribe.services.rulebooks.async_session") as cls:
        cls.return_value = _capturing_session(cap)
        from scribe.services.rulebooks import get_applicable_rules
        await get_applicable_rules(project_id=3, user_id=1)
    assert _has_filter(cap)
