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.creators.test_course import create_test_course
from vbv_lernwelt.course.models import CourseSession
from vbv_lernwelt.feedback.factories import FeedbackResponseFactory
from vbv_lernwelt.feedback.models import FeedbackResponse
from vbv_lernwelt.learnpath.models import Circle
from vbv_lernwelt.notify.models import (
    Notification,
    NotificationCategory,
    NotificationTrigger,
)


class FeedbackBaseTestCase(APITestCase):
    def setUp(self) -> None:
        create_default_users()
        create_test_course(include_vv=False, with_sessions=True)
        self.course_session = CourseSession.objects.get(title="Test Bern 2022 a")
        self.trainer = User.objects.get(username="test-trainer1@example.com")
        self.student = User.objects.get(username="test-student1@example.com")
        self.circle_basis = Circle.objects.get(slug="test-lehrgang-lp-circle-fahrzeug")


class FeedbackNotificationTestCase(FeedbackBaseTestCase):
    def test_creating_submitted_feedback_triggers_notification(self):
        feedback = FeedbackResponse.objects.create(
            circle=self.circle_basis,
            course_session=self.course_session,
            feedback_user=self.student,
            submitted=True,
        )

        self.assertEqual(Notification.objects.count(), 1)
        notification = Notification.objects.first()
        self.assertEqual(notification.recipient, self.trainer)
        self.assertEqual(
            notification.verb,
            f"Feedback abgeschickt für Circle «{self.circle_basis.title}»",
        )
        self.assertEqual(
            notification.target_url,
            f"/course/{self.course_session.course.slug}/cockpit/feedback/{self.circle_basis.id}/",
        )
        self.assertEqual(
            notification.notification_category, NotificationCategory.INFORMATION
        )
        self.assertEqual(
            notification.notification_trigger, NotificationTrigger.NEW_FEEDBACK
        )
        self.assertEqual(notification.action_object, feedback)
        self.assertEqual(notification.course_session, self.course_session)

    def test_only_submitted_feedback_triggers_notification(self):
        FeedbackResponse.objects.create(
            circle=self.circle_basis,
            course_session=self.course_session,
            feedback_user=self.student,
        )

        self.assertEqual(Notification.objects.count(), 0)


class FeedbackRestApiTestCase(FeedbackBaseTestCase):
    def setUp(self) -> None:
        super().setUp()
        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"],
        }

        self.feedback_users = [
            # MEMBERS of the course session
            self.student,
            User.objects.get(username="test-student2@example.com"),
            User.objects.get(username="test-student3@example.com"),
            # EXPERT has submitted feedback for "testing purposes"
            #  -> should be filtered out!
            User.objects.get(username="test-trainer1@example.com"),
        ]

        for i in range(3):
            FeedbackResponseFactory(
                circle=self.circle_basis,
                course_session=self.course_session,
                data={
                    "satisfaction": self.feedback_data["satisfaction"][i],
                    "goal_attainment": self.feedback_data["goal_attainment"][i],
                    "proficiency": self.feedback_data["proficiency"][i],
                    "preparation_task_clarity": self.feedback_data[
                        "preparation_task_clarity"
                    ][i],
                    "instructor_competence": self.feedback_data[
                        "instructor_competence"
                    ][i],
                    "instructor_open_feedback": self.feedback_data[
                        "instructor_open_feedback"
                    ][i],
                    "would_recommend": self.feedback_data["would_recommend"][i],
                    "instructor_respect": self.feedback_data["instructor_respect"][i],
                    "course_positive_feedback": self.feedback_data[
                        "course_positive_feedback"
                    ][i],
                    "course_negative_feedback": self.feedback_data[
                        "course_negative_feedback"
                    ][i],
                    "feedback_type": "uk",
                },
                feedback_user=self.feedback_users[i],
                submitted=True,
            )

    def test_detail_trainer_can_fetch_feedback(self):
        self.client.force_login(self.trainer)
        response = self.client.get(
            f"/api/core/feedback/{self.course_session.id}/{self.circle_basis.id}/"
        )
        self.maxDiff = None

        expected = {
            "amount": 3,
            "questions": self.feedback_data,
            "feedbackType": "uk",
        }
        print(response.data)

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

    def test_summary_trainer_can_fetch_feedback(self):
        self.client.force_login(self.trainer)
        response = self.client.get(
            f"/api/core/feedback/{self.course_session.id}/summary/"
        )
        self.maxDiff = None

        self.assertEqual(response.status_code, 200)
        self.assertDictEqual(
            response.data[0], {"circle_id": self.circle_basis.id, "count": 3}
        )

    def test_detail_student_cannot_fetch_feedback(self):
        self.client.force_login(self.student)
        response = self.client.get(
            f"/api/core/feedback/{self.course_session.id}/{self.circle_basis.id}/"
        )

        self.assertEqual(response.status_code, 403)

    def test_summary_student_cannot_fetch_feedback(self):
        self.client.force_login(self.student)
        response = self.client.get(
            f"/api/core/feedback/{self.course_session.id}/summary/"
        )

        self.assertEqual(response.status_code, 403)
