from graphene_django.utils import GraphQLTestCase

from vbv_lernwelt.assignment.models import AssignmentType
from vbv_lernwelt.course.creators.test_utils import (
    add_course_session_group_supervisor,
    add_course_session_user,
    create_assignment,
    create_assignment_completion,
    create_circle,
    create_course,
    create_course_session,
    create_course_session_group,
    create_performance_criteria_page,
    create_user,
)
from vbv_lernwelt.course.models import CourseSessionUser
from vbv_lernwelt.course.services import mark_course_completion


class DashboardTestCase(GraphQLTestCase):
    GRAPHQL_URL = "/server/graphql/"

    def test_course_progress(self):
        # GIVEN
        course, course_page = create_course("Test Course")

        cs_1 = create_course_session(
            course=course, title="Test Course Session 1", generation=""
        )
        cs_2 = create_course_session(
            course=course, title="Test Course Session 2", generation="2020"
        )
        cs_3 = create_course_session(
            course=course, title="Test Course Session 3", generation="1984"
        )

        member = create_user("sepp")

        add_course_session_user(
            course_session=cs_1, user=member, role=CourseSessionUser.Role.MEMBER
        )
        add_course_session_user(
            course_session=cs_2, user=member, role=CourseSessionUser.Role.MEMBER
        )
        add_course_session_user(
            course_session=cs_3, user=member, role=CourseSessionUser.Role.MEMBER
        )

        # setup assignments
        create_assignment_completion(
            user=member,
            assignment=create_assignment(
                course=course, assignment_type=AssignmentType.CASEWORK
            ),
            course_session=cs_1,
            has_passed=True,
            achieved_points=10,
            max_points=10,
        )

        create_assignment_completion(
            user=member,
            assignment=create_assignment(
                course=course, assignment_type=AssignmentType.CASEWORK
            ),
            course_session=cs_2,
            has_passed=False,
            achieved_points=10,
            max_points=40,
        )

        # setup competence
        circle, _ = create_circle(
            title="How to circle like a pro!", course_page=course_page
        )

        mark_course_completion(
            page=create_performance_criteria_page(
                course=course, course_page=course_page, circle=circle
            ),
            user=member,
            course_session=cs_1,
            completion_status="SUCCESS",
        )

        mark_course_completion(
            page=create_performance_criteria_page(
                course=course, course_page=course_page, circle=circle
            ),
            user=member,
            course_session=cs_2,
            completion_status="FAIL",
        )

        self.client.force_login(member)

        query = f"""query($course_id: ID!) {{
            course_progress(course_id: $course_id) {{
                course_id
                session_to_continue_id
                competence {{
                    total_count
                    success_count
                    fail_count
                }}
                assignment {{
                    total_count
                    points_max_count
                    points_achieved_count
                }}
            }}
        }}
        """

        variables = {"course_id": str(course.id)}

        # WHEN
        response = self.query(query, variables=variables)

        # THEN
        self.assertResponseNoErrors(response)

        course_progress = response.json()["data"]["course_progress"]
        self.assertEqual(course_progress["course_id"], str(course.id))
        self.assertEqual(course_progress["session_to_continue_id"], str(cs_2.id))

        competence = course_progress["competence"]
        self.assertEqual(competence["total_count"], 2)
        self.assertEqual(competence["success_count"], 1)
        self.assertEqual(competence["fail_count"], 1)

        assignment = course_progress["assignment"]
        self.assertEqual(assignment["total_count"], 2)
        self.assertEqual(assignment["points_max_count"], 50)
        self.assertEqual(assignment["points_achieved_count"], 20)

    def test_dashboard_config(self):
        # GIVEN
        course_1, _ = create_course("Test Course 1")
        course_2, _ = create_course("Test Course 2")
        course_3, _ = create_course("Test Course 3")

        cs_1 = create_course_session(course=course_1, title="Test Course 1 Session")
        cs_2 = create_course_session(course=course_2, title="Test Course 2 Session")

        cs_3_a = create_course_session(course=course_3, title="CS 3 A (as member)")
        cs_3_b = create_course_session(course=course_3, title="CS 3 B (as expert)")

        supervisor = create_user("supervisor")

        # CS 1
        add_course_session_user(
            course_session=cs_1, user=supervisor, role=CourseSessionUser.Role.MEMBER
        )

        # CS 2
        add_course_session_group_supervisor(
            group=create_course_session_group(course_session=cs_2), user=supervisor
        )

        # CS 3 A
        add_course_session_user(
            course_session=cs_3_a, user=supervisor, role=CourseSessionUser.Role.MEMBER
        )

        # CS 3 B
        add_course_session_user(
            course_session=cs_3_b, user=supervisor, role=CourseSessionUser.Role.EXPERT
        )

        self.client.force_login(supervisor)

        # WHEN
        query = """query {
                        dashboard_config {
                            id
                            name
                            slug
                            dashboard_type
                        }
                    }
                """

        response = self.query(query)

        # THEN
        self.assertResponseNoErrors(response)

        dashboard_config = response.json()["data"]["dashboard_config"]
        self.assertEqual(len(dashboard_config), 3)

        course_1_config = find_dashboard_config_by_course_id(
            dashboard_config, course_1.id
        )
        self.assertIsNotNone(course_1_config)
        self.assertEqual(course_1_config["name"], course_1.title)
        self.assertEqual(course_1_config["slug"], course_1.slug)
        self.assertEqual(course_1_config["dashboard_type"], "PROGRESS_DASHBOARD")

        course_2_config = find_dashboard_config_by_course_id(
            dashboard_config, course_2.id
        )
        self.assertIsNotNone(course_2_config)
        self.assertEqual(course_2_config["name"], course_2.title)
        self.assertEqual(course_2_config["slug"], course_2.slug)
        self.assertEqual(course_2_config["dashboard_type"], "STATISTICS_DASHBOARD")

        course_3_config = find_dashboard_config_by_course_id(
            dashboard_config, course_3.id
        )
        self.assertIsNotNone(course_3_config)
        self.assertEqual(course_3_config["name"], course_3.title)
        self.assertEqual(course_3_config["slug"], course_3.slug)
        self.assertEqual(course_3_config["dashboard_type"], "SIMPLE_DASHBOARD")

    def test_course_statistics_deny_not_allowed_user(self):
        # GIVEN
        disallowed_user = create_user("1337_hacker_schorsch")
        course, _ = create_course("Test Course")
        create_course_session(course=course, title="Test Course Session")

        self.client.force_login(disallowed_user)

        query = f"""query($course_id: ID!) {{
            course_statistics(course_id: $course_id) {{
                course_id
            }}
        }}
        """
        variables = {"course_id": str(course.id)}

        # WHEN
        response = self.query(query, variables=variables)

        # THEN
        self.assertResponseNoErrors(response)

        course_statistics = response.json()["data"]["course_statistics"]
        self.assertEqual(course_statistics, None)

    def test_course_statistics_data(self):
        # GIVEN
        supervisor = create_user("supervisor")
        course_1, _ = create_course("Test Course 1")
        course_2, _ = create_course("Test Course 2")

        cs_1 = create_course_session(course=course_1, title="Test Course 1 Session")
        cs_2 = create_course_session(course=course_2, title="Test Course 2 Session")

        cs_group_1 = create_course_session_group(course_session=cs_1)
        add_course_session_group_supervisor(group=cs_group_1, user=supervisor)

        cs_group_2 = create_course_session_group(course_session=cs_2)
        add_course_session_group_supervisor(group=cs_group_2, user=supervisor)

        self.client.force_login(supervisor)

        query = f"""query($course_id: ID!) {{
            course_statistics(course_id: $course_id) {{
                course_id
                course_title
                course_slug
            }}
        }}
        """
        variables = {"course_id": str(course_2.id)}

        # WHEN
        response = self.query(query, variables=variables)

        # THEN
        self.assertResponseNoErrors(response)

        course_statistics = response.json()["data"]["course_statistics"]

        self.assertEqual(course_statistics["course_id"], str(course_2.id))
        self.assertEqual(course_statistics["course_title"], course_2.title)
        self.assertEqual(course_statistics["course_slug"], course_2.slug)


def find_dashboard_config_by_course_id(dashboard_configs, course_id):
    return next(
        (config for config in dashboard_configs if config["id"] == str(course_id)), None
    )
