from django.contrib.auth.models import User
from django.utils import timezone
from rest_framework import status
from rest_framework.test import APITestCase, APIRequestFactory

from webapp.models import Event
from webapp.serializers import EventSerializer
from webapp.tests.tag_fixture import tagBuilder
from webapp.tests.event_fixture import createEventObject, createEventJSON
from webapp.tests.signup_fixture import createSignupForm

URL = "/api/events/"


class EventTestCase(APITestCase):

    def setUp(self):
        # Visible and relevant
        test1 = createEventObject(
            "Testitapahtuma1",
            start_time=timezone.datetime(2019, 11, 9, 12, 0, 0))
        # Invisible but relevant
        createEventObject(
            "Testitapahtuma2",
            visible=False,
            start_time=timezone.datetime(2018, 11, 9, 12, 0, 0))
        # Visible but unrelevant
        test2 = createEventObject(
            "Testitapahtuma3",
            visible=True,
            start_time=timezone.datetime(2018, 12, 9, 12, 0, 0),
            end_time=timezone.datetime(2018, 12, 9, 13, 0, 0))
        # Visible and relevant
        createEventObject(
            "Testitapahtuma4",
            visible=True,
            start_time=timezone.datetime(2018, 12, 9, 12, 0, 0))
        # Add some tags
        tag1 = tagBuilder()
        tag2 = tagBuilder("testtag2")
        self.testTagId = tag1.id
        test1.tags.add(tag1)
        test2.tags.add(tag2)
        self.testEventId = test1.id
        self.assertEqual(Event.objects.count(), 4)

        self.signupFormId = createSignupForm().id

        username, password = "test_admin", "password123"
        self.authClient = User.objects.create_superuser(username, "myemail@test.com", password)

    def test_get_current_events(self):
        # Get from API
        response = self.client.get(URL, format="json")
        # Response 200
        self.assertTrue(response.status_code, status.HTTP_200_OK)
        # Response should not have old events and invisible
        self.assertEqual(len(response.data["results"]), 2)
        # Check that serialized data is equal to received response
        expected_events = EventSerializer(
            Event.objects.filter(title_fi__in=("Testitapahtuma1", "Testitapahtuma4")).order_by("start_time"),
            many=True,
            context={
                "request": APIRequestFactory().get(r"http://testserver/api/events/")
            }
        )
        self.assertEqual(response.data["results"], expected_events.data)

    def test_get_events_since(self):
        response = self.client.get(f"{URL}?since=2018-01-01", format="json")
        self.assertTrue(response.status_code, status.HTTP_200_OK)
        self.assertEqual(len(response.data["results"]), 3)

        expected_events = EventSerializer(
            Event.objects.filter(title_fi__in=("Testitapahtuma1", "Testitapahtuma3", "Testitapahtuma4")).order_by("start_time"),
            many=True,
            context={
                "request": APIRequestFactory().get(r"http://testserver/api/events/")
            }
        )
        self.assertEqual(response.data["results"], expected_events.data)

    def test_get_single_event(self):
        response = self.client.get(f"{URL}{self.testEventId}/", format="json")
        self.assertEqual(response.status_code, status.HTTP_200_OK)

        serializer = EventSerializer(
            Event.objects.get(title_fi="Testitapahtuma1"),
            context={
                "request": APIRequestFactory().get(r"http://testserver/api/events/")
            }
        )
        self.assertEqual(response.data, serializer.data)

    def test_get_invalid_event(self):
        response = self.client.get(f"{URL}200/", format="json")
        self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)

    def test_post_event(self):
        # Authenticate
        self.client.force_authenticate(user=self.authClient)
        response = self.client.post(
            URL,
            createEventJSON(tag_id=[self.testTagId], signup_id=[self.signupFormId]),
            format="json"
        )

        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
        self.assertEqual(Event.objects.count(), 5)

    def test_post_event_unauth(self):
        response = self.client.post(
            URL,
            createEventJSON(tag_id=[self.testTagId], signup_id=[self.signupFormId]),
            format="json"
        )

        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        self.assertEqual(Event.objects.count(), 4)

    def test_update_event(self):
        # Authenticate
        self.client.force_authenticate(user=self.authClient)
        event = Event.objects.get(id=self.testEventId)
        new = createEventJSON(name="Update1", signup_id=[self.signupFormId])
        response = self.client.put(
            f"{URL}{self.testEventId}/",
            new,
            format="json"
        )

        self.assertEqual(response.status_code, status.HTTP_200_OK)
        event = Event.objects.get(id=self.testEventId)
        self.assertEqual(event.title_fi, "title_fi Update1")
        self.assertEqual(Event.objects.count(), 4)

    def test_update_event_unauth(self):
        response = self.client.put(
            f"{URL}{self.testEventId}/",
            createEventJSON(name="Update1"),
            format="json"
        )

        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        event = Event.objects.get(id=self.testEventId)
        self.assertEqual(event.title_fi, "Testitapahtuma1")
        self.assertEqual(Event.objects.count(), 4)

    def test_delete_event(self):
        response = self.client.delete(f"{URL}{self.testEventId}/",)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
        self.assertEqual(Event.objects.count(), 4)

        # Authenticate
        self.client.force_authenticate(user=self.authClient)
        response = self.client.delete(f"{URL}{self.testEventId}/")
        self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
        self.assertEqual(Event.objects.count(), 3)
