from typing import *

from aiomax.types import Attachment
from . import buttons
from inspect import signature
import aiohttp
from . import exceptions

def get_message_body(
    text: str,
    format: "Literal['markdown', 'html'] | None" = None,
    reply_to: "int | None" = None,
    notify: bool = True,
    keyboard: "List[List[buttons.Button]] | buttons.KeyboardBuilder | None" = None,
    attachments: "List[Attachment] | Attachment | None" = None
) -> dict:
    '''
    Returns the body of the message as json.
    '''
    body = {
        "text": text,
        "format": format,
        "notify": notify
    }

    # replying
    if reply_to:
        body['link'] = {
            "type": 'reply',
            "mid": reply_to
        }

    # keyboard
    if keyboard:
        if isinstance(keyboard, buttons.KeyboardBuilder):
            keyboard = keyboard.to_list()

        body['attachments'] = [{
            'type': 'inline_keyboard',
            'payload': {
                'buttons': [ [
                    i.to_json() if isinstance(i, buttons.Button) else i for i in row
                ] for row in keyboard ]
            }
        }]
    
    if attachments:
        if 'attachments' not in body:
            body['attachments'] = []

        if not isinstance(attachments, list):
            attachments = [attachments]

        for at in attachments or []:
            assert hasattr(at, 'as_dict'), 'Attachment must be an image, a video, an audio or a file'
            body['attachments'].append(at.as_dict())

    if attachments == [] and 'attachments' not in body:
        body['attachments'] = []

    return body

def context_kwargs(func: Callable, **kwargs):
    '''
    Returns only those kwargs, that callable accepts
    '''
    params = list(signature(func).parameters.keys())
    
    kwargs = {kw: arg for kw, arg in kwargs.items() if kw in params}

    return kwargs

async def get_exception(response: aiohttp.ClientResponse):
    if response.content_type == "text/plain":
        text = await response.text()
    elif response.content_type == "application/json":
        text = (await response.json())['code']
    else:
        return Exception(f"Unknown error: {await response.read()}")

    if text.startswith("Invalid access_token"):
        return exceptions.InvalidToken()
    if text == "attachment.not.ready":
        return exceptions.AttachmentNotReady()
    return Exception(f"Unknown error: {text}")
