"""Game registry and operation dispatch.

Central registry for game engines and operation routing.
"""

from __future__ import annotations

from typing import Any, Protocol

from purefn.core.result import PureResult, error


class GameEngine(Protocol):
    """Protocol for game engines."""

    def dispatch(self, op: str, global_token: str, args: dict[str, Any]) -> PureResult:
        """Dispatch an operation.

        Args:
            op: Operation name
            global_token: Current global state token
            args: Operation arguments

        Returns:
            Result of the operation
        """
        ...


class GameRegistry:
    """Registry of available game engines."""

    def __init__(self) -> None:
        self._games: dict[str, GameEngine] = {}

    def register(self, name: str, engine: GameEngine) -> None:
        """Register a game engine.

        Args:
            name: Game name (e.g., "cards", "chess")
            engine: Game engine instance
        """
        self._games[name] = engine

    def get(self, name: str) -> GameEngine | None:
        """Get a game engine by name.

        Args:
            name: Game name

        Returns:
            Game engine or None if not found
        """
        return self._games.get(name)

    def list_games(self) -> list[str]:
        """List registered game names.

        Returns:
            List of game names
        """
        return list(self._games.keys())


# Global registry instance
_registry = GameRegistry()


def register_game(name: str, engine: GameEngine) -> None:
    """Register a game engine globally.

    Args:
        name: Game name
        engine: Game engine instance
    """
    _registry.register(name, engine)


def get_game(name: str) -> GameEngine | None:
    """Get a registered game engine.

    Args:
        name: Game name

    Returns:
        Game engine or None
    """
    return _registry.get(name)


def list_games() -> list[str]:
    """List all registered games.

    Returns:
        List of game names
    """
    return _registry.list_games()


def apply_envelope(envelope: dict[str, Any]) -> dict[str, Any]:
    """Apply an operation envelope.

    Dispatches to the appropriate game engine.

    Args:
        envelope: Operation envelope with keys:
            - game: Game name
            - op: Operation name
            - global: Global token (optional, empty string for "new")
            - args: Operation arguments

    Returns:
        Result dictionary
    """
    try:
        game_name = envelope.get("game")
        if not game_name:
            return error("Missing 'game' field in envelope").to_dict()

        op = envelope.get("op")
        if not op:
            return error("Missing 'op' field in envelope").to_dict()

        engine = get_game(game_name)
        if not engine:
            return error(f"Unknown game: {game_name}").to_dict()

        global_token = envelope.get("global", "")
        args = envelope.get("args", {})

        result = engine.dispatch(op, global_token, args)
        return result.to_dict()

    except Exception as e:
        return error(f"Dispatch error: {str(e)}").to_dict()
