"""Protocol command models matching the original active-call API."""

from typing import Optional, Dict, Any
from pydantic import BaseModel, Field


class InviteCommand(BaseModel):
    """Invite command to initiate a call."""

    command: str = Field(default="invite", description="Command type")
    option: Optional[Dict[str, Any]] = Field(default=None, description="Call configuration options")


class AcceptCommand(BaseModel):
    """Accept command to accept an incoming call."""

    command: str = Field(default="accept", description="Command type")
    option: Optional[Dict[str, Any]] = Field(default=None, description="Call configuration options")


class RejectCommand(BaseModel):
    """Reject command to reject an incoming call."""

    command: str = Field(default="reject", description="Command type")
    reason: str = Field(default="", description="Reason for rejection")
    code: Optional[int] = Field(default=None, description="SIP response code")


class RingingCommand(BaseModel):
    """Ringing command to send ringing response."""

    command: str = Field(default="ringing", description="Command type")
    recorder: Optional[Dict[str, Any]] = Field(default=None, description="Call recording configuration")
    early_media: bool = Field(default=False, description="Enable early media")
    ringtone: Optional[str] = Field(default=None, description="Custom ringtone URL")


class TTSCommand(BaseModel):
    """TTS command to convert text to speech."""

    command: str = Field(default="tts", description="Command type")
    text: str = Field(..., description="Text to synthesize")
    speaker: Optional[str] = Field(default=None, description="Speaker voice name")
    play_id: Optional[str] = Field(default=None, description="Unique identifier for this TTS session")
    auto_hangup: bool = Field(default=False, description="Auto hangup after TTS completion")
    streaming: bool = Field(default=False, description="Streaming text input")
    end_of_stream: bool = Field(default=False, description="End of streaming input")
    wait_input_timeout: Optional[int] = Field(default=None, description="Max time to wait for input (seconds)")
    option: Optional[Dict[str, Any]] = Field(default=None, description="TTS provider specific options")


class PlayCommand(BaseModel):
    """Play command to play audio from URL."""

    command: str = Field(default="play", description="Command type")
    url: str = Field(..., description="URL of audio file to play")
    auto_hangup: bool = Field(default=False, description="Auto hangup after playback")
    wait_input_timeout: Optional[int] = Field(default=None, description="Max time to wait for input (seconds)")


class InterruptCommand(BaseModel):
    """Interrupt command to interrupt current playback."""

    command: str = Field(default="interrupt", description="Command type")
    graceful: bool = Field(default=False, description="Wait for current TTS to complete")


class PauseCommand(BaseModel):
    """Pause command to pause current playback."""

    command: str = Field(default="pause", description="Command type")


class ResumeCommand(BaseModel):
    """Resume command to resume paused playback."""

    command: str = Field(default="resume", description="Command type")


class HangupCommand(BaseModel):
    """Hangup command to end the call."""

    command: str = Field(default="hangup", description="Command type")
    reason: Optional[str] = Field(default=None, description="Reason for hangup")
    initiator: Optional[str] = Field(default=None, description="Who initiated the hangup")


class HistoryCommand(BaseModel):
    """History command to add conversation history."""

    command: str = Field(default="history", description="Command type")
    speaker: str = Field(..., description="Speaker identifier")
    text: str = Field(..., description="Conversation text")


class ChatCommand(BaseModel):
    """Chat command for text-based conversation."""

    command: str = Field(default="chat", description="Command type")
    text: str = Field(..., description="Chat text message")


# Command type mapping
COMMAND_TYPES = {
    "invite": InviteCommand,
    "accept": AcceptCommand,
    "reject": RejectCommand,
    "ringing": RingingCommand,
    "tts": TTSCommand,
    "play": PlayCommand,
    "interrupt": InterruptCommand,
    "pause": PauseCommand,
    "resume": ResumeCommand,
    "hangup": HangupCommand,
    "history": HistoryCommand,
    "chat": ChatCommand,
}


def parse_command(data: Dict[str, Any]) -> BaseModel:
    """
    Parse a command from JSON data.

    Args:
        data: JSON data as dictionary

    Returns:
        Parsed command model

    Raises:
        ValueError: If command type is unknown
    """
    command_type = data.get("command")

    if not command_type:
        raise ValueError("Missing 'command' field")

    command_class = COMMAND_TYPES.get(command_type)

    if not command_class:
        raise ValueError(f"Unknown command type: {command_type}")

    return command_class(**data)
