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

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


def current_timestamp_ms() -> int:
    """Get current timestamp in milliseconds."""
    return int(datetime.now().timestamp() * 1000)


# Base Event Model
class BaseEvent(BaseModel):
    """Base event model."""

    event: str = Field(..., description="Event type")
    track_id: str = Field(..., description="Unique track identifier")
    timestamp: int = Field(default_factory=current_timestamp_ms, description="Event timestamp in milliseconds")


# Lifecycle Events
class IncomingEvent(BaseEvent):
    """Incoming call event (SIP only)."""

    event: str = Field(default="incoming", description="Event type")
    caller: Optional[str] = Field(default=None, description="Caller's SIP URI")
    callee: Optional[str] = Field(default=None, description="Callee's SIP URI")
    sdp: Optional[str] = Field(default=None, description="SDP offer from caller")


class AnswerEvent(BaseEvent):
    """Call answered event."""

    event: str = Field(default="answer", description="Event type")
    sdp: Optional[str] = Field(default=None, description="SDP answer from server")


class RejectEvent(BaseEvent):
    """Call rejected event."""

    event: str = Field(default="reject", description="Event type")
    reason: Optional[str] = Field(default=None, description="Rejection reason")
    code: Optional[int] = Field(default=None, description="SIP response code")


class RingingEvent(BaseEvent):
    """Call ringing event."""

    event: str = Field(default="ringing", description="Event type")
    early_media: bool = Field(default=False, description="Early media available")


class HangupEvent(BaseModel):
    """Call hangup event."""

    event: str = Field(default="hangup", description="Event type")
    timestamp: int = Field(default_factory=current_timestamp_ms, description="Event timestamp")
    reason: Optional[str] = Field(default=None, description="Hangup reason")
    initiator: Optional[str] = Field(default=None, description="Who initiated hangup")
    start_time: Optional[str] = Field(default=None, description="Call start time (ISO 8601)")
    hangup_time: Optional[str] = Field(default=None, description="Hangup time (ISO 8601)")
    answer_time: Optional[str] = Field(default=None, description="Answer time (ISO 8601)")
    ringing_time: Optional[str] = Field(default=None, description="Ringing time (ISO 8601)")
    from_: Optional[Dict[str, Any]] = Field(default=None, alias="from", description="Caller info")
    to: Optional[Dict[str, Any]] = Field(default=None, description="Callee info")
    extra: Optional[Dict[str, Any]] = Field(default=None, description="Additional metadata")

    class Config:
        populate_by_name = True


# VAD Events
class SpeakingEvent(BaseEvent):
    """Speech detected event."""

    event: str = Field(default="speaking", description="Event type")
    start_time: int = Field(default_factory=current_timestamp_ms, description="Speech start time")


class SilenceEvent(BaseEvent):
    """Silence detected event."""

    event: str = Field(default="silence", description="Event type")
    start_time: int = Field(default_factory=current_timestamp_ms, description="Silence start time")
    duration: int = Field(default=0, description="Silence duration in milliseconds")


# AI/ASR Events
class AsrFinalEvent(BaseEvent):
    """ASR final transcription event."""

    event: str = Field(default="asrFinal", description="Event type")
    index: int = Field(..., description="ASR result sequence number")
    start_time: Optional[int] = Field(default=None, description="Speech start time")
    end_time: Optional[int] = Field(default=None, description="Speech end time")
    text: str = Field(..., description="Transcribed text")


class AsrDeltaEvent(BaseEvent):
    """ASR partial transcription event (streaming)."""

    event: str = Field(default="asrDelta", description="Event type")
    index: int = Field(..., description="ASR result sequence number")
    start_time: Optional[int] = Field(default=None, description="Speech start time")
    end_time: Optional[int] = Field(default=None, description="Speech end time")
    text: str = Field(..., description="Partial transcribed text")


class EouEvent(BaseEvent):
    """End of utterance detection event."""

    event: str = Field(default="eou", description="Event type")
    completed: bool = Field(default=True, description="Whether utterance was completed")


