"""Tests for textual_mcp.session_manager — TDD Red phase."""

from pathlib import Path

import pytest
from textual_mcp.session import AppSession

APPS_DIR = Path(__file__).parent / "apps"


@pytest.fixture
def manager():
    from textual_mcp.session_manager import SessionManager
    return SessionManager()


@pytest.fixture
def simple_app_path():
    return str(APPS_DIR / "simple_app.py")


class TestCreateSession:
    """Test session creation."""

    def test_create_session_returns_app_session(self, manager):
        """Test 6.1: create_session() returns a new AppSession with unique ID."""
        session = manager.create_session()
        assert isinstance(session, AppSession)
        assert session.session_id is not None
        assert len(session.session_id) > 0

    def test_create_session_unique_ids(self, manager):
        """Test 6.1b: multiple create_session() calls produce unique IDs."""
        s1 = manager.create_session()
        s2 = manager.create_session()
        assert s1.session_id != s2.session_id

    def test_create_session_custom_id(self, manager):
        """Test 6.2: create_session(session_id="custom") uses the provided ID."""
        session = manager.create_session(session_id="my-session")
        assert session.session_id == "my-session"

    def test_create_session_duplicate_id_raises(self, manager):
        """Test 6.7: create_session with duplicate ID raises ValueError."""
        manager.create_session(session_id="dup")
        with pytest.raises(ValueError, match="already exists"):
            manager.create_session(session_id="dup")


class TestGetSession:
    """Test session retrieval."""

    def test_get_session_returns_session(self, manager):
        """Test 6.3: get_session(id) returns the session."""
        created = manager.create_session(session_id="abc")
        retrieved = manager.get_session("abc")
        assert retrieved is created

    def test_get_session_invalid_raises_key_error(self, manager):
        """Test 6.4: get_session(invalid_id) raises KeyError."""
        with pytest.raises(KeyError, match="not found"):
            manager.get_session("nonexistent")


class TestListSessions:
    """Test listing sessions."""

    def test_list_sessions_empty(self, manager):
        """Test 6.5a: list_sessions() on empty manager returns empty list."""
        assert manager.list_sessions() == []

    def test_list_sessions_returns_all(self, manager):
        """Test 6.5: list_sessions() returns all active sessions."""
        manager.create_session(session_id="s1")
        manager.create_session(session_id="s2")
        sessions = manager.list_sessions()
        assert len(sessions) == 2
        ids = {s["session_id"] for s in sessions}
        assert ids == {"s1", "s2"}


class TestRemoveSession:
    """Test session removal."""

    @pytest.mark.asyncio
    async def test_remove_session_stops_and_removes(self, manager):
        """Test 6.6: remove_session(id) stops and removes the session."""
        from textual_mcp.app_loader import load_app

        session = manager.create_session(session_id="rm-me")
        app = load_app(str(APPS_DIR / "simple_app.py"))
        await session.launch(app)
        assert session.is_running is True

        await manager.remove_session("rm-me")
        assert manager.list_sessions() == []
        with pytest.raises(KeyError):
            manager.get_session("rm-me")

    @pytest.mark.asyncio
    async def test_remove_session_not_launched(self, manager):
        """Test 6.6b: remove_session on unlaunched session is safe."""
        manager.create_session(session_id="idle")
        await manager.remove_session("idle")
        assert manager.list_sessions() == []


class TestConcurrentSessions:
    """Test session independence."""

    @pytest.mark.asyncio
    async def test_concurrent_sessions_independent(self, manager):
        """Test 6.8: concurrent sessions are independent (different app instances)."""
        from textual_mcp.app_loader import load_app

        s1 = manager.create_session(session_id="a")
        s2 = manager.create_session(session_id="b")

        app1 = load_app(str(APPS_DIR / "simple_app.py"))
        app2 = load_app(str(APPS_DIR / "simple_app.py"))

        await s1.launch(app1)
        await s2.launch(app2)

        try:
            assert s1.app is not s2.app
            assert s1.pilot is not s2.pilot
            assert s1.is_running is True
            assert s2.is_running is True
        finally:
            await s1.stop()
            await s2.stop()
