import tempfile
import unittest
from pathlib import Path

import score_api


def valid_payload():
    selected = []
    for chapter in score_api.CATALOG["chapters"]:
        chapter_ids = [
            question_id
            for question_id, question in score_api.CATALOG["questions"].items()
            if question["chapterId"] == chapter["id"]
        ]
        selected.extend(chapter_ids[:3])

    return {
        "alias": "Tux_42",
        "runId": "run-test-123456",
        "mode": "course",
        "runQuestionIds": selected,
        "outcomes": [[question_id, 0, False] for question_id in selected],
        "durationSeconds": 120,
    }


class ScoreApiTests(unittest.TestCase):
    def test_validates_and_calculates_normalized_score(self):
        entry = score_api.validate_submission(valid_payload())
        self.assertEqual(entry["alias"], "Tux_42")
        self.assertEqual(entry["question_count"], 30)
        self.assertEqual(entry["score"], 1000)

    def test_rejects_links_and_tampered_chapter_distribution(self):
        payload = valid_payload()
        payload["alias"] = "https://spam.example"
        with self.assertRaises(ValueError):
            score_api.validate_submission(payload)

        payload = valid_payload()
        payload["runQuestionIds"][0] = payload["runQuestionIds"][3]
        with self.assertRaises(ValueError):
            score_api.validate_submission(payload)

    def test_recalculates_results_instead_of_trusting_the_browser(self):
        payload = valid_payload()
        payload["outcomes"][0][1] = 2
        payload["outcomes"][1][2] = True
        entry = score_api.validate_submission(payload)

        self.assertEqual(entry["mistakes"], 2)
        self.assertEqual(entry["hints"], 1)
        self.assertEqual(entry["clean"], 28)
        self.assertEqual(entry["integrity"], 96)
        self.assertLess(entry["score"], 1000)

    def test_sqlite_insert_is_idempotent_and_ranked(self):
        with tempfile.TemporaryDirectory() as directory:
            database = Path(directory) / "scores.db"
            score_api.initialize_database(database)
            entry = score_api.validate_submission(valid_payload())

            first, duplicate = score_api.insert_score(entry, database)
            second, second_duplicate = score_api.insert_score(entry, database)

            self.assertFalse(duplicate)
            self.assertTrue(second_duplicate)
            self.assertEqual(first, second)
            self.assertEqual(score_api.list_scores(database), [first])


if __name__ == "__main__":
    unittest.main()
