import json

from django.test import TestCase, Client

from BookStore import error, function


# Create your tests here.

# 注册并登录
from user.models import User, Address


def register_and_login(self):
    data = {
        'user_id': 'zyx',
        'password': '123456',
    }
    self.client.post('/auth/register/', data=data, content_type='application/json')
    data = {
        'user_id': 'zyx',
        'password': '123456',
        'terminal': '127.0.0.1',
    }
    self.client = Client(
        HTTP_TOKEN=json.loads(
            self.client.post('/auth/login/',
                             data=data,
                             content_type='application/json').content).get('token'))


class RegisterTest(TestCase):

    def test_success_register(self):
        data = {
            'user_id': 'zyx',
            'password': '123456',
        }
        response = self.client.post('/auth/register/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)
        expect = {
            'message': 'ok',
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_repeat_register(self):
        self.test_success_register()
        data = {
            'user_id': 'zyx',
            'password': '123456',
        }
        response = self.client.post('/auth/register/', data=data, content_type='application/json')

        code, message = error.user_id_already_exist(data['user_id'])
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_username_too_short(self):
        data = {
            'user_id': 'z',
            'password': '123456',
        }
        response = self.client.post('/auth/register/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_username_too_long(self):
        data = {
            'user_id': 'this_is_a_too_long_username',
            'password': '123456',
        }
        response = self.client.post('/auth/register/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_password_too_short(self):
        data = {
            'user_id': 'zyx',
            'password': 'wrong',
        }
        response = self.client.post('/auth/register/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_password_too_long(self):
        data = {
            'user_id': 'zyx',
            'password': 'this_is_a_too_long_password',
        }
        response = self.client.post('/auth/register/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/register/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class LoginTest(TestCase):

    def setUp(self) -> None:
        # 注册一个号
        data = {
            'user_id': 'zyx',
            'password': '123456',
        }
        self.client.post('/auth/register/', data=data, content_type='application/json')

    def test_success_login(self):
        data = {
            'user_id': 'zyx',
            'password': '123456',
            'terminal': '127.0.0.1',
        }
        response = self.client.post('/auth/login/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)
        expect = {
            'message': 'ok',
            'token': function.generate_token(data),
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_user_id_doesnt_exist(self):
        data = {
            'user_id': 'non',
            'password': '123456',
            'terminal': '127.0.0.1',
        }
        response = self.client.post('/auth/login/', data=data, content_type='application/json')

        code, message = error.user_id_doesnt_exist(data['user_id'])
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_password_error(self):
        data = {
            'user_id': 'zyx',
            'password': 'wrong_password',
            'terminal': '127.0.0.1',
        }
        response = self.client.post('/auth/login/', data=data, content_type='application/json')

        code, message = error.authorization_fail()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/login/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class UnregisterTest(TestCase):

    def setUp(self) -> None:
        register_and_login(self)

    def test_success_unregister(self):
        data = {
            'user_id': 'zyx',
            'password': '123456',
        }
        response = self.client.post('/auth/unregister/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)
        expect = {
            'message': 'ok',
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_user_id_doesnt_exist(self):
        c = Client(HTTP_TOKEN=function.generate_token({'user_id': 'non', 'terminal': '127.0.0.1'}))
        data = {
            'user_id': 'non',
            'password': '123456',
        }
        response = c.post('/auth/unregister/', data=data, content_type='application/json')

        code, message = error.user_id_doesnt_exist(data['user_id'])
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_user_id_not_equal_username(self):
        data = {
            'user_id': 'non',
            'password': '123456',
        }
        response = self.client.post('/auth/unregister/', data=data, content_type='application/json')

        code, message = error.authorization_fail()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_password_error(self):
        data = {
            'user_id': 'zyx',
            'password': 'wrong_password',
        }
        response = self.client.post('/auth/unregister/', data=data, content_type='application/json')

        code, message = error.authorization_fail()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/unregister/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class PasswordTest(TestCase):

    def setUp(self) -> None:
        register_and_login(self)

    def test_success_password(self):
        data = {
            'user_id': 'zyx',
            'oldPassword': '123456',
            'newPassword': '654321',
        }
        response = self.client.post('/auth/password/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)
        expect = {
            'message': 'ok',
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_user_id_doesnt_exist(self):
        c = Client(HTTP_TOKEN=function.generate_token({'user_id': 'non', 'terminal': '127.0.0.1'}))
        data = {
            'user_id': 'non',
            'oldPassword': '123456',
            'newPassword': '654321',
        }
        response = c.post('/auth/unregister/', data=data, content_type='application/json')

        code, message = error.user_id_doesnt_exist(data['user_id'])
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_user_id_not_equal_username(self):
        data = {
            'user_id': 'non',
            'oldPassword': '123456',
            'newPassword': '654321',
        }
        response = self.client.post('/auth/unregister/', data=data, content_type='application/json')

        code, message = error.authorization_fail()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_password_error(self):
        data = {
            'user_id': 'zyx',
            'oldPassword': 'wrong_password',
            'newPassword': '654321',
        }
        response = self.client.post('/auth/unregister/', data=data, content_type='application/json')

        code, message = error.authorization_fail()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/password/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class LogoutTest(TestCase):

    def setUp(self) -> None:
        register_and_login(self)

    def test_success_logout(self):
        data = {
            'user_id': 'zyx',
        }
        response = self.client.post('/auth/logout/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)
        expect = {
            'message': 'ok',
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_user_id_not_equal_username(self):
        data = {
            'user_id': 'non',
        }
        response = self.client.post('/auth/logout/', data=data, content_type='application/json')

        code, message = error.authorization_fail()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/logout/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class ModifyTest(TestCase):

    def setUp(self) -> None:
        register_and_login(self)

    def test_success_modify(self):
        data = {
            "avatar": "$avatar file 无法测试$",
            "gender": "男",
            "phone_number": "12345678901",
            "email": "12345678901@stu.ecnu.edu.cn",
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)
        expect = {
            'message': 'ok',
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_phone_number_too_long(self):
        data = {
            "avatar": "$avatar file 无法测试$",
            "gender": "男",
            "phone_number": "1234567890111",
            "email": "12345678901@stu.ecnu.edu.cn",
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        code, message = error.database_error()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_avatar_is_none(self):
        data = {
            "avatar": None,
            "gender": "男",
            "phone_number": "12345678901",
            "email": "12345678901@stu.ecnu.edu.cn",
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_gender_is_none(self):
        data = {
            "avatar": "$avatar file 无法测试$",
            "gender": None,
            "phone_number": "12345678901",
            "email": "12345678901@stu.ecnu.edu.cn",
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_gender_invalid(self):
        data = {
            "avatar": "$avatar file 无法测试$",
            "gender": 'invalid',
            "phone_number": "12345678901",
            "email": "12345678901@stu.ecnu.edu.cn",
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_phone_number_is_none(self):
        data = {
            "avatar": "$avatar file 无法测试$",
            "gender": '男',
            "phone_number": None,
            "email": "12345678901@stu.ecnu.edu.cn",
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_email_is_none(self):
        data = {
            "avatar": "$avatar file 无法测试$",
            "gender": '男',
            "phone_number": "12345678901",
            "email": None,
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/modify/', data=data, content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class AddAddressTest(TestCase):

    def setUp(self) -> None:
        register_and_login(self)

    def test_success_add_address(self):
        data = {
            "name": "name",
            "address": "address",
            "phone_number": '12345678901',
        }
        response = self.client.post('/auth/add_address/', data=data, content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/add_address/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class DeleteAddressTest(TestCase):

    def setUp(self) -> None:
        # 注册并登录
        data = {
            'user_id': 'zyx',
            'password': '123456',
        }
        user = User.objects.create(username=data['user_id'], password=data['password'])
        data = {
            'user_id': 'zyx',
            'terminal': '127.0.0.1',
        }
        self.token = function.generate_token(data)
        address = Address.objects.create(user=user, name='name', phoneNumber='11111', address='123456')
        self.address_id = address.id
        self.client = Client(HTTP_TOKEN=self.token)

    def test_success_delete(self):
        data = {
            'address_id': self.address_id,
        }
        response = self.client.post('/auth/delete_address/', data=data, content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_non_exist_address(self):
        data = {
            'address_id': 999,
        }
        response = self.client.post('/auth/delete_address/', data=data, content_type='application/json')

        code, message = error.address_id_doesnt_exist(data['address_id'])
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.post('/auth/delete_address/', data=data, content_type='application/json')

        code, message = error.invalid_parameter()
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)


class InfoTest(TestCase):

    def setUp(self) -> None:
        # 注册并登录
        data = {
            'user_id': 'zyx',
            'password': '123456',
        }
        self.user = User.objects.create(username=data['user_id'], password=data['password'])
        data = {
            'user_id': 'zyx',
            'terminal': '127.0.0.1',
        }
        self.token = function.generate_token(data)
        address = Address.objects.create(user=self.user, name='name', phoneNumber='11111', address='123456')
        self.address_id = address.id
        self.client = Client(HTTP_TOKEN=self.token)

    def test_info_success(self):
        response = self.client.get('/auth/info/', content_type='application/json')

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
            'info': {
                'user_id': self.user.username,
                'avatar': self.user.avatar.url,
                'gender': self.user.gender,
                'phone_number': self.user.phoneNumber,
                'email': self.user.email,
                'balance': str(self.user.balance),
                'register_date': str(self.user.registerDate),
                'address': [{
                    'address_id': address.id,
                    'name': address.name,
                    'phone_number': address.phoneNumber,
                    'address': address.address,
                } for address in Address.objects.filter(user=self.user)],
            },
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_token_user_id_doesnt_exist(self):
        c = Client(HTTP_TOKEN=function.generate_token({'user_id': 'non-exist', 'terminal': '127.0.0.1'}))
        response = c.get('/auth/info/')

        code, message = error.user_id_doesnt_exist('non-exist')
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }
        self.assertJSONEqual(response.content, expected_data=expect)