from __future__ import annotations

from typing import Dict, Iterable, Optional, Tuple

from .command_bundle import AsyncHandlerWithWriter, CommandBundle


class CommandSetHandler:
    def __init__(self, command_bundle: CommandBundle) -> None:
        self._static_commands: Dict[str, str] = dict(command_bundle.static_commands)
        self._dynamic_commands: Dict[str, AsyncHandlerWithWriter] = dict(command_bundle.dynamic_commands)
        self._prefix_commands: Dict[str, AsyncHandlerWithWriter] = dict(command_bundle.prefix_commands)

    def can_handle(self, request: str) -> bool:
        if request in self._static_commands:
            return True
        if request in self._dynamic_commands:
            return True
        for prefix in self._prefix_commands:
            if request.startswith(prefix):
                return True
        return False

    def handle(self, request: str, adapter: "Adapter", writer: callable) -> None:
        if request in self._static_commands:
            writer(self._static_commands[request])
            return
        if request in self._dynamic_commands:
            self._dynamic_commands[request](request, adapter, writer)
            return
        match = self._match_prefix(request)
        if match is None:
            raise RuntimeError("No handler for command")
        prefix, handler = match
        postfix = request[len(prefix):]
        handler(postfix, adapter, writer)

    def _match_prefix(self, request: str) -> Optional[Tuple[str, AsyncHandlerWithWriter]]:
        for key, handler in self._prefix_commands.items():
            if request.startswith(key):
                return key, handler
        return None
