import traceback
from account.models import *
from .api_utils import *
from .models import *
from django.core.exceptions import *


def _reqire_access_token(params):
    token = api_get_param_str(params, "access_token")
    return UserToken.get_user_by_token(token)


def account_auth(params):
    login = api_get_param_str(params, "login")
    password = api_get_param_str(params, "password")
    user = UserToken.auth(login, password)
    token = UserToken.create_token(user)

    return api_make_response({"access_token": token.access_token})


def account_deauth(params):
    UserToken.deauth(api_get_param_str(params, "access_token"))
    return api_make_response({})


def account_register(params):
    name = api_get_param_str(params, "name")
    surname = api_get_param_str(params, "surname")
    phone = api_get_param_str(params, "phone")
    email = api_get_param_str(params, "email")
    password = api_get_param_str(params, "password")

    user = SiteUser(
        name=name,
        surname=surname,
        phone=phone,
        email=email,
        password=password
    )

    try:
        user.full_clean()
        user.save()

        try:
            token = UserToken.create_token(user)
            return api_make_response({"access_token": token.access_token})

        except Exception as ex:
            # если вдруг токен нельзя создать
            user.delete()
            raise ex

    except ValidationError as validation_error:
        traceback.print_exc()
        errors = {}
        for field_name in validation_error.error_dict:
            err_list = validation_error.error_dict[field_name]
            print(err_list)
            obj = []
            for err in err_list:
                obj.append({
                    "code": err.code
                })
            errors[field_name] = obj
        raise Exception(API_ERROR_USER_REGISTER, errors)


def account_verify_phone(params):
    user = _reqire_access_token(params)

    if user.is_phone_verified:
        raise Exception(API_ERROR_VALIDATION_CURRENTLY_VERIFIED)

    code = api_get_param_int(params, "code", False, None)

    if code is None:
        res, err_code = PhoneVerificationService.send_verify(user.phone)

        if not res:
            if err_code in API_ERROR_VALIDATION:
                raise Exception(API_ERROR_VALIDATION[err_code])
            else:
                raise Exception(API_ERROR_VALIDATION_UNKNOWN)

        return api_make_response({"action": "phone_call"})
    else:
        res, err_code = PhoneVerificationService.check_code(user.phone, code)

        if res:
            user.is_phone_verified = True
            user.save()
            return api_make_response({})
        else:
            if err_code in API_ERROR_VALIDATION:
                raise Exception(API_ERROR_VALIDATION[err_code])
            else:
                raise Exception(API_ERROR_VALIDATION_UNKNOWN)


def account_get(params):
    user = _reqire_access_token(params)
    return api_make_response({
        "name": user.name,
        "surname": user.surname,
        "email": user.email,
        "phone": user.phone,
        "phone_verified": user.is_phone_verified
    })


def __make_argument_doc(name, arg_type, description, required=True):
    return {
        "name": name,
        "type": arg_type,
        "description": description,
        "required": required
    }


def __make_argument_access_token():
    return __make_argument_doc("access_token", "string", "<i>Токен</i>, выданный методом <code>account.auth</code>")


__doc_type_string = "string"


api_methods = {
    "account.auth": {
        "func": account_auth,
        "doc": "Аутентификация пользователя",
        "params": [
            __make_argument_doc("login", __doc_type_string, "Логин пользователя"),
            __make_argument_doc("password", __doc_type_string, "Пароль пользователя"),
        ],
        "returns": "В случае правильных логина и пароля <code>access_token</code>. В противном случае объект ошибки."
    },

    "account.deauth": {
        "func": account_deauth,
        "doc": "Удаление токена, дальшейшие вызовы API с этим токеном вернут ошибку невалидного токена",
        "params": [
            __make_argument_access_token()
        ],
        "returns": "В случае успеха стандартный код успеха"
    },

    "account.register": {
        "func": account_register,
        "doc": "Регистрация нового пользователя",
        "params": [

        ],
        "returns": "Поля пользователя (name, surname, email, phone, phone_verified)."
    },

    "account.verifyPhone": {
        "func": account_verify_phone,
        "doc": "Запросить верификацию номера телефона."
               "Если телефон уже верифицирован, метод вернет соответствующую ошибку",
        "params": [
            __make_argument_access_token(),
            __make_argument_doc("code", __doc_type_string, "Код верификации. Если не передать, будет выполнен звонок"),
        ],
        "returns": '{"status": "success"}, если верификация пройдена. Иначе одну из стандартных ошибок'
    },

    "account.get": {
        "func": account_get,
        "doc": "Получение информации о пользователе",
        "params": [
            __make_argument_access_token()
        ],
        "returns": "Поля пользователя (name, surname, email, phone, phone_verified)."
    },
}
