"""
Author: Michel Peltriaux
Organization: Struktur- und Genehmigungsdirektion Nord, Rhineland-Palatinate, Germany
Contact: ksp-servicestelle@sgdnord.rlp.de
Created on: 30.08.23

"""
from django.core.exceptions import ObjectDoesNotExist
from django.test import RequestFactory
from django.utils.timezone import now

from compensation.forms.modals.deadline import NewDeadlineModalForm
from compensation.models import CompensationDocument
from konova.forms.modals import RemoveDeadlineModalForm
from konova.models import DeadlineType
from konova.tests.test_views import BaseTestCase
from konova.utils.message_templates import DEADLINE_REMOVED, DOCUMENT_REMOVED_TEMPLATE, COMPENSATION_REMOVED_TEMPLATE, \
    DEADLINE_ADDED
from user.models import UserAction, Team


class AbstractCompensationModelTestCase(BaseTestCase):
    def setUp(self) -> None:
        super().setUp()
        self.request = RequestFactory().request()
        self.request.user = self.superuser

    def test_remove_deadline(self):
        self.compensation.deadlines.add(self.finished_deadline)

        data = {
            "confirm": True
        }

        form = RemoveDeadlineModalForm(
            data,
            request=self.request,
            instance=self.compensation,
            deadline=self.finished_deadline,
        )
        self.assertTrue(form.is_valid(), msg=form.errors)
        self.assertIn(self.finished_deadline, self.compensation.deadlines.all())
        form.save()

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.user, self.request.user)
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.comment, DEADLINE_REMOVED)

        self.assertNotIn(self.finished_deadline, self.compensation.deadlines.all())
        try:
            self.finished_deadline.refresh_from_db()
            self.fail("Deadline should not exist anymore after removing from abstract compensation")
        except ObjectDoesNotExist:
            pass

    def test_add_deadline(self):
        request = RequestFactory().request()
        request.user = self.superuser

        data = {
            "type": DeadlineType.MAINTAIN,
            "date": now().date(),
            "comment": "TestDeadline"
        }
        form = NewDeadlineModalForm(
            data,
            request=self.request,
            instance=self.compensation,
        )
        self.assertTrue(form.is_valid(), msg=form.errors)
        deadline = self.compensation.add_deadline(form)
        self.assertEqual(deadline.date, data["date"])
        self.assertEqual(deadline.type, data["type"])
        self.assertEqual(deadline.comment, data["comment"])
        self.assertEqual(deadline.created.action, UserAction.CREATED)
        self.assertEqual(deadline.created.user, self.superuser)
        self.assertEqual(deadline.created.comment, None)
        self.assertIn(deadline, self.compensation.deadlines.all())

        last_log = self.compensation.log.first()
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.comment, DEADLINE_ADDED)


class CompensationTestCase(BaseTestCase):
    def setUp(self) -> None:
        super().setUp()

    def test_str(self):
        self.assertEqual(str(self.compensation), self.compensation.identifier)

    def test_save(self):
        old_identifier = self.compensation.identifier
        self.compensation.identifier = None
        self.compensation.save()
        self.assertIsNotNone(self.compensation.identifier)
        self.assertNotEqual(old_identifier, self.compensation.identifier)

    def test_share_with_user(self):
        self.assertNotIn(self.user, self.compensation.shared_users)
        self.compensation.share_with_user(self.user)
        self.assertIn(self.user, self.compensation.shared_users)

    def test_share_with_user_list(self):
        user_list = [
            self.user
        ]
        self.assertNotIn(self.user, self.compensation.shared_users)
        self.compensation.share_with_user_list(user_list)
        self.assertIn(self.user, self.compensation.shared_users)
        user_list = [
            self.superuser
        ]
        self.assertNotIn(self.superuser, self.compensation.shared_users)
        self.compensation.share_with_user_list(user_list)
        self.assertIn(self.superuser, self.compensation.shared_users)
        self.assertNotIn(self.user, self.compensation.shared_users)

    def test_share_with_team(self):
        self.assertNotIn(self.team, self.compensation.shared_teams)
        self.compensation.share_with_team(self.team)
        self.assertIn(self.team, self.compensation.shared_teams)

    def test_share_with_team_list(self):
        self.compensation.share_with_team(self.team)
        self.assertIn(self.team, self.compensation.shared_teams)
        other_team = Team.objects.create(
            name="NewTeam"
        )
        team_list = [
            other_team
        ]
        self.compensation.share_with_team_list(team_list)
        self.assertIn(other_team, self.compensation.shared_teams)
        self.assertNotIn(self.team, self.compensation.shared_teams)

    def test_shared_users(self):
        intervention = self.compensation.intervention
        diff = self.compensation.shared_users.difference(intervention.shared_users)
        self.assertEqual(diff.count(), 0)

        self.compensation.share_with_user(self.superuser)
        diff = self.compensation.shared_users.difference(intervention.shared_users)
        self.assertEqual(diff.count(), 0)

    def test_shared_teams(self):
        intervention = self.compensation.intervention
        diff = self.compensation.shared_users.difference(intervention.shared_users)
        self.assertEqual(diff.count(), 0)

        self.compensation.share_with_user(self.superuser)
        diff = self.compensation.shared_users.difference(intervention.shared_users)
        self.assertEqual(diff.count(), 0)

    def test_get_documents(self):
        doc = self.create_dummy_document(CompensationDocument, self.compensation)
        docs = self.compensation.get_documents()
        self.assertIn(doc, docs)

    def test_mark_as_deleted(self):
        self.assertIsNone(self.compensation.deleted)
        self.compensation.mark_as_deleted(self.superuser, send_mail=False)

        comp_deleted = self.compensation.deleted
        self.assertIsNotNone(comp_deleted)
        self.assertEqual(comp_deleted.action, UserAction.DELETED)
        self.assertEqual(comp_deleted.user, self.superuser)
        self.assertEqual(comp_deleted.comment, None)

        intervention_last_log = self.compensation.intervention.log.first()
        self.assertEqual(intervention_last_log.action, UserAction.EDITED)
        self.assertEqual(intervention_last_log.user, self.superuser)
        self.assertEqual(
            intervention_last_log.comment,
            COMPENSATION_REMOVED_TEMPLATE.format(
                self.compensation.identifier
            )
        )


class CompensationDocumentTestCase(BaseTestCase):
    def setUp(self) -> None:
        super().setUp()
        self.doc = self.create_dummy_document(CompensationDocument, self.compensation)

    def test_delete(self):
        doc_title = self.doc.title
        self.assertIn(self.doc, self.compensation.get_documents())
        self.doc.delete(self.superuser)
        self.assertNotIn(self.doc, self.compensation.get_documents())
        try:
            self.doc.refresh_from_db()
            self.fail("Document should not be fetchable anymore")
        except ObjectDoesNotExist:
            pass
        last_log = self.compensation.log.first()
        self.assertEqual(last_log.user, self.superuser)
        self.assertEqual(last_log.action, UserAction.EDITED)
        self.assertEqual(last_log.comment, DOCUMENT_REMOVED_TEMPLATE.format(doc_title))
