from django.test import TestCase
from django.contrib.auth.models import User, Group
from django.urls import reverse

from .models import Person, Event
from apis_core.apis_metainfo.models import Text, Collection
from apis_core.apis_vocabularies.models import ProfessionType
from reversion import revisions as reversion

from datetime import datetime
from rest_framework.authtoken.models import Token
from rest_framework.test import APIClient
from django.contrib.auth.models import Permission


class PersonModelTestCase(TestCase):
    name = "test name"
    first_name = "test first name"
    text = "kjhkjsdhaslkdhadh lasdjalsk alsjdhaksjdh"
    col_name = "Test collection"
    col_name2 = "Test collection2"
    start_date = "1.3.1930"
    end_date = "4.6.1960"
    prof1 = "Lehrer"
    prof2 = "Politiker"

    @classmethod
    def setUpTestData(cls):
        # Set up data for the whole TestCase
        cls.txt = Text.objects.create(text=cls.text)
        cls.col = Collection.objects.create(name=cls.col_name)
        cls.col2 = Collection.objects.create(name=cls.col_name2)
        cls.prof1 = ProfessionType.objects.create(name=cls.prof1)
        cls.prof2 = ProfessionType.objects.create(name=cls.prof2)

    def test_init(self):
        Person()

    def test_create_object(self):
        p = Person.objects.create(
            name=self.name,
            first_name=self.first_name,
            start_date_written=self.start_date,
            end_date_written=self.end_date,
        )

    def test_object_connections(self):
        p = Person.objects.create(
            name=self.name,
            first_name=self.first_name,
            start_date_written=self.start_date,
            end_date_written=self.end_date,
        )
        p.collection.add(self.col)
        p.text.add(self.txt)

    def test_object_validity(self):
        p = Person.objects.create(
            name=self.name,
            first_name=self.first_name,
            start_date_written=self.start_date,
            end_date_written=self.end_date,
        )
        p.collection.add(self.col)
        p.text.add(self.txt)
        self.assertEqual(p.name, self.name)
        self.assertEqual(p.first_name, self.first_name)
        self.assertEqual(p.start_date_written, self.start_date)
        self.assertEqual(p.start_date, datetime.strptime(self.start_date, "%d.%m.%Y"))

    def test_date_parsing_year(self):
        p = Person.objects.create(
            name=self.name,
            first_name=self.first_name,
            start_date_written="1880",
            end_date_written="1890",
        )
        self.assertEqual(p.start_start_date, datetime.strptime("1.1.1880", "%d.%m.%Y"))
        self.assertEqual(p.start_end_date, datetime.strptime("31.12.1880", "%d.%m.%Y"))
        self.assertEqual(p.end_start_date, datetime.strptime("1.1.1890", "%d.%m.%Y"))
        self.assertEqual(p.end_end_date, datetime.strptime("31.12.1890", "%d.%m.%Y"))
        self.assertEqual(p.start_date, datetime.strptime("1.7.1880", "%d.%m.%Y"))

    def test_date_parsing_override(self):
        p = Person.objects.create(
            name=self.name,
            first_name=self.first_name,
            start_date_written="1880<1880-02-01>",
            end_date_written="1890<1890-05-01>",
        )
        self.assertEqual(p.start_date, datetime.strptime("1.2.1880", "%d.%m.%Y"))
        self.assertEqual(p.end_date, datetime.strptime("1.5.1890", "%d.%m.%Y"))

    def test_date_parsing_override_range(self):
        p = Person.objects.create(
            name=self.name,
            first_name=self.first_name,
            start_date_written="1880<1880-05-01,1880-01-01,1880-12-31>",
            end_date_written="1890<1890-05-01>",
        )
        self.assertEqual(p.start_start_date, datetime.strptime("1.1.1880", "%d.%m.%Y"))
        self.assertEqual(p.start_date, datetime.strptime("1.5.1880", "%d.%m.%Y"))
        self.assertEqual(p.start_end_date, datetime.strptime("31.12.1880", "%d.%m.%Y"))

    def test_merge_entities(self):
        p1 = Person.objects.create(name="person1")
        p2 = Person.objects.create(name="person2")
        p1.collection.add(self.col)
        p1.profession.add(self.prof1)
        p2.collection.add(self.col2)
        p2.profession.add(self.prof2)
        p1.merge_with(p2)
        self.assertEqual(p1.collection.all().count(), 2)
        self.assertEqual(p1.profession.all().count(), 2)

    def test_merge_entities_no_selfself(self):
        p1 = Person.objects.first()
        self.assertRaises(ValueError, p1.merge_with, [p1,])
 
