"""Unit tests for the GET /sessions/{id}/tasks background-task list endpoint."""

import asyncio

import pytest
from fastapi import HTTPException

import navi.api.routes.sessions as sessions_mod
from navi.auth import User
from navi.core import tasks as tasks_mod
from navi.core.session import InMemorySessionStore
from navi.core.tasks import TaskManager
from navi.tools._internal.base import ToolContext, ToolResult


_FAKE_USER = User(id="test-user", email="test@example.com", display_name="Test",
                  role="admin", permissions=[])


@pytest.fixture(autouse=True)
def fresh_manager(monkeypatch):
    manager = TaskManager()
    monkeypatch.setattr(tasks_mod, "_manager", manager)
    yield manager
    for job in list(manager._jobs.values()):
        if job.task is not None and not job.task.done():
            job.task.cancel()


@pytest.fixture
async def store():
    session_store = InMemorySessionStore()
    await session_store.create("secretary")
    return session_store


def make_ctx(session_id):
    return ToolContext(
        session_id=session_id, event_sink=None, stop_event=None, model=None,
        user_id=None, user_role="admin", user_info=None, cwd=None,
    )


async def _session_id(store: InMemorySessionStore) -> str:
    sessions = await store.list_all()
    return sessions[0].id


class TestListSessionTasks:
    async def test_lists_jobs_with_summary(self, fresh_manager, store):
        session_id = await _session_id(store)

        async def factory(bg_ctx):
            await asyncio.sleep(30)

        job = fresh_manager.submit(
            session_id, "terminal",
            {"action": "run", "command": "sleep 60", "background": True},
            factory, make_ctx(session_id),
        )
        result = await sessions_mod.list_session_tasks(session_id, store, _FAKE_USER)
        fresh_manager.cancel(job)

        assert result["session_id"] == session_id
        assert len(result["tasks"]) == 1
        task = result["tasks"][0]
        assert task["task_id"] == job.task_id
        assert task["tool"] == "terminal"
        assert task["status"] == "running"
        assert "sleep 60" in task["args_summary"]
        # background flag must be stripped in the summary args
        assert task["parent_tool_call_id"] is None
        assert task["result_preview"] == "" or task["result_preview"] is None

    async def test_session_scoped_and_shows_finished(self, fresh_manager, store):
        session_id = await _session_id(store)

        async def factory(bg_ctx):
            return ToolResult(success=True, output="done 42")

        job = fresh_manager.submit(
            session_id, "code_exec", {"code": "x"}, factory, make_ctx(session_id))
        other = fresh_manager.submit(
            "other-session", "code_exec", {"code": "y"}, factory, make_ctx("other-session"))
        await job.done.wait()
        await other.done.wait()

        result = await sessions_mod.list_session_tasks(session_id, store, _FAKE_USER)
        assert [t["task_id"] for t in result["tasks"]] == [job.task_id]
        task = result["tasks"][0]
        assert task["status"] == "completed"
        assert "done 42" in task["result_preview"]
        assert task["finished_at"] is not None

    async def test_unknown_session_404(self, fresh_manager, store):
        with pytest.raises(HTTPException) as exc:
            await sessions_mod.list_session_tasks("nope", store, _FAKE_USER)
        assert exc.value.status_code == 404