"""Type-safe event models for sandbox execution SSE streaming"""

import json
from enum import Enum
from typing import Any

from pydantic import BaseModel


class SandboxError(Exception):
    pass


class SSEEventType(str, Enum):
    """Event types for Server-Sent Events"""

    BROWSER_CREATED = "browser_created"
    INSTANCE_CREATED = "instance_created"
    INSTANCE_READY = "instance_ready"
    LOG = "log"
    RESULT = "result"
    ERROR = "error"
    STREAM_COMPLETE = "stream_complete"


class BrowserCreatedData(BaseModel):
    """Data for browser_created event"""

    session_id: str
    live_url: str
    status: str


class LogData(BaseModel):
    """Data for log event"""

    message: str
    level: str = "info"  # stdout, stderr, info, warning, error


class ExecutionResponse(BaseModel):
    """Execution result from the executor"""

    success: bool
    result: Any = None
    error: str | None = None
    traceback: str | None = None


class ResultData(BaseModel):
    """Data for result event"""

    execution_response: ExecutionResponse


class ErrorData(BaseModel):
    """Data for error event"""

    error: str
    traceback: str | None = None
    status_code: int = 500


class SSEEvent(BaseModel):
    """Type-safe SSE Event

    Usage:
        # Parse from JSON
        event = SSEEvent.from_json(event_json_string)

        # Type-safe access with type guards
        if event.is_browser_created():
            assert isinstance(event.data, BrowserCreatedData)
            print(event.data.live_url)

        # Or check event type directly
        if event.type == SSEEventType.LOG:
            assert isinstance(event.data, LogData)
            print(event.data.message)
    """

    type: SSEEventType
    data: BrowserCreatedData | LogData | ResultData | ErrorData | dict[str, Any]
    timestamp: str | None = None

    @classmethod
    def from_json(cls, event_json: str) -> "SSEEvent":
        """Parse SSE event from JSON string with proper type discrimination

        Args:
            event_json: JSON string from SSE stream

        Returns:
            Typed SSEEvent with appropriate data model

        Raises:
            json.JSONDecodeError: If JSON is malformed
            ValueError: If event type is invalid
        """
        raw_data = json.loads(event_json)
        event_type = SSEEventType(raw_data.get("type"))
        data_dict = raw_data.get("data", {})

        # Parse data based on event type
        if event_type == SSEEventType.BROWSER_CREATED:
            data = BrowserCreatedData(**data_dict)
        elif event_type == SSEEventType.LOG:
            data = LogData(**data_dict)
        elif event_type == SSEEventType.RESULT:
            data = ResultData(**data_dict)
        elif event_type == SSEEventType.ERROR:
            data = ErrorData(**data_dict)
        else:
            data = data_dict

        return cls(type=event_type, data=data, timestamp=raw_data.get("timestamp"))

    def is_browser_created(self) -> bool:
        """Type guard for BrowserCreatedData"""
        return self.type == SSEEventType.BROWSER_CREATED and isinstance(self.data, BrowserCreatedData)

    def is_log(self) -> bool:
        """Type guard for LogData"""
        return self.type == SSEEventType.LOG and isinstance(self.data, LogData)

    def is_result(self) -> bool:
        """Type guard for ResultData"""
        return self.type == SSEEventType.RESULT and isinstance(self.data, ResultData)

    def is_error(self) -> bool:
        """Type guard for ErrorData"""
        return self.type == SSEEventType.ERROR and isinstance(self.data, ErrorData)
