from authentication.tests import SignatureAuthClient, UserTestMixin, ToolshedTestCase
from files.tests import FilesTestMixin
from toolshed.models import InventoryItem, Category, StorageLocation
from toolshed.tests import InventoryTestMixin, LocationTestMixin

client = SignatureAuthClient()


class LocationApiTestCase(UserTestMixin, InventoryTestMixin, LocationTestMixin, ToolshedTestCase):

    def setUp(self):
        super().setUp()
        self.prepare_users()
        self.prepare_categories()
        self.prepare_tags()
        self.prepare_properties()
        self.prepare_locations()
        self.prepare_inventory()

    def test_locations(self):
        self.assertEqual("loc1", str(self.f['loc1']))
        self.assertEqual("loc1", self.f['loc1'].name)
        self.assertEqual("loc2", str(self.f['loc2']))
        self.assertEqual("loc2", self.f['loc2'].name)
        self.assertEqual("loc1/loc3", str(self.f['loc3']))
        self.assertEqual("loc3", self.f['loc3'].name)
        self.assertEqual(self.f['loc1'], self.f['loc3'].parent)
        self.assertEqual("loc1/loc4", str(self.f['loc4']))
        self.assertEqual("loc4", self.f['loc4'].name)
        self.assertEqual(self.f['loc1'], self.f['loc4'].parent)

    def test_get_inventory(self):
        reply = client.get('/api/inventory_items/', self.f['local_user1'])
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(len(reply.json()), 2)
        self.assertEqual(reply.json()[0]['name'], 'test1')
        self.assertEqual(reply.json()[0]['description'], 'test')
        self.assertEqual(reply.json()[0]['owned_quantity'], 1)
        self.assertEqual(reply.json()[0]['tags'], [])
        self.assertEqual(reply.json()[0]['properties'], [])
        self.assertEqual(reply.json()[0]['category'], 'cat1')
        self.assertEqual(reply.json()[0]['availability_policy'], 'friends')
        self.assertEqual(reply.json()[1]['name'], 'test2')
        self.assertEqual(reply.json()[1]['description'], 'test2')
        self.assertEqual(reply.json()[1]['owned_quantity'], 1)
        self.assertEqual(reply.json()[1]['tags'], ['tag1', 'tag2'])
        self.assertEqual(reply.json()[1]['properties'],
                         [{'name': 'prop1', 'value': 'value1'}, {'name': 'prop2', 'value': 'value2'}])
        self.assertEqual(reply.json()[1]['category'], 'cat1')
        self.assertEqual(reply.json()[1]['availability_policy'], 'friends')

    def test_get_inventory_item(self):
        reply = client.get('/api/storage_locations/', self.f['local_user1'])
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(len(reply.json()), 4)
        self.assertEqual(reply.json()[0]['name'], 'loc1')
        self.assertEqual(reply.json()[0]['description'], None)
        self.assertEqual(reply.json()[0]['category'], None)
        self.assertEqual(reply.json()[0]['path'], 'loc1')
        self.assertEqual(reply.json()[1]['name'], 'loc2')
        self.assertEqual(reply.json()[1]['description'], None)
        self.assertEqual(reply.json()[1]['category'], 'cat1')
        self.assertEqual(reply.json()[1]['path'], 'loc2')
        self.assertEqual(reply.json()[2]['name'], 'loc3')
        self.assertEqual(reply.json()[2]['description'], None)
        self.assertEqual(reply.json()[2]['category'], None)
        self.assertEqual(reply.json()[2]['path'], 'loc1/loc3')
        self.assertEqual(reply.json()[3]['name'], 'loc4')
        self.assertEqual(reply.json()[3]['description'], None)
        self.assertEqual(reply.json()[3]['category'], 'cat1')
        self.assertEqual(reply.json()[3]['path'], 'loc1/loc4')

    def test_post_new_location(self):
        reply = client.post('/api/storage_locations/', self.f['local_user1'], {
            'name': 'loc5',
            'description': 'a new location',
        })
        self.assertEqual(reply.status_code, 201)
        self.assertEqual(StorageLocation.objects.count(), 5)
        location = StorageLocation.objects.get(name='loc5')
        self.assertEqual(location.description, 'a new location')
        self.assertEqual(location.owner, self.f['local_user1'])
        self.assertEqual(location.parent, None)
        self.assertEqual(reply.json()['path'], 'loc5')

    def test_post_new_nested_location(self):
        reply = client.post('/api/storage_locations/', self.f['local_user1'], {
            'name': 'loc5',
            'parent': self.f['loc3'].id,
        })
        self.assertEqual(reply.status_code, 201)
        location = StorageLocation.objects.get(name='loc5')
        self.assertEqual(location.parent, self.f['loc3'])
        self.assertEqual(reply.json()['path'], 'loc1/loc3/loc5')

    def test_patch_location(self):
        reply = client.patch('/api/storage_locations/' + str(self.f['loc2'].id) + '/', self.f['local_user1'], {
            'name': 'loc2-renamed',
            'parent': self.f['loc1'].id,
        })
        self.assertEqual(reply.status_code, 200)
        location = StorageLocation.objects.get(id=self.f['loc2'].id)
        self.assertEqual(location.name, 'loc2-renamed')
        self.assertEqual(location.parent, self.f['loc1'])
        self.assertEqual(reply.json()['path'], 'loc1/loc2-renamed')

    def test_delete_location(self):
        reply = client.delete('/api/storage_locations/' + str(self.f['loc4'].id) + '/', self.f['local_user1'])
        self.assertEqual(reply.status_code, 204)
        self.assertEqual(StorageLocation.objects.count(), 3)
        self.assertEqual(StorageLocation.objects.filter(id=self.f['loc4'].id).count(), 0)

    def test_delete_location_with_items_sets_null(self):
        item = InventoryItem.objects.create(
            owner=self.f['local_user1'], name='located_item', storage_location=self.f['loc3'])
        reply = client.delete('/api/storage_locations/' + str(self.f['loc3'].id) + '/', self.f['local_user1'])
        self.assertEqual(reply.status_code, 204)
        item.refresh_from_db()
        self.assertIsNone(item.storage_location)
        self.assertEqual(InventoryItem.objects.filter(id=item.id).count(), 1)

    def test_locations_are_owner_scoped(self):
        reply = client.get('/api/storage_locations/', self.f['local_user2'])
        self.assertEqual(reply.status_code, 200)
        self.assertEqual(len(reply.json()), 0)

    def test_cannot_delete_other_users_location(self):
        reply = client.delete('/api/storage_locations/' + str(self.f['loc1'].id) + '/', self.f['local_user2'])
        self.assertEqual(reply.status_code, 404)
        self.assertEqual(StorageLocation.objects.filter(id=self.f['loc1'].id).count(), 1)

