import json
import urllib.request

from security import encoding
from security.request import sign_request
from server.server import SERVER


def send_check_email(email, server):
    server_url = SERVER[server]["server_url"]
    request = {"name": "check_email", "data": {"email": email}}
    signed_request = sign_request(request)
    answer = send_request(signed_request, server_url)
    return answer["email_already_exists"]


def send_register(username, display_name, password, email, server):
    server_url = SERVER[server]["server_url"]
    request = {"name": "register", "data": {}}
    request["data"]["username"] = username
    request["data"]["display_name"] = display_name
    request["data"]["password"] = password
    request["data"]["email"] = email
    signed_request = sign_request(request)
    answer = send_request(signed_request, server_url)
    if not answer["success"]:
        if answer["reason"] == "user already exists":
            raise UserAlreadyExists
        elif answer["reason"] == "username already taken":
            raise UsernameTaken
        elif answer["reason"] == "user limit reached":
            raise UserLimitReached
        raise UnableToRegister
    return answer["data"]["user_id"], answer["data"]["login_id"]


def send_login(email, password, server):
    server_url = SERVER[server]["server_url"]
    request = {"name": "login", "data": {}}
    request["data"]["email"] = email
    request["data"]["password"] = password
    signed_request = sign_request(request)
    answer = send_request(signed_request, server_url)
    if not answer["success"]:
        if answer["reason"] == "banned":
            raise UserBanned(answer["banned_for"])
        else:
            raise LoginFailed
    return answer["data"]["user_id"], answer["data"]["login_id"]


def send_check_login_id(user_id, login_id, server):
    server_url = SERVER[server]["server_url"]
    request = {"name": "check_login_id", "data": {}}
    request["data"]["user_id"] = user_id
    request["data"]["login_id"] = login_id
    signed_request = sign_request(request)
    answer = send_request(signed_request, server_url)
    if not answer["valid_login_id"]:
        raise LoginIDNotValid
    return


def send_set_new_password(email, new_password, server):
    server_url = SERVER[server]["server_url"]
    request = {"name": "set_new_password", "data": {}}
    request["data"]["email"] = email
    request["data"]["new_password"] = new_password
    signed_request = sign_request(request)
    answer = send_request(signed_request, server_url)
    if not answer["success"]:
        raise CouldNotSetNewPassword
    return


def send_request(request, url):
    try:
        request = urllib.request.Request(url+"/auth", data=bytes(json.dumps(request, indent=4), encoding=encoding))
        request.add_header('Content-Type', 'application/json')
        return json.loads(urllib.request.urlopen(request).read())
    except Exception:
        raise UnableToAccessGateway


class UnableToAccessGateway(Exception):
    pass


class EmailAlreadyInUse(Exception):
    pass


class LoginFailed(Exception):
    pass


class LoginIDNotValid(Exception):
    pass


class UnableToRegister(Exception):
    pass


class CouldNotSetNewPassword(Exception):
    pass


class UserBanned(Exception):

    def __init__(self, banned_for, message="User is banned"):
        self.banned_for = banned_for
        self.message = message
        super().__init__(self.message)


class UserAlreadyExists(Exception):
    pass


class UserDoesNotExist(Exception):
    pass


class UserLimitReached(Exception):
    pass


class UsernameTaken(Exception):
    pass
