"""Integration tests for the Mesh runtime."""

from __future__ import annotations

import pytest

from a2a_mesh.exceptions import AgentNotFoundError, NoCapableAgentError
from a2a_mesh.models import (
    AgentCard,
    RoutingPolicy,
    RoutingStrategy,
    Task,
    TaskStatus,
    Workflow,
)
from a2a_mesh.mesh import Mesh


class TestMesh:
    """Integration tests for the Mesh class."""

    def test_initialization(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        assert mesh.port == 9000
        assert mesh.registry is not None
        assert mesh.router is not None
        assert mesh.auth is not None
        assert mesh.tracer is not None

    def test_register_agent(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        card = AgentCard(
            name="test-agent",
            capabilities=["testing"],
        )
        agent = mesh.register(card)
        assert agent.card.name == "test-agent"

    def test_register_and_deregister(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        card = AgentCard(name="temp", capabilities=["x"])
        mesh.register(card)
        mesh.deregister("temp")
        with pytest.raises(AgentNotFoundError):
            mesh.registry.get("temp")

    @pytest.mark.asyncio
    async def test_dispatch_local_agent(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        mesh.register(AgentCard(
            name="echo",
            capabilities=["echo"],
        ))
        result = await mesh.dispatch(
            task="hello world",
            required_capabilities=["echo"],
        )
        assert result["agent"] == "echo"
        assert result["input"] == "hello world"
        assert result["status"] == "completed"

    @pytest.mark.asyncio
    async def test_dispatch_no_agent_raises(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        with pytest.raises(NoCapableAgentError):
            await mesh.dispatch(
                task="test",
                required_capabilities=["nonexistent_cap"],
            )

    @pytest.mark.asyncio
    async def test_dispatch_task_object(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        mesh.register(AgentCard(
            name="worker",
            capabilities=["work"],
        ))
        task = Task(
            name="job",
            input="do something",
            required_capabilities=["work"],
        )
        result = await mesh.dispatch(task)
        assert result["agent"] == "worker"

    @pytest.mark.asyncio
    async def test_workflow_execution(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        mesh.register(AgentCard(name="a1", capabilities=["step1"]))
        mesh.register(AgentCard(name="a2", capabilities=["step2"]))

        workflow = Workflow(
            name="pipeline",
            tasks=[
                Task(name="first", agent="a1", input="start"),
                Task(name="second", agent="a2", depends_on=["first"]),
            ],
        )
        result = await mesh.execute_workflow(workflow)
        assert result.status == TaskStatus.COMPLETED
        assert "first" in result.task_results
        assert "second" in result.task_results

    @pytest.mark.asyncio
    async def test_traces_recorded(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        mesh.register(AgentCard(name="traced", capabilities=["trace_test"]))
        await mesh.dispatch("test", required_capabilities=["trace_test"])

        traces = mesh.traces(limit=10)
        assert len(traces) >= 1

    @pytest.mark.asyncio
    async def test_start_and_stop(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING", health_interval=600.0)
        await mesh.start()
        await mesh.stop()

    def test_auth_integration(self) -> None:
        mesh = Mesh(port=9000, log_level="WARNING")
        token = mesh.auth.issue_token(
            issuer="agent-a",
            subject="agent-b",
            scopes=["dispatch"],
        )
        claims = mesh.auth.validate_token(token.token)
        assert claims["iss"] == "agent-a"

    @pytest.mark.asyncio
    async def test_routing_policy(self) -> None:
        mesh = Mesh(
            port=9000,
            log_level="WARNING",
            policy=RoutingPolicy(strategy=RoutingStrategy.LEAST_COST),
        )
        mesh.register(AgentCard(
            name="cheap",
            capabilities=["work"],
            cost_per_task=0.01,
        ))
        mesh.register(AgentCard(
            name="expensive",
            capabilities=["work"],
            cost_per_task=0.10,
        ))

        result = await mesh.dispatch("test", required_capabilities=["work"])
        assert result["agent"] == "cheap"
