import json

from django.test import TestCase, Client

from BookStore import error, function
from order import state
from order.models import Order, OrderBook
from order.views import auto_cancel
from store.models import Store, Book

from user.models import User, Address


# Create your tests here.


def init(self):
    # 注册并登录
    data = {
        'user_id': 'zyx',
        'password': '123456',
    }
    self.user = User.objects.create(username=data['user_id'], password=data['password'], balance=50000)
    self.seller = self.user
    data = {
        'user_id': 'zyx',
        'terminal': '127.0.0.1',
    }
    self.token = function.generate_token(data)
    self.client = Client(HTTP_TOKEN=self.token)
    self.store = Store.objects.create(storeName='s1', owner=self.user)
    self.book = Book.objects.create(bookID='b1', title='t1', store=self.store, price='13.00', stock=10, isbn='isbn1')

    buyer = User.objects.create(username='yzm', password='999999')

    self.store1 = Store.objects.create(storeName='648全球连锁店', owner=self.seller, address='648')

    Book.objects.create(bookID='book_id_1', stock=10, store=self.store1, isbn='1', title='1', price='1')
    Book.objects.create(bookID='book_id_2', stock=10, store=self.store1, isbn='2', title='2', price='2', off=True)

    auto_cancel.start()
    # 未支付且买家支付得起的订单
    self.order1 = Order.objects.create(store=self.store1, user=buyer, sumPrice=10, state=state.order_no_paid())
    auto_cancel.add_order_id(self.order1.id)
    # 已支付但未发货的订单
    self.order2 = Order.objects.create(store=self.store1, user=buyer, sumPrice=10, state=state.order_paid_no_shipped(),
                                       paid=True)
    auto_cancel.add_order_id(self.order2.id)
    # 已失效订单
    self.order3 = Order.objects.create(store=self.store1, user=buyer, sumPrice=10, state=state.order_invalid(),
                                       valid=False)
    auto_cancel.add_order_id(self.order3.id)
    # 未支付且买家支付不起的订单
    self.order4 = Order.objects.create(store=self.store1, user=buyer, sumPrice=1000000, state=state.order_no_paid())
    auto_cancel.add_order_id(self.order4.id)
    # 买家未收货订单
    self.order5 = Order.objects.create(store=self.store1, user=buyer, sumPrice=10, state=state.order_shipped(),
                                       paid=True)
    auto_cancel.add_order_id(self.order5.id)

    # 已收货的订单
    self.order6 = Order.objects.create(store=self.store1, user=buyer, sumPrice=10, state=state.order_received(),
                                       paid=True, complete=True)


