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

"""
from django.test import RequestFactory
from django.utils.timezone import now

from intervention.forms.modals.share import ShareModalForm
from konova.models import DeadlineType, Resubmission
from konova.settings import ZB_GROUP
from konova.tests.test_views import BaseTestCase
from user.models import UserAction



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

    def test_str(self):
        self.assertEqual(str(self.finished_deadline), self.finished_deadline.type)

    def test_type_humanized_property(self):
        self.assertEqual(self.finished_deadline.type_humanized, DeadlineType.FINISHED.label)


class BaseObjectTestCase(BaseTestCase):
    def test_add_log_entry(self):
        self.assertEqual(self.intervention.log.count(), 0)
        self.intervention.add_log_entry(UserAction.EDITED, self.user, "TEST")
        self.assertEqual(self.intervention.log.count(), 1)
        last_log = self.intervention.log.first()
        self.assertEqual(last_log.user, self.user)
        self.assertEqual(last_log.comment, "TEST")
        self.assertEqual(last_log.action, UserAction.EDITED)

    def test_generate_new_identifier(self):
        old_identifier = self.intervention.identifier
        new_identifier = self.intervention.generate_new_identifier()
        self.assertNotEqual(old_identifier, new_identifier)


class RecordableObjectMixinTestCase(BaseTestCase):
    def test_set_recorded_and_set_unrecorded(self):
        """ Tests set_unrecorded() as well

        Returns:

        """
        self.intervention.set_recorded(self.user)
        self.assertIsNotNone(self.intervention.recorded)
        self.assertEqual(self.intervention.recorded.user, self.user)
        self.assertEqual(self.intervention.recorded.action, UserAction.RECORDED)

        self.intervention.set_unrecorded(self.user)
        self.assertIsNone(self.intervention.recorded)
        last_log = self.intervention.log.first()
        self.assertEqual(last_log.action, UserAction.UNRECORDED)
        self.assertEqual(last_log.user, self.user)


class CheckableObjectMixinTestCase(BaseTestCase):
    def test_set_unchecked_and_set_checked(self):
        self.intervention.set_checked(self.user)
        self.assertIsNotNone(self.intervention.checked)
        self.assertEqual(self.intervention.checked.action, UserAction.CHECKED)
        self.assertEqual(self.intervention.checked.user, self.user)
        checked_action = self.intervention.checked

        self.intervention.set_unchecked()
        self.assertIsNone(self.intervention.checked)

        # There is no explicit UNCHECKED UserAction since unchecking does never happen manually but only as an
        # automatic consequence of editing an already checked entry. Therefore the last log entry in this case would
        # be the checking of the entry
        last_log = self.intervention.log.first()
        self.assertEqual(last_log.action, UserAction.CHECKED)
        self.assertEqual(last_log.user, self.user)
        self.assertEqual(last_log, checked_action)

    def test_get_last_checked_action(self):
        self.intervention.set_checked(self.user)
        action = self.intervention.checked

        self.intervention.mark_as_edited(self.user)
        last_log = self.intervention.log.first()
        self.assertNotEqual(last_log, action)

        last_check_action = self.intervention.get_last_checked_action()
        self.assertEqual(action, last_check_action)


class ShareableObjectMixinTestCase(BaseTestCase):
    def test_share_with_and_is_shared_with(self):
        self.assertFalse(self.intervention.is_shared_with(self.user))
        self.assertNotIn(self.user, self.intervention.shared_users)

        self.intervention.share_with_user(self.user)
        self.assertTrue(self.intervention.is_shared_with(self.user))
        self.assertIn(self.user, self.intervention.shared_users)

        self.assertTrue(self.intervention.is_only_shared_with(self.user))
        self.assertFalse(self.intervention.is_only_shared_with(self.superuser))
        self.assertNotIn(self.superuser, self.intervention.shared_users)
        self.intervention.share_with_user(self.superuser)
        self.assertFalse(self.intervention.is_only_shared_with(self.user))
        self.assertIn(self.superuser, self.intervention.shared_users)

        self.intervention.share_with_user_list([])
        self.assertNotIn(self.superuser, self.intervention.shared_users)
        self.assertNotIn(self.user, self.intervention.shared_users)
        self.intervention.share_with_user_list([
            self.superuser,
            self.user
        ])
        self.assertIn(self.superuser, self.intervention.shared_users)
        self.assertIn(self.user, self.intervention.shared_users)

    def test_share_with_team_and_team_list(self):
        self.assertNotIn(self.team, self.intervention.shared_teams)
        self.intervention.share_with_team(self.team)
        self.assertIn(self.team, self.intervention.shared_teams)

        another_team = self.create_dummy_team(name="Another team")
        team_list = [
            self.team,
            another_team
        ]
        self.assertNotIn(another_team, self.intervention.shared_teams)
        self.intervention.share_with_team_list(team_list)
        self.assertIn(another_team, self.intervention.shared_teams)

    def test_update_shared_access(self):
        another_team = self.create_dummy_team(name="Another team")
        request = RequestFactory().request()
        request.user = self.superuser
        self.superuser.groups.add(
            self.groups.get(name=ZB_GROUP)
        )

        self.intervention.share_with_team(another_team)
        self.intervention.share_with_user(self.user)
        self.assertTrue(self.intervention.is_shared_with(self.user))
        self.assertIn(another_team, self.intervention.shared_teams)

        data = {
            "users": [
                self.superuser.id,
            ],
            "teams": [
                self.team.id,
            ]
        }
        form = ShareModalForm(data, request=request, instance=self.intervention)
        self.assertTrue(form.is_valid(), msg=form.errors)
        form.save()
        self.assertNotIn(self.user, self.intervention.shared_users)
        self.assertNotIn(another_team, self.intervention.shared_teams)
        self.assertIn(self.superuser, self.intervention.shared_users)
        self.assertIn(self.team, self.intervention.shared_teams)

    def test_unshare_with_default_users(self):
        self.superuser.groups.add(
            self.groups.get(
                name=ZB_GROUP
            )
        )
        self.intervention.share_with_user(self.user)
        self.intervention.share_with_user(self.superuser)

        self.assertTrue(self.user.is_default_group_only())
        self.assertFalse(self.superuser.is_default_group_only())

        self.assertTrue(self.intervention.is_shared_with(self.user))
        self.assertTrue(self.intervention.is_shared_with(self.superuser))

        self.intervention.unshare_with_default_users()
        self.assertFalse(self.intervention.is_shared_with(self.user))
        self.assertTrue(self.intervention.is_shared_with(self.superuser))


class ResubmissionTestCase(BaseTestCase):
    def test_send_resubmission_mail(self):
        resubmission = Resubmission.objects.create(
            user=self.user,
            resubmit_on=now().date(),
            comment="Test",
        )
        self.intervention.resubmissions.add(resubmission)

        self.assertFalse(resubmission.resubmission_sent)
        resubmission.send_resubmission_mail(
            self.intervention.id,
            self.intervention.get_app_object_tuple()
        )
        self.assertTrue(resubmission.resubmission_sent)
