from .func_mixin import FunctionMixin, Filter, Func
from typing import Callable, Any, List
from ncatbot.core.event import BaseMessageEvent
from ncatbot.utils import PermissionGroup
import asyncio
import functools


class AliasFilter(Filter):
    def __init__(self, name: str, aliases: List[str]):
        self.name = name
        self.aliases = aliases

    def check(self, event: BaseMessageEvent) -> bool:
        if event.raw_message.startswith("/" + self.name):
            return True
        if self.aliases is not None:
            for aliases in self.aliases:
                if event.raw_message.startswith("/" + aliases):
                    return True
        return False


class Command:
    def __init__(self, data: dict):
        self.name = data["name"]
        self.aliases = data["aliases"]
        self.permission = data["permission"]
        self.description = data["description"]
        self.usage = data["usage"]
        self.examples = data["examples"]
        self.func: Func = data["func"]

    def __str__(self) -> str:
        return f"{self.name} - {self.description}"

    def __repr__(self) -> str:
        return f"Command(name={self.name}, permission={self.permission}, description={self.description}, usage={self.usage}, examples={self.examples}, func={self.func})"

    def __eq__(self, other: Any) -> bool:
        if isinstance(other, Command):
            return self.name == other.name
        if isinstance(other, str):
            return self.name == other
        return False


class CommandMixin(FunctionMixin):
    _registered_command_activators: List[str] = []

    def unregister_command(self, name: str):
        for command in self._registered_commands:
            if command.name == name:
                self.unregister_func(command.func.name)
                self._registered_commands.remove(command)
                break
        else:
            raise ValueError(f"命令 {name} 不存在")

    def get_registered_commands(self) -> List[Command]:
        if not hasattr(self, "_registered_commands"):
            self._registered_commands = []
        return self._registered_commands

    def _create_command_handler(self, handler: Callable) -> Callable:
        @functools.wraps(handler)
        async def warpped_handler(event: BaseMessageEvent, handler=handler):
            args = event.raw_message.split()
            if asyncio.iscoroutinefunction(handler):
                return await handler(event, args)
            else:
                return handler(event, args)

        return warpped_handler

    def register_command(
        self,
        name: str,
        handler: Callable[[BaseMessageEvent, List[str]], Any],
        aliases: List[str] = None,
        description: str = "",
        usage: str = "",
        examples: List[str] = None,
        permission: PermissionGroup = PermissionGroup.USER.value,
        timeout: float = None,
    ) -> Command:
        # TODO 提示已经注册的别名
        # TODO 限定参数
        if not hasattr(self, "_registered_commands"):
            self._registered_commands: List[Command] = []
        if name in self._registered_commands:
            raise ValueError(f"命令 {name} 已经存在")

        warpped_handler = self._create_command_handler(handler)
        func = self._register_func(
            name,
            warpped_handler,
            AliasFilter(name, aliases).check,
            description=description,
            usage=usage,
            examples=examples,
            permission=PermissionGroup.USER.value,
            timeout=timeout,
        )
        command = Command(
            {
                "name": name,
                "aliases": aliases,
                "permission": permission,
                "description": description,
                "usage": usage,
                "examples": examples,
                "func": func,
            }
        )
        self._registered_commands.append(command)
        return command

    def register_user_command(
        self,
        name: str,
        handler: Callable[[BaseMessageEvent, List[str]], Any],
        aliases: List[str] = None,
        description: str = "",
        usage: str = "",
        examples: List[str] = None,
        timeout: float = None,
    ) -> Command:
        return self.register_command(
            name,
            handler,
            aliases,
            description,
            usage,
            examples,
            PermissionGroup.USER.value,
            timeout,
        )

    def register_admin_command(
        self,
        name: str,
        handler: Callable[[List[str], BaseMessageEvent], Any],
        aliases: List[str] = None,
        description: str = "",
        usage: str = "",
        examples: List[str] = None,
        timeout: float = None,
    ) -> Command:
        return self.register_command(
            name,
            handler,
            aliases,
            description,
            usage,
            examples,
            PermissionGroup.ADMIN.value,
            timeout,
        )
