"""Tests for anima.logs() MCP tool."""

from __future__ import annotations

import asyncio
import json
from pathlib import Path
from unittest.mock import MagicMock

import pytest

from anima.shell.mcp_agent import AgentMCPServer


@pytest.fixture
def mock_agent_runner() -> MagicMock:
    """Create a mock agent runner for AgentMCPServer."""
    runner = MagicMock()
    runner.instance_id = "ag_test_logs"
    return runner


class TestLogsTool:
    """Tests for the anima.logs MCP tool."""

    @pytest.fixture
    def short_state_dir(self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
        """Create a temporary state directory."""
        state_dir = tmp_path / "anima_state"
        state_dir.mkdir(parents=True, exist_ok=True)
        monkeypatch.setenv("ANIMA_STATE", str(state_dir))
        return state_dir

    @pytest.mark.asyncio
    async def test_logs_missing_file_returns_empty_entries(
        self, short_state_dir: Path, mock_agent_runner: MagicMock
    ) -> None:
        """Missing log.jsonl returns empty entries gracefully."""
        instance_id = "inst_logs_missing"
        mock_agent_runner.instance_id = instance_id

        server = AgentMCPServer(instance_id, mock_agent_runner)
        await server.start()

        try:
            await asyncio.sleep(0.1)

            result = await server._handle_logs()

            assert result["instance_id"] == instance_id
            assert result["entries"] == []
            assert result["count"] == 0
        finally:
            await server.stop()

    @pytest.mark.asyncio
    async def test_logs_with_entries(
        self, short_state_dir: Path, mock_agent_runner: MagicMock
    ) -> None:
        """Log file with entries returns parsed JSON."""
        import asyncio

        instance_id = "inst_logs_with_entries"
        mock_agent_runner.instance_id = instance_id

        # Create log.jsonl file with entries
        log_dir = short_state_dir / "agents" / instance_id
        log_dir.mkdir(parents=True, exist_ok=True)
        log_file = log_dir / "log.jsonl"

        log_entries = [
            {"event": "start", "timestamp": "2024-01-01T00:00:00Z"},
            {"event": "message", "content": "hello"},
            {"event": "finish", "timestamp": "2024-01-01T00:01:00Z"},
        ]
        log_file.write_text("\n".join(json.dumps(e) for e in log_entries))

        server = AgentMCPServer(instance_id, mock_agent_runner)
        await server.start()

        try:
            await asyncio.sleep(0.1)

            result = await server._handle_logs()

            assert result["instance_id"] == instance_id
            assert result["count"] == 3
            assert len(result["entries"]) == 3
            assert result["entries"][0]["event"] == "start"
            assert result["entries"][1]["event"] == "message"
            assert result["entries"][2]["event"] == "finish"
        finally:
            await server.stop()

    @pytest.mark.asyncio
    async def test_logs_tail_returns_last_n_entries(
        self, short_state_dir: Path, mock_agent_runner: MagicMock
    ) -> None:
        """Tail parameter returns only last N lines."""
        import asyncio

        instance_id = "inst_logs_tail"
        mock_agent_runner.instance_id = instance_id

        # Create log.jsonl file with entries
        log_dir = short_state_dir / "agents" / instance_id
        log_dir.mkdir(parents=True, exist_ok=True)
        log_file = log_dir / "log.jsonl"

        log_entries = [
            {"event": "start", "timestamp": "2024-01-01T00:00:00Z"},
            {"event": "message", "content": "hello"},
            {"event": "finish", "timestamp": "2024-01-01T00:01:00Z"},
        ]
        log_file.write_text("\n".join(json.dumps(e) for e in log_entries))

        server = AgentMCPServer(instance_id, mock_agent_runner)
        await server.start()

        try:
            await asyncio.sleep(0.1)

            result = await server._handle_logs(tail=2)

            assert result["count"] == 2
            assert len(result["entries"]) == 2
            # Should be last 2 entries
            assert result["entries"][0]["event"] == "message"
            assert result["entries"][1]["event"] == "finish"
        finally:
            await server.stop()

    @pytest.mark.asyncio
    async def test_logs_empty_file_returns_empty(
        self, short_state_dir: Path, mock_agent_runner: MagicMock
    ) -> None:
        """Empty log.jsonl returns empty entries."""
        import asyncio

        instance_id = "inst_logs_empty"
        mock_agent_runner.instance_id = instance_id

        # Create empty log.jsonl file
        log_dir = short_state_dir / "agents" / instance_id
        log_dir.mkdir(parents=True, exist_ok=True)
        log_file = log_dir / "log.jsonl"
        log_file.write_text("")

        server = AgentMCPServer(instance_id, mock_agent_runner)
        await server.start()

        try:
            await asyncio.sleep(0.1)

            result = await server._handle_logs()

            assert result["entries"] == []
            assert result["count"] == 0
        finally:
            await server.stop()

    @pytest.mark.asyncio
    async def test_logs_skips_malformed_json_lines(
        self, short_state_dir: Path, mock_agent_runner: MagicMock
    ) -> None:
        """Malformed JSON lines are skipped gracefully."""
        import asyncio

        instance_id = "inst_logs_malformed"
        mock_agent_runner.instance_id = instance_id

        # Create log.jsonl file with some malformed lines
        log_dir = short_state_dir / "agents" / instance_id
        log_dir.mkdir(parents=True, exist_ok=True)
        log_file = log_dir / "log.jsonl"

        # Mix of valid and invalid JSON
        content = '{"event": "start"}\nnot valid json\n{"event": "finish"}\n'
        log_file.write_text(content)

        server = AgentMCPServer(instance_id, mock_agent_runner)
        await server.start()

        try:
            await asyncio.sleep(0.1)

            result = await server._handle_logs()

            # Should have 2 valid entries
            assert result["count"] == 2
            assert result["entries"][0]["event"] == "start"
            assert result["entries"][1]["event"] == "finish"
        finally:
            await server.stop()
