from abc import ABC, abstractmethod
from typing import Any, Optional, Callable, List


class Command(ABC):
    name: str = ""
    description: str = ""

    @abstractmethod
    def execute(self, args: Any) -> bool:
        pass

    def can_execute(self, args: Any) -> bool:
        return True


class ExitCommand(Command):
    name = "exit"
    description = "Exit the CLI"

    def execute(self, args: Any) -> bool:
        return True


class CommandParameter:
    """Command parameter model"""
    def __init__(
        self,
        name: str,
        param_type: str = None,
        description: str = "",
        required: bool = False,
        default: Any = None,
        type: str = None
    ):
        self.name = name
        self.param_type = param_type or type or "str"
        self.description = description
        self.required = required
        self.default = default

    def to_dict(self) -> dict:
        return {
            "name": self.name,
            "type": self.param_type,
            "description": self.description,
            "required": self.required,
            "default": self.default
        }


class CommandModel:
    """Command model for registered commands"""
    def __init__(
        self,
        name: str,
        description: str,
        implementation: Callable,
        parameters: Optional[List[CommandParameter]] = None
    ):
        self.name = name
        self.description = description
        self.implementation = implementation
        self.parameters = parameters or []

    def execute(self, args: Any) -> Any:
        return self.implementation(args)


_registry: Optional["CommandRegistry"] = None


class CommandRegistry:
    def __init__(self):
        self._commands: dict[str, Command] = {}
        self._registered_commands: dict[str, CommandModel] = {}

    def register(self, name: str, command: Command) -> None:
        self._commands[name] = command

    def register_model(self, model: CommandModel) -> None:
        """Register a CommandModel as a command"""
        self._registered_commands[model.name] = model
        command = CommandModelCommand(model)
        self._commands[model.name] = command

    def register_models(self, models: List[CommandModel]) -> None:
        """Register multiple CommandModels"""
        for model in models:
            self.register_model(model)

    def unregister(self, name: str) -> bool:
        if name in self._commands:
            del self._commands[name]
        if name in self._registered_commands:
            del self._registered_commands[name]
            return True
        return False

    def get(self, name: str) -> Optional[Command]:
        return self._commands.get(name)

    def get_model(self, name: str) -> Optional[CommandModel]:
        return self._registered_commands.get(name)

    def list_all(self) -> list[Command]:
        return list(self._commands.values())

    def list_registered(self) -> list[CommandModel]:
        return list(self._registered_commands.values())

    def list_names(self) -> set:
        return set(self._commands.keys())

    def has(self, name: str) -> bool:
        return name in self._commands


class CommandModelCommand(Command):
    """Wrapper to convert CommandModel to Command"""
    def __init__(self, model: CommandModel):
        self._model = model

    @property
    def name(self) -> str:
        return self._model.name

    @property
    def description(self) -> str:
        return self._model.description

    def execute(self, args: Any) -> bool:
        return self._model.execute(args)


def get_command_registry() -> CommandRegistry:
    global _registry
    if _registry is None:
        _registry = CommandRegistry()
    return _registry