class MyStoresTest(TestCase):

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

    def test_my_stores_success(self):
        data = {
        }
        response = self.client.get('/store/mystores/', data=data)

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
            'num': len(Store.objects.filter(owner=self.user)),
            'stores': [store.info_json() for store in Store.objects.filter(owner=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('/store/mystores/')

        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)


class CreateStoreTest(TestCase):

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

    def test_create_success(self):
        data = {
            'user_id': 'zyx',
            'store_id': 's2',
        }
        response = self.client.post('/store/create_store/', 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_user_id_doesnt_exist(self):
        c = Client(HTTP_TOKEN=function.generate_token({'user_id': 'non', 'terminal': '127.0.0.1'}))
        data = {
            'user_id': 'non',
            'store_id': 's2',
        }
        response = c.post('/store/create_store/', 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': 'yzm',
            'store_id': 's2',
        }
        response = self.client.post('/store/create_store/', 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_repeat_register(self):
        data = {
            'user_id': 'zyx',
            'store_id': 's1',
        }
        response = self.client.post('/store/create_store/', data=data, content_type='application/json')

        code, message = error.store_id_already_exist(data['store_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('/store/create_store/', 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 AddBookTest(TestCase):

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

    def test_add_success(self):
        data = {
            "user_id": "zyx",
            "store_id": "s1",
            "book_info": {
                "tags": [
                    "tags1",
                    "tags2",
                    "tags3",
                    "..."
                ],
                "id": "b2",
                "title": "$book title$",
                "author": "$book author$",
                "publisher": "$book publisher$",
                "original_title": "$original title$",
                "translator": "translater",
                "pub_year": "$pub year$",
                "pages": 10,
                "price": 10,
                "binding": "平装",
                "isbn": "$isbn$",
                "author_intro": "$author introduction$",
                "book_intro": "$book introduction$",
                "content": "$chapter1 ...$"
            },
            "stock_level": 0
        }
        response = self.client.post('/store/add_book/', 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_repeat_id(self):
        data = {
            "user_id": "zyx",
            "store_id": "s1",
            "book_info": {
                "id": "b1",
                "title": "$book title$",
                "price": 10,
                "binding": "平装",
                "isbn": "$isbn$",
            },
            "stock_level": 0
        }
        response = self.client.post('/store/add_book/', data=data, content_type='application/json')

        code, message = error.book_id_already_exist(data['book_info']['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):
        c = Client(HTTP_TOKEN=function.generate_token({'user_id': 'non', 'terminal': '127.0.0.1'}))
        data = {
            'user_id': 'zyx',
            "store_id": "s1",
            "book_info": {
                "id": "b3",
                "title": "$book title$",
                "price": 10,
                "binding": "平装",
                "isbn": "$isbn$",
            },
            "stock_level": 0
        }
        response = c.post('/store/add_book/', 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_user_id_not_exist(self):
        c = Client(HTTP_TOKEN=function.generate_token({'user_id': 'non', 'terminal': '127.0.0.1'}))
        data = {
            "user_id": "non",
            "store_id": "s1",
            "book_info": {
                "id": "b2",
                "title": "$book title$",
                "price": 10,
                "binding": "平装",
                "isbn": "$isbn$",
            },
            "stock_level": 0
        }
        response = c.post('/store/add_book/', 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_store_id_doesnt_exist(self):
        data = {
            "user_id": "zyx",
            "store_id": "s9",
            "book_info": {
                "id": "b2",
                "title": "$book title$",
                "price": 10,
                "binding": "平装",
                "isbn": "$isbn$",
            },
            "stock_level": 0
        }
        response = self.client.post('/store/add_book/', data=data, content_type='application/json')

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

    def test_book_id_already_exist(self):
        data = {
            "user_id": "zyx",
            "store_id": "s1",
            "book_info": {
                "id": "b1",
                "title": "$book title$",
                "price": 10,
                "binding": "平装",
                "isbn": "$isbn$",
            },
            "stock_level": 0
        }
        response = self.client.post('/store/add_book/', data=data, content_type='application/json')

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


class AddStockLevelTest(TestCase):

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

    def test_add_stock_level_success(self):
        data = {
            "user_id": "zyx",
            "store_id": "s1",
            "book_id": "b1",
            "add_stock_level": 10
        }
        response = self.client.post('/store/add_stock_level/', 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_user_id_doesnt_exist(self):
        c = Client(HTTP_TOKEN=function.generate_token({'user_id': 'non', 'terminal': '127.0.0.1'}))
        data = {
            "user_id": "non",
            "store_id": "s1",
            "book_id": "b1",
            "add_stock_level": 10
        }
        response = c.post('/store/add_stock_level/', 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_store_id_doesnt_exist(self):
        data = {
            "user_id": "zyx",
            "store_id": "s99",
            "book_id": "b1",
            "add_stock_level": 10
        }
        response = self.client.post('/store/add_stock_level/', data=data, content_type='application/json')

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

    def test_book_id_doesnt_exist(self):
        data = {
            "user_id": "zyx",
            "store_id": "s1",
            "book_id": "b99",
            "add_stock_level": 10
        }
        response = self.client.post('/store/add_stock_level/', data=data, content_type='application/json')

        code, message = error.book_id_doesnt_exist(data['book_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",
            "store_id": "s1",
            "book_id": "b1",
            "add_stock_level": 10
        }
        response = self.client.post('/store/add_stock_level/', 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('/store/add_stock_level/', 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 StoreInfoTest(TestCase):

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

    def test_store_info_success(self):
        data = {
            'store_id': 's1',
            'page': 1,
        }
        response = self.client.get('/store/store_info/', data=data)

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
            "store": {
                "store_id": 's1',
                "address": "",
                "create_date": str(self.store.createDate),
                "sold": 0,
                "info": ''
            },
            "off_books_page": 1,
            "off_books_page_num": 1,
            "off_book_num": 0,
            "off_books": [],
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_store_id_doesnt_exist(self):
        data = {
            'store_id': 's2',
            'page': 1,
        }
        response = self.client.get('/store/store_info/', data=data)

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

    def test_page_too_small(self):
        data = {
            'store_id': 's1',
            'page': -1,
        }
        response = self.client.get('/store/store_info/', data=data)

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
            "store": {
                "store_id": 's1',
                "address": "",
                "create_date": str(self.store.createDate),
                "sold": 0,
                "info": ''
            },
            "off_books_page": 1,
            "off_books_page_num": 1,
            "off_book_num": 0,
            "off_books": [],
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_page_too_big(self):
        data = {
            'store_id': 's1',
            'page': 9999,
        }
        response = self.client.get('/store/store_info/', data=data)

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
            "store": {
                "store_id": 's1',
                "address": "",
                "create_date": str(self.store.createDate),
                "sold": 0,
                "info": ''
            },
            "off_books_page": 1,
            "off_books_page_num": 1,
            "off_book_num": 0,
            "off_books": [],
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_no_parameter(self):
        data = {
        }
        response = self.client.get('/store/store_info/', 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 BookInfoTest(TestCase):

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

    def test_book_info_success(self):
        data = {
            "store_id": "s1",
            "book_id": "b1",
        }
        response = self.client.get('/store/book_info/', data=data)

        code, message = 200, 'ok'
        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
            'store_id': data['store_id'],
            'book_info': json.loads(response.content).get('book_info')
        }
        self.assertJSONEqual(response.content, expected_data=expect)

    def test_store_id_doesnt_exist(self):
        data = {
            "store_id": "s99",
            "book_id": "b1",
        }
        response = self.client.get('/store/book_info/', data=data)

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

    def test_book_id_doesnt_exist(self):
        data = {
            "store_id": "s1",
            "book_id": "b999",
        }
        response = self.client.get('/store/book_info/', data=data)

        code, message = error.book_id_doesnt_exist(data['book_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.get('/store/book_info/', 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:
        init(self)

    def test_modify_success(self):
        data = {
            "store_id": "s1",
            "address": "$store_address$",
            "info": "$book_info$"
        }
        response = self.client.post('/store/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_store_id_doesnt_exist(self):
        data = {
            "store_id": "s999",
            "address": "$store_address$",
            "info": "$book_info$"
        }
        response = self.client.post('/store/modify/', data=data, content_type='application/json')

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

    def test_no_address(self):
        data = {
            "store_id": "s1",
            "address": None,
            "info": "$book_info$"
        }
        response = self.client.post('/store/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_info(self):
        data = {
            "store_id": "s1",
            "address": "$store_address$",
            "info": None,
        }
        response = self.client.post('/store/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('/store/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)


class StoreOrder(TestCase):
    def setUp(self) -> None:
        init(self)

    def test_store_id_not_exist(self):
        data = {
            "store_id": 55555,
        }

        response = self.client.get('/seller/store_orders/', data=data, content_type='application/json')

        code, message = error.store_id_doesnt_exist(data['store_id'])

        self.assertEqual(response.status_code, code)
        expect = {
            'message': message,
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_success(self):
        data = {
            "store_id": self.store1.storeName,
        }

        response = self.client.get('/seller/store_orders/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)

        expect = {
            'message': 'ok',
            'orders': json.loads(response.content).get('orders')
        }

        self.assertJSONEqual(response.content, expected_data=expect)


class DeliverTest(TestCase):
    def setUp(self) -> None:
        init(self)

    def test_deliver_shipped(self):
        data = {
            'order_id': self.order5.id,
        }

        response = self.client.post('/seller/deliver/', 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_deliver_received(self):
        data = {
            'order_id': self.order6.id
        }

        response = self.client.post('/seller/deliver/', 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_deliver_not_exist(self):
        data = {
            'order_id': 15645684789478,
        }

        response = self.client.post('/seller/deliver/', data=data, content_type='application/json')

        code, message = error.order_id_doesnt_exist(data['order_id'])

        self.assertEqual(response.status_code, code)

        expect = {
            'message': message,
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_success(self):
        data = {
            'order_id': self.order2.id
        }

        response = self.client.post('/seller/deliver/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)

        expect = {
            'message': 'ok',
        }

        self.assertJSONEqual(response.content, expected_data=expect)


class DeleteTest(TestCase):
    def setUp(self) -> None:
        init(self)

    def test_delete_not_exist(self):
        data = {
            'store_id': 12313214,
        }

        response = self.client.post('/seller/delete_store/', data=data, content_type='application/json')

        code, message = error.store_id_doesnt_exist(data['store_id'])

        self.assertEqual(response.status_code, code)

        expect = {
            'message': message,
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_success(self):
        data = {
            'store_id': self.store.storeName
        }

        response = self.client.post('/seller/delete_store/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)

        expect = {
            'message': 'ok',
        }

        self.assertJSONEqual(response.content, expected_data=expect)


class OffBookTest(TestCase):
    def setUp(self) -> None:
        init(self)

    def test_store_id_not_exist(self):
        data = {
            "store_id": 12341586,
            "book_id": "book_id_1"
        }

        response = self.client.post('/seller/off_book/', data=data, content_type='application/json')

        code, message = error.store_id_doesnt_exist(data['store_id'])

        self.assertEqual(response.status_code, code)

        expect = {
            'message': message,
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_order_id_not_exsit(self):
        data = {
            "store_id": self.store1.storeName,
            "book_id": "book_id_3"
        }

        response = self.client.post('/seller/off_book/', data=data, content_type='application/json')

        code, message = error.book_id_doesnt_exist(data['book_id'])

        self.assertEqual(response.status_code, code)

        expect = {
            'message': message,
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_off_success(self):
        data = {
            "store_id": self.store1.storeName,
            "book_id": "book_id_1"
        }

        response = self.client.post('/seller/off_book/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)

        expect = {
            'message': 'ok',
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_not_off_success(self):
        data = {
            "store_id": self.store1.storeName,
            "book_id": "book_id_2"
        }

        response = self.client.post('/seller/off_book/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)

        expect = {
            'message': 'ok',
        }

        self.assertJSONEqual(response.content, expected_data=expect)


class ModifyPriceTest(TestCase):
    def setUp(self) -> None:
        init(self)

    def test_store_id_not_exist(self):
        data = {
            "store_id": 12341586,
            "book_id": "book_id_1",
            "price": '100'
        }

        response = self.client.post('/seller/modify_price/', data=data, content_type='application/json')

        code, message = error.store_id_doesnt_exist(data['store_id'])

        self.assertEqual(response.status_code, code)

        expect = {
            'message': message,
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_book_id_not_exist(self):
        data = {
            "store_id": self.store1.storeName,
            "book_id": 1234567,
            "price": '100'
        }

        response = self.client.post('/seller/modify_price/', data=data, content_type='application/json')

        code, message = error.book_id_doesnt_exist(data['book_id'])

        self.assertEqual(response.status_code, code)

        expect = {
            'message': message,
        }

        self.assertJSONEqual(response.content, expected_data=expect)

    def test_price_not_heli(self):
        data = {
            "store_id": self.store1.storeName,
            "book_id": "book_id_1",
            "price": '-100'
        }

        response = self.client.post('/seller/modify_price/', 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_success(self):
        data = {
            "store_id": self.store1.storeName,
            "book_id": "book_id_1",
            "price": '100'
        }

        response = self.client.post('/seller/modify_price/', data=data, content_type='application/json')

        self.assertEqual(response.status_code, 200)

        expect = {
            'message': 'ok',
        }

        self.assertJSONEqual(response.content, expected_data=expect)
