import random

from authenticate.models import User, UserJWT, VerificationAttempt


class AuthenticateTestHelper:

    def __init__(self, tester):
        self.tester = tester

    test_token = 'eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJleHAiOjQ3NTA2NTU4NDQsInNlY3VyZV9rZXkiOiJiM2Q3NzU5YjI3OWY0NDA3YjE0ZjA3ZmE5ZmViMWZjMyJ9.M2zBB2sM9sDDqT2VUc1ct9qN5b5bJAPBXadQPuLQVPRUb6PBAMHU9VZLOPb9bAiogm_pOjriZRWUvHleOc6zvj5WJeik1sbL0WCySB_tor5Et6X5cnzdL09U_QTnulClg3WoZLuGUre2X5wE3CM2lBDBEp2bzZz8PCwnZncH6nI'
    user_email_index = 0
    user_phone_index = 1000000
    send_a_verification_code_url = '/user/send_a_verification_code'
    login_or_verification_code_check = '/user/authenticate'
    register_url = '/user/register'
    login_url = '/user/login_with_password'
    user_balance = '/user/balance'

    change_password = '/user/change_password'
    google_login_url = '/user/google_login'
    facebook_login_url = '/user/facebook_login'
    logout_url = '/user/logout'

    forget_password = '/user/forget_password'
    edit_profile = '/user/edit'
    profile_url = '/user/profile'
    account_url = '/user/account'

    def new_user_name(self):
        self.user_email_index += 1
        return 'niso' + str(self.user_email_index)

    def new_email(self):
        self.user_email_index += 1
        return 'niso' + str(self.user_email_index) + "@nisodynamic.com"

    def new_phone_number(self):
        self.user_phone_index += 1
        return '0910' + str(self.user_phone_index)

    def generate_randnum_not_equals_to_verification_code(self, model, email=None, phone=None):
        if email:
            verification_code = model.objects.get(email=email).verification_code
        elif phone:
            verification_code = model.objects.get(phone=phone).verification_code
        randnum = random.randint(100000, 999999)
        while randnum == verification_code:
            randnum = random.randint(100000, 999999)
        return randnum

    def new_user_with_email(self, email=None, password=None):
        if email is None:
            email = self.new_email()
        # if password is None:
        #     password = "dEdhbd3Ethdset"
        (response_data, status_code, error_message) = self.tester.post_with_token(self.send_a_verification_code_url,
                                                                                  {'email': email}, "")
        self.tester.assertEqual(response_data['message'], 'Successful', error_message)

        verification_code = VerificationAttempt.objects.get(email=email).verification_code
        request = {'email': email, 'code': verification_code, 'first_name': 'testfirstname',
                   'last_name': 'testlastname'}
        if password:
            request['password'] = password
        (response_data, status_code, error_message) = self.tester.post_with_token(self.register_url, request, "")
        self.tester.assertEqual(response_data['message'], 'Successful', error_message)

        user = User.objects.get(email=email)
        return user, UserJWT.objects.get(user=user).token

    def new_user_with_phone(self, phone=None, password=None, username=None):
        if phone is None:
            phone = self.new_phone_number()

        (response_data, status_code, error_message) = self.tester.post_with_token(self.send_a_verification_code_url,
                                                                                  {'phone': phone}, "")
        self.tester.assertEqual(response_data['message'], 'Successful', error_message)

        verification_code = VerificationAttempt.objects.get(phone=phone).verification_code
        request = {'phone': phone, 'code': verification_code, 'first_name': 'testfirstname',
                   'last_name': 'testlastname'}
        if password:
            request['password'] = password

        if username:
            request['username'] = username

        (response_data, status_code, error_message) = self.tester.post_without_token(self.register_url, request)
        self.tester.assertEqual(response_data['message'], 'Successful', error_message)

        user = User.objects.get(phone=phone)
        return user, UserJWT.objects.get(user=user).token

    def new_user_with_user_name_and_recovery_phone(self, recovery_phone=None, password=None, username=None):
        if username is None:
            username = self.new_user_name()

        if recovery_phone is None:
            recovery_phone = self.new_phone_number()

        if password is None:
            password = "dEdhbd3Ethdset"

        # TODO currently, our APIs do not support registering with recovery_phone
        # (response_data, status_code, error_message) = self.tester.post_without_token(self.send_a_verification_code_url,
        #                                                                              {'recovery_phone': recovery_phone,
        #                                                                               'username': username})
        # self.tester.assertEqual(response_data['message'], 'Successful', error_message)
        #
        # verification_code = VerificationAttempt.objects.get(recovery_phone=recovery_phone, username=username).verification_code
        # request = {'recovery_phone': recovery_phone, 'code': verification_code, 'first_name': 'testfirstname',
        #            'last_name': 'testlastname', 'username': username, 'password': password}
        #
        # (response_data, status_code, error_message) = self.tester.post_without_token(self.register_url, request)
        # self.tester.assertEqual(response_data['message'], 'Successful', error_message)
        #
        # user = User.objects.get(username=username)
        # return user, UserJWT.objects.get(user=user).token

        (user, token) = self.new_user_with_phone(phone=recovery_phone, password=password)

        user.phone = None
        user.recovery_phone = recovery_phone
        user.username = username
        user.save()

        return (user, token)


    def new_verification_attempt_with_email(self, email=None):
        if email is None:
            email = self.new_email()
        (response_data, status_code, error_message) = self.tester.post_with_token(self.send_a_verification_code_url,
                                                                                  {'email': email}, "")
        self.tester.assertEqual(response_data['status'], 'ok', error_message)
        self.tester.assertEqual(response_data['message'], 'Successful', error_message)

    def new_verification_attempt_with_phone(self, phone=None):
        if phone is None:
            phone = self.new_phone_number()
        (response_data, status_code, error_message) = self.tester.post_with_token(self.send_a_verification_code_url,
                                                                                  {'phone': phone}, "")
        self.tester.assertEqual(response_data['status'], 'ok', error_message)
        self.tester.assertEqual(response_data['message'], 'Successful', error_message)

    def new_verification_attempt_with_username(self, username):
        (response_data, status_code, error_message) = self.tester.post_without_token(self.send_a_verification_code_url,
                                                                                  {'username': username})
        self.tester.assertEqual(response_data['status'], 'ok', error_message)
        self.tester.assertEqual(response_data['message'], 'Successful', error_message)

    def verification_code_check_incorrect_code_with_email(self, email=None):
        if email is None:
            email = self.new_email()
        self.new_verification_attempt_with_email(email=email)
        randnum = self.generate_randnum_not_equals_to_verification_code(model=VerificationAttempt, email=email)
        (response_data, status_code, error_message) = self.tester.post_with_token(
            self.login_or_verification_code_check, {'email': email, 'code': randnum}, "")
        self.tester.assertEqual(response_data['status'], 'error', error_message)
        self.tester.assertEqual(response_data['message'], 'wrong code', error_message)

    def verification_code_check_incorrect_code_with_phone(self, phone=None):
        if phone is None:
            phone = self.new_phone_number()
        self.new_verification_attempt_with_phone(phone=phone)
        randnum = self.generate_randnum_not_equals_to_verification_code(model=VerificationAttempt, phone=phone)
        (response_data, status_code, error_message) = self.tester.post_with_token(
            self.login_or_verification_code_check, {'phone': phone, 'code': randnum}, "")
        self.tester.assertEqual(response_data['status'], 'error', error_message)
        self.tester.assertEqual(response_data['message'], 'wrong code', error_message)

    def login_with_password_helper(self, email=None, phone=None, username=None, password=None):
        if email:
            (response_data, status_code, error_message) = self.tester.post_without_token(self.login_url,
                                                                                         {'email': email,
                                                                                          'password': password})
            self.tester.assertEqual(response_data['message'], 'Successful')
        elif phone:
            (response_data, status_code, error_message) = self.tester.post_without_token(self.login_url,
                                                                                         {'phone': phone,
                                                                                          'password': password})
            self.tester.assertEqual(response_data['message'], 'Successful')
        elif username:
            (response_data, status_code, error_message) = self.tester.post_without_token(self.login_url,
                                                                                         {'username': username,
                                                                                          'password': password})
            self.tester.assertEqual(response_data['message'], 'Successful')
        else:
            self.tester.assertEqual(1, 2, 'email or phone should be provided')
