"""Tests for tools module."""

import tempfile
from pathlib import Path

import pytest

from ccontext_mcp.tools import ContextTools


@pytest.fixture
def temp_dir():
    """Create a temporary directory for tests."""
    with tempfile.TemporaryDirectory() as tmpdir:
        yield Path(tmpdir)


@pytest.fixture
def tools(temp_dir):
    """Create a tools instance with temp directory."""
    return ContextTools(temp_dir)


class TestGetContext:
    """Tests for get_context tool."""

    def test_get_empty_context(self, tools):
        """Test getting context when nothing exists."""
        result = tools.get_context()
        
        assert result["goal"] is None
        assert result["why"] is None
        assert result["agents"] == {}
        assert result["notes"] == []
        assert result["references"] == []
        assert result["tasks_summary"]["total"] == 0
        assert result["active_task"] is None

    def test_get_context_with_data(self, tools):
        """Test getting context with existing data."""
        # Set up data
        tools.update_context(goal="Test goal", why="Test reason")
        tools.add_entry(type="note", content="Test note", score=50)
        tools.create_task(
            name="Test task",
            goal="Complete test",
            steps=[{"name": "Step 1", "done": "Finish step 1"}]
        )
        
        result = tools.get_context()
        
        assert result["goal"] == "Test goal"
        assert result["why"] == "Test reason"
        assert len(result["notes"]) == 1
        assert result["notes"][0]["content"] == "Test note"
        assert result["tasks_summary"]["total"] == 1


class TestUpdateContext:
    """Tests for update_context tool."""

    def test_update_goal(self, tools):
        """Test updating goal."""
        result = tools.update_context(goal="New goal")
        assert result["goal"] == "New goal"
        
        # Verify persisted
        context = tools.get_context()
        assert context["goal"] == "New goal"

    def test_update_agent_status(self, tools):
        """Test updating agent status."""
        result = tools.update_context(agent_id="PeerA", agent_status="Working on task")
        assert result["agents"]["PeerA"] == "Working on task"


class TestTaskTools:
    """Tests for task tools."""

    def test_create_task(self, tools):
        """Test creating a task."""
        result = tools.create_task(
            name="Test task",
            goal="Complete test",
            steps=[
                {"name": "Step 1", "done": "Finish step 1"},
                {"name": "Step 2", "done": "Finish step 2"},
            ]
        )
        
        assert result["id"] == "T001"
        assert result["name"] == "Test task"
        assert result["status"] == "planned"
        assert len(result["steps"]) == 2
        assert result["steps"][0]["id"] == "S1"
        assert result["progress"] == 0.0

    def test_create_task_with_custom_id(self, tools):
        """Test creating a task with custom ID."""
        result = tools.create_task(
            name="Test",
            goal="Test",
            steps=[{"name": "Step", "done": "Done"}],
            task_id="T100"
        )
        assert result["id"] == "T100"

    def test_update_task_status(self, tools):
        """Test updating task status."""
        tools.create_task(
            name="Test",
            goal="Test",
            steps=[{"name": "Step", "done": "Done"}]
        )
        
        result = tools.update_task(task_id="T001", status="active")
        assert result["status"] == "active"

    def test_update_step_status(self, tools):
        """Test updating step status."""
        tools.create_task(
            name="Test",
            goal="Test",
            steps=[{"name": "Step 1", "done": "Done"}]
        )
        
        result = tools.update_task(task_id="T001", step_id="S1", step_status="done")
        assert result["steps"][0]["status"] == "done"
        assert result["progress"] == 1.0

    def test_delete_task(self, tools):
        """Test deleting a task."""
        tools.create_task(
            name="Test",
            goal="Test",
            steps=[{"name": "Step", "done": "Done"}]
        )
        
        result = tools.delete_task("T001")
        assert result["deleted"] is True
        
        # Verify deleted
        with pytest.raises(ValueError):
            tools.list_tasks(task_id="T001")

    def test_list_tasks_filter_by_status(self, tools):
        """Test listing tasks with status filter."""
        tools.create_task(name="Task 1", goal="Goal", steps=[{"name": "S", "done": "D"}])
        tools.create_task(name="Task 2", goal="Goal", steps=[{"name": "S", "done": "D"}])
        tools.update_task(task_id="T001", status="active")
        
        active_tasks = tools.list_tasks(status="active")
        assert len(active_tasks) == 1
        assert active_tasks[0]["id"] == "T001"


