from django.test import TestCase, Client
from django.urls import reverse
from django.contrib.auth.models import User
from generic.models import CidUserExam, CidUser
from physics.models import Exam, Question, UserAnswer
from atlas.models import Case
from atlas.forms import CaseForm

class ScoresStatsTests(TestCase):
    def setUp(self):
        self.admin = User.objects.create_superuser(
            username="admin",
            email="admin@example.com",
            password="adminpassword"
        )
        self.client = Client()
        self.client.force_login(self.admin)

    def test_physics_stats_with_pass_mark_and_exclusion(self):
        # Create Exam
        exam = Exam.objects.create(name="Physics Test Exam", exam_mode=True)
        exam.author.add(self.admin)

        # Create Questions (max score will be 10 points)
        q1 = Question.objects.create(
            stem="stem1",
            a="a", a_answer=True,
            b="b", b_answer=False,
            c="c", c_answer=True,
            d="d", d_answer=False,
            e="e", e_answer=True,
        )
        q1.exams.add(exam)
        q2 = Question.objects.create(
            stem="stem2",
            a="a", a_answer=True,
            b="b", b_answer=False,
            c="c", c_answer=True,
            d="d", d_answer=False,
            e="e", e_answer=True,
        )
        q2.exams.add(exam)

        # Create two candidates: cid=1 (score=5/10), cid=2 (score=3/10)
        UserAnswer.objects.create(
            question=q1, exam=exam, cid=1,
            a=True, b=False, c=True, d=False, e=True
        )
        UserAnswer.objects.create(
            question=q2, exam=exam, cid=1,
            a=False, b=True, c=False, d=True, e=False
        )

        UserAnswer.objects.create(
            question=q1, exam=exam, cid=2,
            a=True, b=True, c=True, d=True, e=False
        )

        # 1. Test stats calculations without custom pass mark (defaults to 50% = 5)
        url = reverse("physics:exam_scores_all", kwargs={"pk": exam.pk})
        response = self.client.get(f"{url}?stats_only=true")
        self.assertEqual(response.status_code, 200)
        context = response.context
        self.assertEqual(context["pass_mark_threshold"], 5.0)
        self.assertEqual(context["passed_candidates_count"], 1)
        self.assertEqual(context["pass_rate"], 50.0)

        # 2. Update pass mark to 3.0 via HTMX update_pass_mark url
        update_url = reverse("physics:update_pass_mark", kwargs={"pk": exam.pk})
        update_response = self.client.post(update_url, {"pass_mark": "3.0"}, HTTP_HX_REQUEST="true")
        self.assertEqual(update_response.status_code, 302)
        exam.refresh_from_db()
        self.assertEqual(exam.pass_mark, 3.0)

        # Fetch stats again and verify updated pass mark threshold and pass rate
        response = self.client.get(f"{url}?stats_only=true")
        context = response.context
        self.assertEqual(context["pass_mark_threshold"], 3.0)
        self.assertEqual(context["passed_candidates_count"], 2)
        self.assertEqual(context["pass_rate"], 100.0)

        # 3. Exclude cid=2 from stats
        exclude_url = reverse("physics:toggle_candidate_stats_exclusion", kwargs={"pk": exam.pk})
        exclude_response = self.client.post(f"{exclude_url}?candidate=c/2")
        self.assertEqual(exclude_response.status_code, 200)

        # Check database status
        cid_user = CidUser.objects.get(cid=2)
        cux = CidUserExam.objects.get(object_id=exam.pk, cid_user=cid_user)
        self.assertTrue(cux.exclude_from_stats)

        # Fetch stats again and verify cid=2 is excluded
        response = self.client.get(f"{url}?stats_only=true")
        context = response.context
        self.assertEqual(len(context["cids"]), 1)
        self.assertIn("c/1", context["cids"])
        self.assertNotIn("c/2", context["cids"])
        self.assertEqual(context["mean"], 5.0)
        self.assertEqual(context["passed_candidates_count"], 1)
        self.assertEqual(context["pass_rate"], 100.0)

    def test_case_form_save_commit_false_does_not_persist(self):
        form_data = {
            "title": "Unsaved Case Form Test",
            "description": "Unsaved description",
            "diagnostic_certainty": 3,
            "open_access": True,
        }
        form = CaseForm(data=form_data, user=self.admin)
        self.assertTrue(form.is_valid())
        case_inst = form.save(commit=False)
        self.assertIsNone(case_inst.pk)
        self.assertEqual(Case.objects.filter(title="Unsaved Case Form Test").count(), 0)

    def test_case_linked_series_info(self):
        # Create a chain of 3 cases: c1 -> c2 -> c3
        c1 = Case.objects.create(title="Case 1")
        c2 = Case.objects.create(title="Case 2", previous_case=c1)
        c3 = Case.objects.create(title="Case 3", previous_case=c2)

        # Verify positions and totals
        info1 = c1.get_series_info()
        self.assertTrue(info1["in_series"])
        self.assertEqual(info1["position"], 1)
        self.assertEqual(info1["total"], 3)

        info2 = c2.get_series_info()
        self.assertTrue(info2["in_series"])
        self.assertEqual(info2["position"], 2)
        self.assertEqual(info2["total"], 3)

        info3 = c3.get_series_info()
        self.assertTrue(info3["in_series"])
        self.assertEqual(info3["position"], 3)
        self.assertEqual(info3["total"], 3)

        c4 = Case.objects.create(title="Case 4")
        info4 = c4.get_series_info()
        self.assertFalse(info4["in_series"])
