"""Tests for context/session.py — AgentSession and SessionStore."""

import time

import pytest

from proxym.context.session import AgentSession, SessionStore


class TestAgentSession:
    """Tests for AgentSession class."""

    def test_new_session_has_empty_history(self):
        """New session has empty history."""
        session = AgentSession(session_id="test-123")

        assert session.id == "test-123"
        assert session.history == []
        assert session.message_count == 0

    def test_add_exchange_increments_history(self):
        """Adding exchange increments history."""
        session = AgentSession(session_id="test-123")

        session.add_exchange(
            user_message="Hello",
            assistant_message="Hi there!",
            metadata={"model": "claude-3-haiku"},
        )

        assert len(session.history) == 1
        assert session.history[0]["user"] == "Hello"
        assert session.history[0]["assistant"] == "Hi there!"
        assert session.message_count == 1

    def test_add_multiple_exchanges(self):
        """Adding multiple exchanges builds history."""
        session = AgentSession(session_id="test-123")

        session.add_exchange("Hello", "Hi!")
        session.add_exchange("How are you?", "I'm doing well!")
        session.add_exchange("Goodbye", "See you!")

        assert len(session.history) == 3
        assert session.message_count == 3

    def test_touch_updates_last_active(self):
        """Touch updates last_active timestamp."""
        session = AgentSession(session_id="test-123")
        original_time = session.last_active

        time.sleep(0.01)  # Small delay
        session.touch()

        assert session.last_active > original_time

    def test_age_seconds_grows_over_time(self):
        """Age seconds grows over time."""
        session = AgentSession(session_id="test-123")

        time.sleep(0.1)  # 100ms delay
        age = session.age_seconds

        assert age >= 0.1

    def test_idle_seconds_resets_on_touch(self):
        """Idle seconds resets on touch."""
        session = AgentSession(session_id="test-123")

        time.sleep(0.1)
        idle_before = session.idle_seconds

        session.touch()
        idle_after = session.idle_seconds

        assert idle_before > 0.1
        assert idle_after < 0.01  # Nearly zero after touch

    def test_session_metadata(self):
        """Session stores metadata correctly."""
        session = AgentSession(
            session_id="test-123",
            metadata={"project": "test-project", "tool": "windsurf"},
        )

        assert session.metadata["project"] == "test-project"
        assert session.metadata["tool"] == "windsurf"


class TestSessionStore:
    """Tests for SessionStore class."""

    def test_get_or_create_creates_new_session(self, tmp_path):
        """get_or_create creates new session if not exists."""
        store = SessionStore(base_dir=tmp_path)

        session = store.get_or_create("new-session-123")

        assert session.id == "new-session-123"
        assert session.history == []

    def test_get_or_create_returns_existing(self, tmp_path):
        """get_or_create returns existing session."""
        store = SessionStore(base_dir=tmp_path)

        # Create first
        session1 = store.get_or_create("existing-session")
        session1.add_exchange("Hello", "Hi!")

        # Get again
        session2 = store.get_or_create("existing-session")

        assert session1 is session2
        assert len(session2.history) == 1

    def test_expired_session_evicted_on_access(self, tmp_path):
        """TTL expired → new session, not old."""
        store = SessionStore(base_dir=tmp_path, ttl_seconds=0.01)

        # Create session
        session1 = store.get_or_create("expiring-session")
        session1.add_exchange("Hello", "Hi!")

        # Wait for TTL
        time.sleep(0.02)

        # Get again - should create new
        session2 = store.get_or_create("expiring-session")

        assert session1.id == session2.id  # Same ID
        # But different object if evicted

    def test_list_sessions_excludes_expired(self, tmp_path):
        """list_sessions excludes expired sessions."""
        store = SessionStore(base_dir=tmp_path, ttl_seconds=0.01)

        # Create sessions
        store.get_or_create("active-session")

        time.sleep(0.02)  # Let it expire

        store.get_or_create("another-session")

        # List
        sessions = store.list_sessions()

        # Should only have non-expired
        assert len(sessions) >= 1

    def test_delete_removes_session(self, tmp_path):
        """delete removes session."""
        store = SessionStore(base_dir=tmp_path)

        store.get_or_create("to-delete")
        assert len(store.list_sessions()) == 1

        store.delete("to-delete")
        assert len(store.list_sessions()) == 0

    def test_max_sessions_evicts_oldest(self, tmp_path):
        """After exceeding limit, oldest session is removed."""
        store = SessionStore(base_dir=tmp_path, max_sessions=2)

        # Create 3 sessions (max is 2)
        store.get_or_create("session-1")
        time.sleep(0.01)
        store.get_or_create("session-2")
        time.sleep(0.01)
        store.get_or_create("session-3")  # Should evict session-1

        sessions = store.list_sessions()
        session_ids = [s.id for s in sessions]

        assert "session-1" not in session_ids
        assert "session-2" in session_ids
        assert "session-3" in session_ids

    def test_clear_all_sessions(self, tmp_path):
        """clear removes all sessions."""
        store = SessionStore(base_dir=tmp_path)

        store.get_or_create("session-1")
        store.get_or_create("session-2")
        store.get_or_create("session-3")

        assert len(store.list_sessions()) == 3

        store.clear()

        assert len(store.list_sessions()) == 0

    def test_session_persistence(self, tmp_path):
        """Sessions are persisted to disk."""
        store1 = SessionStore(base_dir=tmp_path)

        session = store1.get_or_create("persistent-session")
        session.add_exchange("Hello", "Hi!", {"cost": 0.001})

        # Create new store pointing to same directory
        store2 = SessionStore(base_dir=tmp_path)
        loaded = store2.get_or_create("persistent-session")

        assert loaded.id == "persistent-session"
        # Note: This depends on implementation - if fully in-memory, may not persist
