from rest_framework.test import APITestCase

from vbv_lernwelt.core.create_default_users import create_default_users
from vbv_lernwelt.core.models import User
from vbv_lernwelt.course.consts import COURSE_TEST_ID
from vbv_lernwelt.course.creators.test_course import create_test_course
from vbv_lernwelt.course.models import CourseSession, CourseSessionUser
from vbv_lernwelt.feedback.factories import FeedbackFactory
from vbv_lernwelt.learnpath.models import Circle
from vbv_lernwelt.notify.models import Notification


class FeedbackApiBaseTestCase(APITestCase):
    def setUp(self) -> None:
        create_default_users()
        create_test_course()

        self.user = User.objects.get(username="student")
        self.expert = User.objects.get(
            username="patrizia.huggel@eiger-versicherungen.ch"
        )

        self.course_session = CourseSession.objects.create(
            course_id=COURSE_TEST_ID,
            title="Test Lehrgang Session",
        )

        csu = CourseSessionUser.objects.create(
            course_session=self.course_session,
            user=User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch"),
            role=CourseSessionUser.Role.EXPERT,
        )
        csu.expert.add(Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug"))

        _csu = CourseSessionUser.objects.create(
            course_session=self.course_session,
            user=self.user,
            role=CourseSessionUser.Role.MEMBER,
        )

        self.test_data = {
            "file_name": "test.pdf",
            "file_type": "application/pdf",
            "name": "Test",
            "course_session": self.course_session.id,
        }

        self.client.login(
            username="patrizia.huggel@eiger-versicherungen.ch", password="myvbv1234"
        )


class FeedbackSummaryApiTestCase(FeedbackApiBaseTestCase):
    def test_triggers_notification(self):
        expert = User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch")
        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=expert,
            role=CourseSessionUser.Role.EXPERT,
        )
        basis_circle = Circle.objects.get(slug="test-lehrgang-lp-circle-reisen")
        csu.expert.add(basis_circle)

        FeedbackFactory(circle=basis_circle, course_session=csu.course_session).save()

        notifications = Notification.objects.all()
        self.assertEqual(len(notifications), 1)
        self.assertEqual(notifications[0].recipient, expert)
        self.assertEqual(
            notifications[0].verb, f"New feedback for circle {basis_circle.title}"
        )
        self.assertEqual(
            notifications[0].target_url,
            f"/course/{self.course_session.course.slug}/cockpit/feedback/{basis_circle.id}/",
        )

    def test_triggers_notification_only_on_create(self):
        expert = User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch")
        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=expert,
            role=CourseSessionUser.Role.EXPERT,
        )
        basis_circle = Circle.objects.get(slug="test-lehrgang-lp-circle-reisen")
        csu.expert.add(basis_circle)

        feedback = FeedbackFactory(
            circle=basis_circle, course_session=csu.course_session
        )
        feedback.save()

        # Check that the initial notification was created and then deleted
        self.assertEqual(len(Notification.objects.all()), 1)
        Notification.objects.all().delete()
        self.assertEqual(len(Notification.objects.all()), 0)

        # Check that an update of the feedback does not trigger a notification
        feedback.name = "Test2"
        feedback.save()
        self.assertEqual(len(Notification.objects.all()), 0)

    def test_can_get_feedback_summary_for_circles(self):
        number_reisen_feedback = 5
        number_fahrzeug_feedback = 10

        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch"),
            role=CourseSessionUser.Role.EXPERT,
        )
        fahrzeug_circle = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug")
        reisen_circle = Circle.objects.get(slug="test-lehrgang-lp-circle-reisen")
        csu.expert.add(reisen_circle)

        for i in range(number_reisen_feedback):
            FeedbackFactory(
                circle=reisen_circle, course_session=csu.course_session
            ).save()

        for i in range(number_fahrzeug_feedback):
            FeedbackFactory(
                circle=fahrzeug_circle, course_session=csu.course_session
            ).save()

        response = self.client.get(
            f"/api/core/feedback/{csu.course_session.course.id}/summary/"
        )

        self.assertEqual(response.status_code, 200)
        expected = [
            {"circle_id": fahrzeug_circle.id, "count": number_fahrzeug_feedback},
            {"circle_id": reisen_circle.id, "count": number_reisen_feedback},
        ]
        self.assertEqual(response.data, expected)

    def test_can_only_see_feedback_from_own_circle(self):
        number_basis_feedback = 5
        number_analyse_feedback = 10

        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch"),
            role=CourseSessionUser.Role.EXPERT,
        )
        fahrzeug_circle = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug")
        reisen_circle = Circle.objects.get(slug="test-lehrgang-lp-circle-reisen")

        for i in range(number_basis_feedback):
            FeedbackFactory(
                circle=reisen_circle, course_session=csu.course_session
            ).save()

        for i in range(number_analyse_feedback):
            FeedbackFactory(
                circle=fahrzeug_circle, course_session=csu.course_session
            ).save()

        response = self.client.get(
            f"/api/core/feedback/{csu.course_session.course.id}/summary/"
        )

        self.assertEqual(response.status_code, 200)
        expected = [
            {"circle_id": fahrzeug_circle.id, "count": number_analyse_feedback},
        ]
        self.assertEqual(response.data, expected)

    def test_student_does_not_see_feedback(self):
        self.client.login(username="student", password="test")
        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=self.user,
        )
        fahrzeug_circle = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug")
        FeedbackFactory(
            circle=fahrzeug_circle, course_session=csu.course_session
        ).save()

        response = self.client.get(
            f"/api/core/feedback/{csu.course_session.course.id}/summary/"
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, [])