# Audio Track Events
class TrackStartEvent(BaseEvent):
    """Audio track start event."""

    event: str = Field(default="trackStart", description="Event type")
    play_id: Optional[str] = Field(default=None, description="Play ID from TTS/Play command")


class TrackEndEvent(BaseEvent):
    """Audio track end event."""

    event: str = Field(default="trackEnd", description="Event type")
    duration: int = Field(..., description="Track duration in milliseconds")
    ssrc: int = Field(..., description="RTP SSRC identifier")
    play_id: Optional[str] = Field(default=None, description="Play ID from TTS/Play command")


class InterruptionEvent(BaseEvent):
    """Playback interruption event."""

    event: str = Field(default="interruption", description="Event type")
    play_id: Optional[str] = Field(default=None, description="Play ID that was interrupted")
    subtitle: Optional[str] = Field(default=None, description="TTS text being played")
    position: Optional[int] = Field(default=None, description="Word index position")
    total_duration: Optional[int] = Field(default=None, description="Total TTS duration")
    current: Optional[int] = Field(default=None, description="Elapsed time when interrupted")


# System Events
class ErrorEvent(BaseEvent):
    """Error event."""

    event: str = Field(default="error", description="Event type")
    sender: str = Field(..., description="Component that generated the error")
    error: str = Field(..., description="Error message")
    code: Optional[int] = Field(default=None, description="Error code")


class MetricsEvent(BaseModel):
    """Performance metrics event."""

    event: str = Field(default="metrics", description="Event type")
    timestamp: int = Field(default_factory=current_timestamp_ms, description="Event timestamp")
    key: str = Field(..., description="Metric key")
    duration: int = Field(..., description="Duration in milliseconds")
    data: Optional[Dict[str, Any]] = Field(default=None, description="Additional metric data")


class AddHistoryEvent(BaseModel):
    """Conversation history entry added event."""

    event: str = Field(default="addHistory", description="Event type")
    timestamp: int = Field(default_factory=current_timestamp_ms, description="Event timestamp")
    sender: Optional[str] = Field(default=None, description="Component that added history")
    speaker: str = Field(..., description="Speaker identifier")
    text: str = Field(..., description="Conversation text")


class DTMFEvent(BaseEvent):
    """DTMF tone detected event."""

    event: str = Field(default="dtmf", description="Event type")
    digit: str = Field(..., description="DTMF digit (0-9, *, #, A-D)")


class HeartBeatEvent(BaseModel):
    """Server-to-client heartbeat to keep connection alive."""

    event: str = Field(default="heartBeat", description="Event type")
    timestamp: int = Field(default_factory=current_timestamp_ms, description="Event timestamp in milliseconds")


# Event type mapping
EVENT_TYPES = {
    "incoming": IncomingEvent,
    "answer": AnswerEvent,
    "reject": RejectEvent,
    "ringing": RingingEvent,
    "hangup": HangupEvent,
    "speaking": SpeakingEvent,
    "silence": SilenceEvent,
    "asrFinal": AsrFinalEvent,
    "asrDelta": AsrDeltaEvent,
    "eou": EouEvent,
    "trackStart": TrackStartEvent,
    "trackEnd": TrackEndEvent,
    "interruption": InterruptionEvent,
    "error": ErrorEvent,
    "metrics": MetricsEvent,
    "addHistory": AddHistoryEvent,
    "dtmf": DTMFEvent,
    "heartBeat": HeartBeatEvent,
}


def create_event(event_type: str, **kwargs) -> BaseModel:
    """
    Create an event model.

    Args:
        event_type: Type of event to create
        **kwargs: Event fields

    Returns:
        Event model instance

    Raises:
        ValueError: If event type is unknown
    """
    event_class = EVENT_TYPES.get(event_type)

    if not event_class:
        raise ValueError(f"Unknown event type: {event_type}")

    return event_class(event=event_type, **kwargs)
