from __future__ import annotations

from pydantic import BaseModel

from yera.agents.exceptions import ErrorCause
from yera.events.blocks.base import _BlockFactory
from yera.events.models import ExitEventData, FailureExitEventData, SuccessExitEventData
from yera.events.stream import push_output


class _ExitBlockFactory(_BlockFactory):
    def __init__(self):
        super().__init__("exit")

    def __call__(
        self,
        exit_code: int,
        reason: str,
        return_value: str | None,
        *,
        error_cause: ErrorCause | None = None,
    ):
        return_type = type(return_value).__name__

        if isinstance(return_value, BaseModel):
            return_value = return_value.model_dump_json()

        data: ExitEventData = (
            SuccessExitEventData(
                exit_code=0,
                reason=reason,
                return_type=return_type,
                return_value=str(return_value),
            )
            if exit_code == 0
            else FailureExitEventData(
                exit_code=exit_code,
                reason=reason,
                return_type=return_type,
                return_value=str(return_value),
                error_cause=error_cause,
            )
        )

        event = self._create_block_output_event(
            data=data,
            message_type="informational",
        )
        push_output(event)


exit_event = _ExitBlockFactory()


def quit_event():
    exit_event(exit_code=0, reason="User quit", return_value=None)


def unsupported_block_event(block_type: str) -> None:
    """Push an exit event for an unsupported await_user block (e.g. form).

    Block factories use this when is_restricted_stream() is True, then raise
    UnsupportedAwaitUserBlockError. Uses exit_event() so the event has the correct
    agent_instance from the current context.
    """
    reason = (
        f"Block type {block_type!r} is not supported by the built-in stream handler. "
        "Run this agent using the stream server (web UI) via the `yera` CLI."
    )
    exit_event(
        exit_code=1,
        reason=reason,
        return_value=None,
        error_cause=ErrorCause(
            error_type="UnsupportedAwaitUserBlockError",
            block_type=block_type,
        ),
    )


__all__ = ["exit_event", "quit_event", "unsupported_block_event"]
