from abc import ABC, abstractmethod
from typing import Optional


class Mode(ABC):
    @property
    @abstractmethod
    def name(self) -> str:
        pass

    @property
    @abstractmethod
    def prompt_prefix(self) -> str:
        pass

    @abstractmethod
    def should_exit(self, user_input: str) -> bool:
        pass

    def on_activate(self):
        pass

    def on_deactivate(self):
        pass


class ClientMode(Mode):
    name = "client"
    prompt_prefix = "<diona@local>"
    
    def should_exit(self, user_input: str) -> bool:
        return False


class AgentMode(Mode):
    name = "agent"
    prompt_prefix = "<agent:diona>"
    
    def should_exit(self, user_input: str) -> bool:
        return user_input.strip().lower() in ("$exit", "exit")


class WebMode(Mode):
    name = "web"
    prompt_prefix = "<web:diona>"
    
    def should_exit(self, user_input: str) -> bool:
        return False


class ModeManager:
    _instance: Optional["ModeManager"] = None

    def __new__(cls) -> "ModeManager":
        if cls._instance is None:
            cls._instance = super().__new__(cls)
            cls._instance._initialized = False
        return cls._instance

    def __init__(self):
        if self._initialized:
            return
        self._modes: dict[str, Mode] = {}
        self._current_mode: Optional[Mode] = None
        self._register_default_modes()
        self._initialized = True

    def _register_default_modes(self):
        self._modes["client"] = ClientMode()
        self._modes["agent"] = AgentMode()
        self._modes["web"] = WebMode()
        self._current_mode = self._modes["client"]

    def register(self, mode: Mode) -> None:
        self._modes[mode.name] = mode

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

    def set_mode(self, name: str) -> bool:
        mode = self._modes.get(name)
        if mode is None:
            return False
        if self._current_mode is not None:
            self._current_mode.on_deactivate()
        self._current_mode = mode
        self._current_mode.on_activate()
        return True

    def exit_mode(self) -> bool:
        if self._current_mode is None:
            return False
        self._current_mode.on_deactivate()
        self._current_mode = None
        return True

    @property
    def current_mode(self) -> Optional[Mode]:
        return self._current_mode

    @property
    def is_default_mode(self) -> bool:
        return self._current_mode is None or self._current_mode.name == "client"


_manager: Optional[ModeManager] = None


def get_mode_manager() -> ModeManager:
    global _manager
    if _manager is None:
        _manager = ModeManager()
    return _manager
