from django.http import HttpResponse
from .api_params import *


api_methods_dict = {}


def api_make_response(response):
    return API_OK_OBJ | {"response": response}


# def api_make_param(name, arg_class, description, required=True):
#     return {
#         "name": name,
#         "type": arg_class,
#         "description": description,
#         "required": required
#     }

# API_PARAM_ACCESS_TOKEN = api_make_param(
#     "access_token",
#     AccessToken,
#     "<i>Токен</i>, выданный методом <code>account.auth</code>"
# )


def api_method(func_name, doc="", params: list or None = None, returns=""):
    """
    Декоратор для методов API, автоматически валидирует и передает параметры методам
    """
    def actual_decorator(func):
        async def wrapper(__raw_request, **kwargs):
            print(f"> call method {func_name} with params {kwargs}. method params: {params}")

            errors = []
            func_args = {}
            for p in params:
                try:
                    if not isinstance(p, ApiParam):
                        raise Exception(API_ERROR_INTERNAL_ERROR, f"param {p} is not instance of ApiParam class")

                    name = p.get_name()

                    if isinstance(p, ApiRequestParam):
                        func_args[name] = __raw_request
                    else:
                        value = kwargs[name] if name in kwargs else None

                        if asyncio.iscoroutinefunction(p.validate):
                            func_args[name] = await p.validate(value)
                        else:
                            func_args[name] = p.validate(value)

                except Exception as ex:
                    errors.append(ex)
            # print(f"errors: {errors}, args: {func_args}")
            if len(errors) > 0:
                if len(errors) == 1:
                    return make_error_object(errors[0])
                else:
                    return make_error_object(errors)
            else:
                try:
                    if asyncio.iscoroutinefunction(func):
                        out = await func(**func_args)
                    else:
                        out = func(**func_args)
                except Exception as ex:
                    return make_error_object(ex)

                if out is None:
                    return make_error_object(Exception(API_ERROR_INTERNAL_ERROR, "method returned null object"))

                if not isinstance(out, dict) and not isinstance(out, HttpResponse):
                    return make_error_object(Exception(API_ERROR_INTERNAL_ERROR, "method returned invalid object type"))

                return out

        api_methods_dict[func_name] = {
            "doc": doc,
            "params": params,
            "func": wrapper,
            "returns": returns
        }
        return wrapper

    return actual_decorator

