class PhDTabFormView(TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.settings = SettingsFactory()

        cls.current_academic_year = AcademicYearFactory(current=True)
        cls.tutor = TutorFactory()

        cls.get_url = reverse("form_part3_edit")
        cls.post_url = reverse("form_part3_save")

    def setUp(self) -> None:
        self.assistant_mandate = AssistantMandateFactory(
            academic_year=self.current_academic_year,
            state=assistant_mandate_state.TRTS)
        self.client.force_login(self.assistant_mandate.assistant.person.user)

    def test_template_used_for_get(self):
        response = self.client.get(self.get_url)

        self.assertTemplateUsed(response, "assistant_form_part3.html")

    def test_invalid_post_if_inscription_set_and_no_promoter_given(self):
        data = {
            "mand-thesis_title": "My thesis",
            "mand-remark": "This is my remark",
            "mand-inscription": assistant_phd_inscription.IN_PROGRESS,
        }

        response = self.client.post(self.post_url, data=data)
        self.assertFalse(response.context["form"].is_valid())

    def test_invalid_post_data_if_no_inscription_information_given(self):
        data = {
            "mand-thesis_title": "My thesis",
            "mand-remark": "This is my remark",
            "mand-supervisor": str(self.tutor.person.id)
        }

        response = self.client.post(self.post_url, data=data)
        self.assertFalse(response.context["form"].is_valid())

    def test_valid_post_data_if_no_inscription_to_phd_and_no_promoter_given(
            self):
        data = {
            "mand-thesis_title": "My thesis",
            "mand-remark": "This is my remark",
            "mand-inscription": assistant_phd_inscription.NO,
        }

        self.client.post(self.post_url, data=data)

        self.assert_assistant_mandate_equal_to_post_data(data)

    def test_valid_post_with_promoter_given(self):
        data = {
            "mand-thesis_title": "My thesis",
            "mand-remark": "This is my remark",
            "mand-inscription": assistant_phd_inscription.YES,
            "mand-supervisor": str(self.tutor.person.id)
        }

        self.client.post(self.post_url, data=data)

        self.assert_assistant_mandate_equal_to_post_data(data)

    def assert_assistant_mandate_equal_to_post_data(self, post_data: Dict):
        self.assistant_mandate.refresh_from_db()

        academic_assistant_obj = self.assistant_mandate.assistant  # type: academic_assistant.AcademicAssistant
        for field_name, field_value in post_data.items():
            cleaned_field_name = field_name.lstrip("mand-")
            if cleaned_field_name == "supervisor":
                self.assertEqual(str(academic_assistant_obj.supervisor.id),
                                 field_value, field_name)
            else:
                self.assertEqual(
                    getattr(academic_assistant_obj, cleaned_field_name),
                    field_value, cleaned_field_name)
class TestMandateEntity(TestCase):
    def setUp(self):
        self.factory = RequestFactory()
        self.client = Client()
        self.manager = ManagerFactory()
        self.settings = SettingsFactory()
        self.client.force_login(self.manager.person.user)
        self.assistant = AcademicAssistantFactory()
        self.assistant_mandate = AssistantMandateFactory(
            state=assistant_mandate_state.TRTS,
            assistant=self.assistant,
            assistant_type=assistant_type.ASSISTANT)
        self.assistant2 = AcademicAssistantFactory()
        self.assistant_mandate2 = AssistantMandateFactory(
            state=assistant_mandate_state.SUPERVISION,
            assistant=self.assistant2,
            assistant_type=assistant_type.TEACHING_ASSISTANT)
        self.entity1 = EntityFactory()
        self.entity_version1 = EntityVersionFactory(
            entity=self.entity1, entity_type=entity_type.SECTOR)
        self.entity2 = EntityFactory()
        self.entity_version2 = EntityVersionFactory(
            entity=self.entity2, entity_type=entity_type.FACULTY)
        self.entity3 = EntityFactory()
        self.entity_version3 = EntityVersionFactory(
            entity=self.entity3, entity_type=entity_type.INSTITUTE)
        self.entity4 = EntityFactory()
        self.entity_version4 = EntityVersionFactory(
            entity=self.entity4,
            parent=self.entity2,
            entity_type=entity_type.SCHOOL)

        self.mandate_entity1 = MandateEntityFactory(
            assistant_mandate=self.assistant_mandate, entity=self.entity1)
        self.mandate_entity2 = MandateEntityFactory(
            assistant_mandate=self.assistant_mandate, entity=self.entity2)
        self.mandate_entity3 = MandateEntityFactory(
            assistant_mandate=self.assistant_mandate, entity=self.entity3)

        self.mandate_entity4 = MandateEntityFactory(
            assistant_mandate=self.assistant_mandate2, entity=self.entity1)
        self.mandate_entity5 = MandateEntityFactory(
            assistant_mandate=self.assistant_mandate2, entity=self.entity2)

        self.reviewer1 = ReviewerFactory(entity=self.entity3,
                                         role=reviewer_role.RESEARCH)
        self.reviewer2 = ReviewerFactory(entity=self.entity2,
                                         role=reviewer_role.SUPERVISION)
        self.reviewer3 = ReviewerFactory(entity=self.entity1,
                                         role=reviewer_role.VICE_RECTOR)
        self.reviewer4 = ReviewerFactory(entity=None,
                                         role=reviewer_role.PHD_SUPERVISOR)

    def test_mandate_can_go_backward(self):
        self.assertTrue(mandate_can_go_backward(self.assistant_mandate))
        self.assistant_mandate.state = assistant_mandate_state.RESEARCH
        self.assistant_mandate.save()
        self.review1 = ReviewFactory(reviewer=self.reviewer1,
                                     mandate=self.assistant_mandate,
                                     status=review_status.IN_PROGRESS)
        self.assertFalse(mandate_can_go_backward(self.assistant_mandate))
        self.review1.delete()
        self.assistant_mandate.state = assistant_mandate_state.TO_DO
        self.assistant_mandate.save()
        self.assertFalse(mandate_can_go_backward(self.assistant_mandate))

    def test_assistant_mandate_step_back_from_assistant_to_beginning(self):
        self.assistant_mandate.state = assistant_mandate_state.TRTS
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state,
                         assistant_mandate_state.TO_DO)

    def test_assistant_mandate_step_back_from_phd_supervisor_to_assistant(
            self):
        self.assistant_mandate.state = assistant_mandate_state.PHD_SUPERVISOR
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state,
                         assistant_mandate_state.TRTS)

    def test_assistant_mandate_step_back_from_institute_president_to_php_supervisor(
            self):
        self.assistant.supervisor = PersonFactory()
        self.assistant.save()
        self.review1 = ReviewFactory(reviewer=self.reviewer1,
                                     mandate=self.assistant_mandate,
                                     status=review_status.DONE)
        self.review2 = ReviewFactory(reviewer=None,
                                     mandate=self.assistant_mandate,
                                     status=review_status.DONE)
        self.assistant_mandate.state = assistant_mandate_state.RESEARCH
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state,
                         assistant_mandate_state.PHD_SUPERVISOR)

    def test_assistant_mandate_step_back_from_institute_president_to_assistant(
            self):
        # Test if assistant does not have a phd supervisor
        self.assistant_mandate.state = assistant_mandate_state.RESEARCH
        self.assistant_mandate.save()
        self.assistant.supervisor = None
        self.assistant.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state,
                         assistant_mandate_state.TRTS)

    def test_assistant_mandate_step_back_from_dean_of_faculty_to_institute_president(
            self):
        self.research_review = ReviewFactory(mandate=self.assistant_mandate,
                                             reviewer=self.reviewer1)
        self.assistant_mandate.state = assistant_mandate_state.SUPERVISION
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state,
                         assistant_mandate_state.RESEARCH)

    def test_assistant_mandate_step_back_from_vice_rector_to_dean_of_faculty(
            self):
        self.supervision_review = ReviewFactory(mandate=self.assistant_mandate,
                                                reviewer=self.reviewer2)
        self.assistant_mandate.state = assistant_mandate_state.VICE_RECTOR
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state,
                         assistant_mandate_state.SUPERVISION)

    def test_assistant_mandate_step_back_from_dean_of_faculty_to_assistant(
            self):
        # Test if assistant is teaching assistant
        self.research_review = ReviewFactory(mandate=self.assistant_mandate,
                                             reviewer=self.reviewer1)
        self.assistant_mandate.state = assistant_mandate_state.SUPERVISION
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate2.id})
        self.assistant_mandate2.refresh_from_db()
        self.assertEqual(self.assistant_mandate2.state,
                         assistant_mandate_state.TRTS)

    def test_assistant_mandate_step_back_from_done_to_vice_rector(self):
        self.review4 = ReviewFactory(reviewer=self.reviewer3,
                                     mandate=self.assistant_mandate2,
                                     status=review_status.DONE)
        self.review5 = ReviewFactory(reviewer=self.reviewer2,
                                     mandate=self.assistant_mandate2,
                                     status=review_status.DONE)
        self.assistant_mandate2.state = assistant_mandate_state.DONE
        self.assistant_mandate2.save()
        self.client.post(reverse('assistant_mandate_step_back'),
                         {'mandate_id': self.assistant_mandate2.id})
        self.assistant_mandate2.refresh_from_db()
        self.assertEqual(self.assistant_mandate2.state,
                         assistant_mandate_state.VICE_RECTOR)

    def test_add_actions_to_mandates_list(self):
        self.client.force_login(self.reviewer1.person.user)
        response = self.client.get('/assistants/reviewer/')
        context = add_actions_to_mandates_list(response.context,
                                               self.reviewer1)
        for mandate in context['object_list']:
            if mandate.id == self.assistant_mandate.id:
                self.assertFalse(mandate.view)
                self.assertFalse(mandate.edit)
        self.client.force_login(self.reviewer2.person.user)
        response = self.client.get('/assistants/reviewer/')
        context = add_actions_to_mandates_list(response.context,
                                               self.reviewer2)
        for mandate in context['object_list']:
            if mandate.id == self.assistant_mandate2.id:
                self.assertTrue(mandate.view)
                self.assertTrue(mandate.edit)