class TestEntryTools:
    """Tests for entry tools (notes and references)."""

    def test_add_note(self, tools):
        """Test adding a note."""
        result = tools.add_entry(type="note", content="Test note", score=50)
        
        assert result["id"] == "N001"
        assert result["type"] == "note"
        assert result["score"] == 50
        assert result["content"] == "Test note"

    def test_add_reference(self, tools):
        """Test adding a reference."""
        result = tools.add_entry(
            type="reference",
            content="Important file",
            uri="src/main.py:10-20",
            score=70
        )
        
        assert result["id"] == "R001"
        assert result["type"] == "reference"
        assert result["uri"] == "src/main.py:10-20"

    def test_add_reference_requires_uri(self, tools):
        """Test that reference requires URI."""
        with pytest.raises(ValueError, match="URI is required"):
            tools.add_entry(type="reference", content="Missing URI")

    def test_update_note_score(self, tools):
        """Test updating note score (renewing)."""
        tools.add_entry(type="note", content="Test", score=10)
        
        result = tools.update_entry(id="N001", score=50)
        assert result["score"] == 50

    def test_remove_note(self, tools):
        """Test removing a note."""
        tools.add_entry(type="note", content="Test")
        
        result = tools.remove_entry("N001")
        assert result["deleted"] is True
        
        # Verify removed from context
        context = tools.get_context()
        assert len(context["notes"]) == 0

    def test_remove_reference(self, tools):
        """Test removing a reference."""
        tools.add_entry(type="reference", content="Test", uri="test.py")
        
        result = tools.remove_entry("R001")
        assert result["deleted"] is True


class TestScoreDecayIntegration:
    """Integration tests for score decay."""

    def test_get_context_decays_scores(self, tools):
        """Test that get_context decays all scores."""
        tools.add_entry(type="note", content="Test note", score=20)
        tools.add_entry(type="reference", content="Test ref", uri="test.py", score=20)
        
        # First get_context
        result = tools.get_context()
        assert result["notes"][0]["score"] == 19
        assert result["references"][0]["score"] == 19
        
        # Second get_context
        result = tools.get_context()
        assert result["notes"][0]["score"] == 18
        assert result["references"][0]["score"] == 18

    def test_expiring_flag(self, tools):
        """Test expiring flag is set correctly."""
        tools.add_entry(type="note", content="Test", score=11)
        
        # Score becomes 10, not expiring
        result = tools.get_context()
        assert result["notes"][0]["expiring"] is False
        
        # After 10 more calls, score becomes 0, expiring
        for _ in range(10):
            tools.get_context()
        
        result = tools.get_context()
        assert result["notes"][0]["expiring"] is True


class TestErrorHandling:
    """Tests for error handling."""

    def test_invalid_task_id(self, tools):
        """Test error for invalid task ID."""
        with pytest.raises(ValueError, match="Invalid task ID format"):
            tools.create_task(
                name="Test",
                goal="Test",
                steps=[{"name": "S", "done": "D"}],
                task_id="invalid"
            )

    def test_task_not_found(self, tools):
        """Test error for missing task."""
        with pytest.raises(ValueError, match="Task not found"):
            tools.update_task(task_id="T999", status="active")

    def test_invalid_entry_type(self, tools):
        """Test error for invalid entry type."""
        with pytest.raises(ValueError, match="Invalid entry type"):
            tools.add_entry(type="invalid", content="Test")

    def test_entry_not_found(self, tools):
        """Test error for missing entry."""
        with pytest.raises(ValueError, match="not found"):
            tools.update_entry(id="N999", score=50)
