import json
from datetime import date
from datetime import datetime

from django.contrib.auth.models import User
from django.urls import reverse
from games.models import Game
from games.models import Platform
from games.models import Timeline
from rest_framework import status
from rest_framework.test import APITestCase


class PlatformTest(APITestCase):
    @classmethod
    def setUpTestData(cls):
        cls.superuser = User.objects.create_superuser(
            'admin', 'admin@localhost', 'admin')

    def test_create_platform(self):
        """
        Check we can create a platform object.
        """
        url = reverse('platform-list')
        data = {'name': 'GP2X', 'shortname': 'GP2X'}
        self.client.force_authenticate(user=self.superuser)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Platform.objects.count(), 1)
        self.assertEqual(Platform.objects.get().name, 'GP2X')

    def test_sorted_platform(self):
        """
        Check that platform list is sorted.
        """
        Platform.objects.create(name='GP2X')
        Platform.objects.create(name='3DS')
        Platform.objects.create(name='Game Boy')
        Platform.objects.create(name='Amiga')
        url = reverse('platform-list')
        self.client.force_authenticate(user=self.superuser)
        response = self.client.get(url, format='json')
        sorted_platforms = list(Platform.objects.all().order_by('name')
                                .values_list('name', flat=True))
        platforms = [x.get('name') for x in json.loads(response.content)]
        self.assertEqual(platforms, sorted_platforms)


class GameTest(APITestCase):
    @classmethod
    def setUpTestData(cls):
        cls.superuser = User.objects.create_superuser(
            'admin', 'admin@localhost', 'admin')

    def test_create_game(self):
        """
        Check we can create a game object.
        """
        # Game works on specific platform
        console = Platform.objects.create(name='Game Boy')
        console_url = reverse('platform-detail', kwargs={'pk': console.id})

        url = reverse('game-list')
        data = {
            'name': 'Tetris',
            'collection': console_url,
        }
        self.client.force_authenticate(user=self.superuser)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Game.objects.count(), 1)
        self.assertEqual(Game.objects.get().name, 'Tetris')
        self.assertEqual(Game.objects.get().collection_id, console.id)

    def test_sorted_games(self):
        """
        Check that game list is sorted.
        """
        console = Platform.objects.create(name='BestPlatform4Ever')
        Game.objects.create(name='Pomperman', collection=console)
        Game.objects.create(name='Vektoria', collection=console)
        Game.objects.create(name='Qrackovitchya', collection=console)
        url = reverse('game-list')
        self.client.force_authenticate(user=self.superuser)
        response = self.client.get(url, format='json')
        sorted_games = list(
            Game.objects.all().order_by('name').values_list('name', flat=True))
        games = [x.get('name') for x in json.loads(response.content)]
        self.assertEqual(games, sorted_games)

    def test_not_allowed_status(self):
        """
        Check that we cannot insert a not allowed status in a Game
        """
        Platform.objects.create(name='BestPlatform4Ever')
        url = reverse('game-list')
        data = {
            'name': 'Vilebrequin',
            'status': 'wrecked',
        }
        self.client.force_authenticate(user=self.superuser)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
        self.assertEqual(Game.objects.count(), 0)


class TimelineTest(APITestCase):
    @classmethod
    def setUpTestData(cls):
        cls.superuser = User.objects.create_superuser(
            'admin', 'admin@localhost', 'admin')

    def test_create_timeline(self):
        """
        Check we can create a timeline object.
        """
        console = Platform.objects.create(name='BestPlatform4Ever')
        game = Game.objects.create(
            name='Cherubin', collection=console, status='created')

        # By default a timeline is generated with current datetime.
        # We need to change this date.
        timeline = Timeline.objects.first()
        timeline.date = date(2017, 9, 15)
        timeline.save()

        url = reverse('game_timeline-list')
        data = {
            'item': reverse('game-detail', kwargs={'pk': game.id}),
            'date': date(2017, 9, 16),
            'status': 'beaten',
        }
        self.client.force_authenticate(user=self.superuser)
        response = self.client.post(url, data, format='json')
        self.assertEqual(response.status_code, status.HTTP_201_CREATED,
                         response.content)
        self.assertEqual(Timeline.objects.count(), 2)

    def test_sorted_game_timeline(self):
        """
        Check that timelines are sorted by date in descending order.
        """
        # Prepare timeline with some different dates
        console = Platform.objects.create(name='BestPlatform4Ever')
        game = Game.objects.create(
            name='Symptomatic', collection=console, status='created')
        game.status = 'beaten'
        game.save()
        game.status = 'completed'
        game.save()
        # Change date from Timelines
        Timeline.objects.filter(status='created').update(date='2017-03-01')
        Timeline.objects.filter(status='completed').update(date='2017-03-05')
        Timeline.objects.filter(status='beaten').update(date='2017-03-07')
        # Check dates
        url = reverse('game_timeline-list')
        self.client.force_authenticate(user=self.superuser)
        response = self.client.get(url, format='json')
        # sorted_timelines are datetime.date
        sorted_timelines = list(Timeline.objects.all().order_by('-date')
                                .values_list('date', flat=True))
        # dates are string date, format %Y-%m-%d
        dates = [x.get('date') for x in json.loads(response.content)]
        da = [datetime.date(datetime.strptime(x, '%Y-%m-%d')) for x in dates]
        self.assertEqual(da, sorted_timelines)
