"""AgentCard configuration and builder utilities."""

from __future__ import annotations

from typing import Any, Literal

from a2a.types import (
    AgentCapabilities,
    AgentCard,
    AgentExtension,
    AgentInterface,
    AgentSkill,
    TransportProtocol,
)
from pydantic import BaseModel, Field, model_validator


class SkillConfig(BaseModel):
    """User-friendly skill definition without A2A protocol imports."""

    id: str
    name: str
    description: str
    tags: list[str] = Field(default_factory=list)
    examples: list[str] = Field(default_factory=list)


class ExtensionConfig(BaseModel):
    """User-friendly extension definition without A2A protocol imports."""

    uri: str
    description: str | None = None
    params: dict[str, Any] = Field(default_factory=dict)


class CapabilitiesConfig(BaseModel):
    """Declares which A2A protocol features this agent supports.

    All capabilities default to False (opt-in). Features not yet
    implemented by a2akit raise NotImplementedError when set to True.
    """

    streaming: bool = False
    push_notifications: bool = False
    extended_agent_card: bool = False
    extensions: list[AgentExtension] | None = None

    @model_validator(mode="after")
    def _check_not_yet_supported(self) -> CapabilitiesConfig:
        unsupported = {
            "push_notifications": self.push_notifications,
            "extended_agent_card": self.extended_agent_card,
            "extensions": bool(self.extensions),
        }
        for name, enabled in unsupported.items():
            if enabled:
                raise NotImplementedError(f"{name} is not yet supported by a2akit.")
        return self


class AgentCardConfig(BaseModel):
    """User-friendly configuration for building an AgentCard."""

    name: str
    description: str
    version: str = "1.0.0"
    protocol_version: str = "0.3.0"
    skills: list[SkillConfig] = Field(default_factory=list)
    extensions: list[ExtensionConfig] = Field(default_factory=list)

    capabilities: CapabilitiesConfig = Field(default_factory=CapabilitiesConfig)

    protocol: Literal["jsonrpc", "http+json"] = "jsonrpc"

    input_modes: list[str] = Field(default_factory=lambda: ["application/json", "text/plain"])
    output_modes: list[str] = Field(default_factory=lambda: ["application/json", "text/plain"])


def _to_agent_skill(skill: SkillConfig) -> AgentSkill:
    """Convert a SkillConfig to the A2A AgentSkill type."""
    return AgentSkill(
        id=skill.id,
        name=skill.name,
        description=skill.description,
        tags=skill.tags or None,
        examples=skill.examples or None,
    )


def _to_agent_extension(ext: ExtensionConfig) -> AgentExtension:
    """Convert an ExtensionConfig to the A2A AgentExtension type."""
    return AgentExtension(
        uri=ext.uri,
        description=ext.description,
        params=ext.params or None,
    )


def validate_protocol(protocol: str) -> str:
    """Validate the protocol string, raising ValueError for unsupported values."""
    supported = ["http+json", "jsonrpc"]
    if protocol == "grpc":
        msg = f"Protocol 'grpc' is not yet supported by a2akit. Supported protocols: {supported}"
        raise ValueError(msg)
    if protocol not in supported:
        msg = f"Unknown protocol {protocol!r}. Supported protocols: {supported}"
        raise ValueError(msg)
    return protocol


def build_agent_card(config: AgentCardConfig, base_url: str) -> AgentCard:
    """Build a full AgentCard from user config and the runtime base URL."""
    stripped = base_url.rstrip("/")
    if config.protocol == "jsonrpc":
        agent_url = stripped
        transport = TransportProtocol.jsonrpc
    else:
        agent_url = f"{stripped}/v1"
        transport = TransportProtocol.http_json

    caps = config.capabilities
    return AgentCard(
        protocol_version=config.protocol_version,
        name=config.name,
        description=config.description,
        url=agent_url,
        preferred_transport=transport,
        additional_interfaces=[
            AgentInterface(url=agent_url, transport=transport),
        ],
        version=config.version,
        capabilities=AgentCapabilities(
            extensions=[_to_agent_extension(e) for e in config.extensions] or None,
            streaming=caps.streaming,
            push_notifications=caps.push_notifications,
            state_transition_history=False,
        ),
        default_input_modes=config.input_modes,
        default_output_modes=config.output_modes,
        skills=[_to_agent_skill(s) for s in config.skills],
        supports_authenticated_extended_card=caps.extended_agent_card,
    )


def external_base_url(headers: dict[str, str], scheme: str, netloc: str) -> str:
    """Derive the external base URL from request headers (proxy-aware)."""
    resolved_scheme = (headers.get("x-forwarded-proto") or scheme).split(",")[0].strip()
    resolved_host = (
        (headers.get("x-forwarded-host") or headers.get("host") or netloc).split(",")[0].strip()
    )
    return f"{resolved_scheme}://{resolved_host}"
