from django.db.models import ProtectedError
from django.test import TestCase, Client

from gameruns.models import EmailGameRuns
from training.models import *
from django.urls import reverse


class TestViews(TestCase):
    def setUp(self):
        self.client = Client()

        self.sign1 = Signs.objects.create(
            text='sign1'
        )

        self.typeDeletable = Types.objects.create(
            type='typeDeletable'
        )

        self.typeNonDeletable = Types.objects.create(
            type='typeNonDeletable'
        )

        self.email1 = Emails.objects.create(
            content='email1',
            type=self.typeNonDeletable
        )

        self.gameRun1 = GameRuns.objects.create(
            session='1234',
            player_name='patrik',
        )

        self.emailGameRun1 = EmailGameRuns.objects.create(
            email=self.email1,
            game_run=self.gameRun1,
            player_answer=True
        )

    def test_email_list_GET(self):
        """
            test if client can get list of emails
        """
        response = self.client.get(reverse('email_list-list'))
        self.assertEqual(response.status_code, 200)

    def test_sign_list_GET(self):
        """
            test if client can get list of signs
        """
        response = self.client.get(reverse('sign_list-list'))
        self.assertEqual(response.status_code, 200)

    def test_type_list_GET(self):
        """
            test if client can get list of types
        """
        response = self.client.get(reverse('type_list-list'))
        self.assertEqual(response.status_code, 200)

    def test_gamerun_list_GET(self):
        """
            test if client can get list of gameruns
        """
        response = self.client.get(reverse('gamerun_list-list'))
        self.assertEqual(response.status_code, 200)

    def test_egrun_list_GET(self):
        """
            test if client can get list of m:n table gameruns-emails
        """
        response = self.client.get(reverse('egrun_list-list'))
        self.assertEqual(response.status_code, 200)

    def test_type_POST(self):
        """
            test if client can post types
        """
        url = reverse('type_list-list')
        text = 'spear phishing'
        data = {
            'type': text
        }
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, 201)
        self.assertEqual(Types.objects.filter(type__exact=text)[:1].get().type, text)

    def test_sign_POST(self):
        """
            test if client can post signs
        """
        url = reverse('sign_list-list')
        text = 'suspicious sender'
        data = {
            'text': text
        }
        response = self.client.post(url, data)
        self.assertEqual(response.status_code, 201)
        self.assertEqual(Signs.objects.filter(text__exact=text)[:1].get().text, text)

    def test_email_POST(self):
        """
            test if client can post emails
        """
        url = reverse('email_list-list')
        text = 'Dear Martin, how are you?'
        data = {
            'content': text,
            'type': self.typeDeletable.type_id,
            'sign': self.sign1.sign_id
        }
        response = self.client.post(url, data)

        self.assertEqual(response.status_code, 201)
        self.assertEqual(Emails.objects.filter(content__exact=text)[:1].get().content, text)

    def test_game_run_POST(self):
        """
            test if client can post game runs
        """
        url = reverse('gamerun_list-list')

        data = {
            'session': '2222',
            'player_name': 'Patrik'
        }
        response = self.client.post(url, data)

        self.assertEqual(response.status_code, 201)
        self.assertEqual(GameRuns.objects.filter(session__exact='2222')[:1].count(), 1)

    def test_email_game_run_POST(self):
        """
            test if client can post m:n table gameruns-emails
        """
        url = reverse('egrun_list-list')

        data = {
            'email': self.email1.email_id,
            'game_run': self.gameRun1.game_run_id,
            'player_answer': True
        }
        response = self.client.post(url, data)

        self.assertEqual(response.status_code, 201)
        self.assertEqual(EmailGameRuns.objects.count(), 2)

    def test_sign_DELETE(self):
        """
            test if client can delete signs
        """
        url = reverse('sign_list-detail', kwargs={'pk': self.sign1.sign_id})
        response = self.client.delete(url)

        self.assertEqual(response.status_code, 204)
        self.assertEqual(Signs.objects.count(), 0)

    def test_type_DELETE(self):
        """
            test if client can delete types
        """
        url = reverse('type_list-detail', kwargs={'pk': self.typeDeletable.type_id})
        response = self.client.delete(url)

        self.assertEqual(response.status_code, 204)
        self.assertEqual(Types.objects.count(), 1)

    def test_type_DELETE_with_email_assigned(self):
        """
            test if client can delete type with email assigned to it
        """
        url = reverse('type_list-detail', kwargs={'pk': self.typeNonDeletable.type_id})

        try:
            self.client.delete(url)
            self.assertTrue(False)
        except ProtectedError:
            self.assertTrue(True)

    def test_sign_DELETE_with_email_assigned(self):
        """
            test if client can delete type with no email assigned
        """
        self.email1.sign.add(self.sign1)

        url = reverse('sign_list-detail', kwargs={'pk': self.sign1.sign_id})
        response = self.client.delete(url)

        self.assertEqual(response.status_code, 204)
        self.assertEqual(self.email1.sign.count(), 0)

    def test_email_DELETE(self):
        """
            test if client can delete email
        """
        self.email1.sign.add(self.sign1)

        url = reverse('email_list-detail', kwargs={'pk': self.email1.email_id})
        response = self.client.delete(url)

        self.assertEqual(response.status_code, 204)
        self.assertEqual(Emails.objects.count(), 0)
        self.assertEqual(self.sign1.emails_set.count(), 0)
        self.assertEqual(self.typeNonDeletable.emails_set.count(), 0)

    def test_email_DELETE_egruns_cascade(self):
        """
            test if deleting email will delete record in m:n table gameruns-emails automatically
        """
        url = reverse('email_list-detail', kwargs={'pk': self.email1.email_id})
        response = self.client.delete(url)

        self.assertEqual(response.status_code, 204)
        self.assertEqual(EmailGameRuns.objects.count(), 0)
        self.assertEqual(self.gameRun1.emailgameruns_set.count(), 0)

    def test_gamerun_DELETE_egruns_cascade(self):
        """
            test if deleting game run will delete record in m:n table gameruns-emails automatically
        """
        url = reverse('gamerun_list-detail', kwargs={'pk': self.gameRun1.game_run_id})
        response = self.client.delete(url)

        self.assertEqual(response.status_code, 204)
        self.assertEqual(EmailGameRuns.objects.count(), 0)
        self.assertEqual(self.email1.emailgameruns_set.count(), 0)