class FeedbackDetailApiTestCase(FeedbackApiBaseTestCase):
    def test_can_receive_feedback(self):
        feedback_data = {
            "satisfaction": [1, 4, 2],
            "goal_attainment": [2, 4, 3],
            "proficiency": [20, 60, 80],
            "preparation_task_clarity": [True, False, True],
            "instructor_competence": [1, 2, 3],
            "instructor_respect": [40, 80, 100],
            "instructor_open_feedback": ["super", "ok", "naja"],
            "would_recommend": [False, True, False],
            "course_positive_feedback": ["Bla", "Katze", "Hund"],
            "course_negative_feedback": ["Maus", "Hase", "Fuchs"],
        }
        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch"),
            role=CourseSessionUser.Role.EXPERT,
        )
        circle = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug")

        for i in range(3):
            FeedbackFactory(
                circle=circle,
                course_session=csu.course_session,
                data={
                    "satisfaction": feedback_data["satisfaction"][i],
                    "goal_attainment": feedback_data["goal_attainment"][i],
                    "proficiency": feedback_data["proficiency"][i],
                    "preparation_task_clarity": feedback_data[
                        "preparation_task_clarity"
                    ][i],
                    "instructor_competence": feedback_data["instructor_competence"][i],
                    "instructor_open_feedback": feedback_data[
                        "instructor_open_feedback"
                    ][i],
                    "would_recommend": feedback_data["would_recommend"][i],
                    "instructor_respect": feedback_data["instructor_respect"][i],
                    "course_positive_feedback": feedback_data[
                        "course_positive_feedback"
                    ][i],
                    "course_negative_feedback": feedback_data[
                        "course_negative_feedback"
                    ][i],
                },
            ).save()

        response = self.client.get(
            f"/api/core/feedback/{csu.course_session.course.id}/{circle.id}/"
        )
        self.maxDiff = None

        expected = {
            "amount": 3,
            "questions": feedback_data,
        }

        self.assertEqual(response.status_code, 200)
        self.assertDictEqual(response.data, expected)

    def test_cannot_receive_feedback_from_other_circle(self):
        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=User.objects.get(username="patrizia.huggel@eiger-versicherungen.ch"),
            role=CourseSessionUser.Role.EXPERT,
        )

        circle = Circle.objects.get(slug="test-lehrgang-lp-circle-reisen")
        FeedbackFactory(circle=circle, course_session=csu.course_session).save()

        response = self.client.get(
            f"/api/core/feedback/{csu.course_session.course.id}/{circle.id}/"
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, {"amount": 0, "questions": {}})

    def test_student_cannot_receive_feedback(self):
        self.client.login(username="student", password="test")
        csu = CourseSessionUser.objects.get(
            course_session=self.course_session,
            user=self.user,
        )
        circle = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug")
        FeedbackFactory(circle=circle, course_session=csu.course_session).save()

        response = self.client.get(
            f"/api/core/feedback/{csu.course_session.course.id}/{circle.id}/"
        )

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, {"amount": 0, "questions": {}})
