import json

import pytest
from agents import RunContextWrapper
from pydantic import BaseModel, Field

from agency_swarm import Agency, Agent, ModelSettings
from agency_swarm.context import MasterContext
from agency_swarm.tools.send_message import SendMessage
from agency_swarm.utils.thread import ThreadManager


class ExtraParams(BaseModel):
    key_moments: str = Field(description="Important context")
    decisions: str = Field(description="Decisions made")


class SendMessageWithContext(SendMessage):
    extra_params_model = ExtraParams


class NestedSendMessage(SendMessage):
    class ExtraParams(BaseModel):
        summary: str = Field(description="Short summary")


@pytest.mark.asyncio
async def test_schema_includes_extra_params_for_explicit_and_nested_models():
    a = Agent(name="A", instructions="", model_settings=ModelSettings(temperature=0.0))
    b = Agent(name="B", instructions="", model_settings=ModelSettings(temperature=0.0))

    explicit_agency = Agency(a, communication_flows=[(a > b, SendMessageWithContext)])
    explicit_tool = next(iter(explicit_agency.get_agent_runtime_state("A").send_message_tools.values()))
    explicit_props = explicit_tool.params_json_schema.get("properties", {})
    explicit_required = explicit_tool.params_json_schema.get("required", [])
    assert "key_moments" in explicit_props and explicit_props["key_moments"]["type"] == "string"
    assert "decisions" in explicit_props and explicit_props["decisions"]["type"] == "string"
    assert "key_moments" in explicit_required and "decisions" in explicit_required

    nested_agency = Agency(a, communication_flows=[(a > b, NestedSendMessage)])
    nested_tool = next(iter(nested_agency.get_agent_runtime_state("A").send_message_tools.values()))
    nested_props = nested_tool.params_json_schema.get("properties", {})
    nested_required = nested_tool.params_json_schema.get("required", [])
    assert "summary" in nested_props and nested_props["summary"]["type"] == "string"
    assert "summary" in nested_required


@pytest.mark.asyncio
async def test_validation_of_extra_params_errors():
    a = Agent(
        name="A",
        instructions="Use send_message to talk to B and include fields.",
        model_settings=ModelSettings(temperature=0.0),
    )
    b = Agent(name="B", instructions="Reply with OK", model_settings=ModelSettings(temperature=0.0))
    agency = Agency(a, communication_flows=[(a > b, SendMessageWithContext)])

    runtime_state = agency.get_agent_runtime_state("A")
    send_tool = next(iter(runtime_state.send_message_tools.values()))

    args = {
        "recipient_agent": "B",
        "message": "hi",
        "additional_instructions": "",
    }

    wrapper = RunContextWrapper(context=MasterContext(thread_manager=ThreadManager(), agents={}))
    out = await send_tool.on_invoke_tool(wrapper, json.dumps(args))
    assert isinstance(out, str) and out.startswith("Error: Invalid extra parameters")