"""
    def test_object_reversion(self):
        with reversion.create_revision():
            p = Person.objects.create(
                name=self.name,
                first_name=self.first_name,
                start_date_written=self.start_date,
                end_date_written=self.end_date)
            p.collection.add(self.col)
            p.text.add(self.txt)
        with reversion.create_revision():
            p2 = Person.objects.get(name=self.name)
            p2.name = 'testname 2'
            p2.save()
        self.assertEqual(p2.name, 'testname 2')
        versions = Version.objects.get_for_object(p2)
        self.assertEqual(len(versions), 2)
        self.assertEqual(versions[0].field_dict['name'], 'testname 2')
        self.assertEqual(versions[1].field_dict['name'], self.name)
"""  # TODO: solve the reversion datetime error


class PermissionsModelTestCase(TestCase):
    name = "test name"
    first_name = "test first name"
    text = "kjhkjsdhaslkdhadh lasdjalsk alsjdhaksjdh"
    col_name = "Test collection"
    start_date = "1.3.1930"
    end_date = "4.6.1960"

    @classmethod
    def setUpTestData(cls):
        # Set up data for the whole TestCase
        cls.txt = Text.objects.create(text=cls.text)
        cls.col = Collection.objects.create(name=cls.col_name)
        cls.pers = Person.objects.create(
            name=cls.name,
            first_name=cls.first_name,
            # start_date_written=cls.start_date,  TODO: serializer throwing error on date
            # end_date_written=cls.end_date
        )
        cls.user = User.objects.create_user("testuser", "apisdev16")
        pe = Permission.objects.get(name="Can change person")
        cls.user.user_permissions.add(pe)
        cls.token = Token.objects.create(user=cls.user).key
        cls.group = Group.objects.create(name="testgroup")
        cls.col.groups_allowed.add(cls.group)
        cls.user.groups.add(cls.group)
        cls.c = APIClient()
        cls.c.credentials(HTTP_AUTHORIZATION="Token " + cls.token)

    def test_no_perm(self):
        res = self.c.patch(
            reverse("apis:apis_core:person-detail", kwargs={"pk": self.pers.pk}),
            data={"name": "changed name"},
            # format='json'
        )
        print(f"no permissions, patch: {res.status_code}")
        self.assertEqual(res.status_code, 403)

    def test_no_perm_view(self):
        res = self.c.get(
            reverse("apis:apis_core:person-detail", kwargs={"pk": self.pers.pk}),
        )
        print(f"no permissions, get: {res.status_code}")
        self.assertEqual(res.status_code, 200)

    def test_perm(self):
        self.pers.collection.add(self.col)
        res = self.c.patch(
            reverse("apis:apis_core:person-detail", kwargs={"pk": self.pers.pk}),
            data={"name": "changed name"},
            # format='json'
        )
        print(f"permissions granted, patch: {res.status_code}")
        self.assertEqual(res.status_code, 200)

    def test_perm_removed(self):
        self.pers.collection.remove(self.col)
        res = self.c.patch(
            reverse("apis:apis_core:person-detail", kwargs={"pk": self.pers.pk}),
            data={"name": "changed name"},
            # format='json'
        )
        print(f"permissions revoked, patch: {res.status_code}")
        self.assertEqual(res.status_code, 403)
 