class TestMandateEntity(TestCase):

    def setUp(self):
        self.factory = RequestFactory()
        self.client = Client()
        self.manager = ManagerFactory()
        self.settings = SettingsFactory()
        self.client.force_login(self.manager.person.user)
        self.assistant = AcademicAssistantFactory()
        self.assistant_mandate = AssistantMandateFactory(
            state=assistant_mandate_state.TRTS,
            assistant=self.assistant,
            assistant_type=assistant_type.ASSISTANT
        )
        self.assistant2 = AcademicAssistantFactory()
        self.assistant_mandate2 = AssistantMandateFactory(
            state=assistant_mandate_state.SUPERVISION,
            assistant=self.assistant2,
            assistant_type=assistant_type.TEACHING_ASSISTANT
        )
        self.entity1 = EntityFactory()
        self.entity_version1 = EntityVersionFactory(entity=self.entity1, entity_type=entity_type.SECTOR)
        self.entity2 = EntityFactory()
        self.entity_version2 = EntityVersionFactory(entity=self.entity2, entity_type=entity_type.FACULTY)
        self.entity3 = EntityFactory()
        self.entity_version3 = EntityVersionFactory(entity=self.entity3, entity_type=entity_type.INSTITUTE)
        self.entity4 = EntityFactory()
        self.entity_version4 = EntityVersionFactory(
            entity=self.entity4, parent=self.entity2, entity_type=entity_type.SCHOOL)

        self.mandate_entity1 = MandateEntityFactory(assistant_mandate=self.assistant_mandate, entity=self.entity1)
        self.mandate_entity2 = MandateEntityFactory(assistant_mandate=self.assistant_mandate, entity=self.entity2)
        self.mandate_entity3 = MandateEntityFactory(assistant_mandate=self.assistant_mandate, entity=self.entity3)

        self.mandate_entity4 = MandateEntityFactory(assistant_mandate=self.assistant_mandate2, entity=self.entity1)
        self.mandate_entity5 = MandateEntityFactory(assistant_mandate=self.assistant_mandate2, entity=self.entity2)

        self.reviewer1 = ReviewerFactory(entity=self.entity3, role=reviewer_role.RESEARCH)
        self.reviewer2 = ReviewerFactory(entity=self.entity2, role=reviewer_role.SUPERVISION)
        self.reviewer3 = ReviewerFactory(entity=self.entity1, role=reviewer_role.VICE_RECTOR)
        self.reviewer4 = ReviewerFactory(entity=None, role=reviewer_role.PHD_SUPERVISOR)

    def test_mandate_can_go_backward(self):
        self.assertTrue(mandate_can_go_backward(self.assistant_mandate))
        self.assistant_mandate.state = assistant_mandate_state.RESEARCH
        self.assistant_mandate.save()
        self.review1 = ReviewFactory(
            reviewer=self.reviewer1,
            mandate=self.assistant_mandate,
            status=review_status.IN_PROGRESS
        )
        self.assertFalse(mandate_can_go_backward(self.assistant_mandate))
        self.review1.delete()
        self.assistant_mandate.state = assistant_mandate_state.TO_DO
        self.assistant_mandate.save()
        self.assertFalse(mandate_can_go_backward(self.assistant_mandate))

    def test_assistant_mandate_step_back_from_assistant_to_beginning(self):
        self.assistant_mandate.state = assistant_mandate_state.TRTS
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state, assistant_mandate_state.TO_DO)

    def test_assistant_mandate_step_back_from_phd_supervisor_to_assistant(self):
        self.assistant_mandate.state = assistant_mandate_state.PHD_SUPERVISOR
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state, assistant_mandate_state.TRTS)

    def test_assistant_mandate_step_back_from_institute_president_to_php_supervisor(self):
        self.assistant.supervisor = PersonFactory()
        self.assistant.save()
        self.review1 = ReviewFactory(
            reviewer=self.reviewer1,
            mandate=self.assistant_mandate,
            status=review_status.DONE
        )
        self.review2 = ReviewFactory(
            reviewer=None,
            mandate=self.assistant_mandate,
            status=review_status.DONE
        )
        self.assistant_mandate.state = assistant_mandate_state.RESEARCH
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state, assistant_mandate_state.PHD_SUPERVISOR)

    def test_assistant_mandate_step_back_from_institute_president_to_assistant(self):
        # Test if assistant does not have a phd supervisor
        self.assistant_mandate.state = assistant_mandate_state.RESEARCH
        self.assistant_mandate.save()
        self.assistant.supervisor = None
        self.assistant.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state, assistant_mandate_state.TRTS)

    def test_assistant_mandate_step_back_from_dean_of_faculty_to_institute_president(self):
        self.research_review = ReviewFactory(mandate=self.assistant_mandate, reviewer=self.reviewer1)
        self.assistant_mandate.state = assistant_mandate_state.SUPERVISION
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state, assistant_mandate_state.RESEARCH)

    def test_assistant_mandate_step_back_from_vice_rector_to_dean_of_faculty(self):
        self.supervision_review = ReviewFactory(mandate=self.assistant_mandate, reviewer=self.reviewer2)
        self.assistant_mandate.state = assistant_mandate_state.VICE_RECTOR
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate.id})
        self.assistant_mandate.refresh_from_db()
        self.assertEqual(self.assistant_mandate.state, assistant_mandate_state.SUPERVISION)

    def test_assistant_mandate_step_back_from_dean_of_faculty_to_assistant(self):
        # Test if assistant is teaching assistant
        self.research_review = ReviewFactory(mandate=self.assistant_mandate, reviewer=self.reviewer1)
        self.assistant_mandate.state = assistant_mandate_state.SUPERVISION
        self.assistant_mandate.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate2.id})
        self.assistant_mandate2.refresh_from_db()
        self.assertEqual(self.assistant_mandate2.state, assistant_mandate_state.TRTS)

    def test_assistant_mandate_step_back_from_done_to_vice_rector(self):
        self.review4 = ReviewFactory(
            reviewer=self.reviewer3,
            mandate=self.assistant_mandate2,
            status=review_status.DONE
        )
        self.review5 = ReviewFactory(
            reviewer=self.reviewer2,
            mandate=self.assistant_mandate2,
            status=review_status.DONE
        )
        self.assistant_mandate2.state = assistant_mandate_state.DONE
        self.assistant_mandate2.save()
        self.client.post(reverse('assistant_mandate_step_back'), {'mandate_id': self.assistant_mandate2.id})
        self.assistant_mandate2.refresh_from_db()
        self.assertEqual(self.assistant_mandate2.state, assistant_mandate_state.VICE_RECTOR)

    def test_add_actions_to_mandates_list(self):
        self.client.force_login(self.reviewer1.person.user)
        response = self.client.get('/assistants/reviewer/')
        context = add_actions_to_mandates_list(response.context, self.reviewer1)
        for mandate in context['object_list']:
            if mandate.id == self.assistant_mandate.id:
                self.assertFalse(mandate.view)
                self.assertFalse(mandate.edit)
        self.client.force_login(self.reviewer2.person.user)
        response = self.client.get('/assistants/reviewer/')
        context = add_actions_to_mandates_list(response.context, self.reviewer2)
        for mandate in context['object_list']:
            if mandate.id == self.assistant_mandate2.id:
                self.assertTrue(mandate.view)
                self.assertTrue(mandate.edit)