from ..user.bot_schema import schema
from .utils import validate

blocked = frozenset({
    "getUpdates",
    "setWebhook",
    "deleteWebhook",
    "getWebhookInfo",
    "logOut",
    "close",
    "getManagedBotToken",
    "replaceManagedBotToken",
    "getManagedBotAccessSettings",
    "setManagedBotAccessSettings",
})
methods = frozenset(schema["methods"]) - blocked


def arguments(method, data):
    from ..errors import AccessError, InputError
    if method not in methods: raise AccessError("This bot method is not available to modules")
    if not isinstance(data, dict): raise InputError("Invalid bot parameters")
    fields = schema["methods"][method]
    if set(data) - fields.keys(): raise InputError("Unknown bot parameters")
    if any(field["required"] and key not in data for key, field in fields.items()):
        raise InputError("Required bot parameters are missing")
    validate(data)


def keyboard(data, callback=None):
    from ..errors import InputError
    if not isinstance(data, dict): raise InputError("Invalid reply markup")
    variants = [key for key in ("inline_keyboard", "keyboard", "remove_keyboard") if key in data]
    if not variants and "force_reply" in data: variants = ["force_reply"]
    if len(variants) != 1: raise InputError("Exactly one keyboard type is required")
    key = variants[0]
    kind = {"inline_keyboard": "InlineKeyboardMarkup", "keyboard": "ReplyKeyboardMarkup",
            "remove_keyboard": "ReplyKeyboardRemove", "force_reply": "ForceReply"}[key]
    if set(data) - schema["types"][kind].keys(): raise InputError("Invalid keyboard parameters")
    validate(data)
    if key not in ("inline_keyboard", "keyboard"): return
    if not isinstance(data[key], list) or len(data[key]) > 20: raise InputError("Too many keyboard rows")
    for row in data[key]:
        if not isinstance(row, list) or not 1 <= len(row) <= 8: raise InputError("Invalid keyboard row")
        for button in row:
            if isinstance(button, str) and key == "keyboard": continue
            if not isinstance(button, dict) or not isinstance(button.get("text"), str) or not button["text"]:
                raise InputError("Invalid button")
            kind = "InlineKeyboardButton" if key == "inline_keyboard" else "KeyboardButton"
            if set(button) - schema["types"][kind].keys(): raise InputError("Invalid button parameters")
            if key == "inline_keyboard":
                actions = set(button) - {"text", "icon_custom_emoji_id", "style"}
                if len(actions) != 1: raise InputError("Exactly one button action is required")
                if "disabled" in button and button["disabled"] != {}: raise InputError("Invalid disabled button")
            if "callback_data" in button:
                value = button["callback_data"]
                if not isinstance(value, str) or not 1 <= len(value.encode()) <= 64: raise InputError("Invalid callback data")
                if callback is not None: callback(value)
