"""
Tests for _normalize_quiz_answers_for_write — numerical/range key mapping.

Covers the bug where Canvas read-format keys (exact, margin, …) were not
mapped to Canvas write-format keys (answer_exact, answer_error_margin, …),
causing pushed numerical answers to silently reset to 0.0.
"""

import sys
import os

# Ensure scripts/ is importable
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))

from canvas_api import _normalize_quiz_answers_for_write


class TestNumericalAnswerKeyMapping:
    """AC-1 & AC-2: exact/margin read keys map to write keys; no clobber."""

    def test_exact_answer_mapped(self):
        answers = [
            {
                "numerical_answer_type": "exact_answer",
                "exact": 26.9,
                "margin": 0,
                "answer_weight": 100,
            }
        ]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_exact"] == 26.9

    def test_margin_mapped_to_answer_error_margin(self):
        answers = [
            {
                "numerical_answer_type": "exact_answer",
                "exact": 26.9,
                "margin": 0,
                "answer_weight": 100,
            }
        ]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_error_margin"] == 0

    def test_existing_write_key_not_clobbered(self):
        """AC-2: if answer_exact already set, exact must not overwrite it."""
        answers = [
            {
                "numerical_answer_type": "exact_answer",
                "exact": 5.0,
                "answer_exact": 99.9,  # caller already supplied write key
                "answer_weight": 100,
            }
        ]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_exact"] == 99.9

    def test_range_answer_keys_mapped(self):
        answers = [
            {
                "numerical_answer_type": "range_answer",
                "start": 10.0,
                "end": 20.0,
                "answer_weight": 100,
            }
        ]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_range_start"] == 10.0
        assert result[0]["answer_range_end"] == 20.0

    def test_approximate_and_precision_mapped(self):
        answers = [
            {
                "numerical_answer_type": "precision_answer",
                "approximate": 3.14,
                "precision": 2,
                "answer_weight": 100,
            }
        ]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_approximate"] == 3.14
        assert result[0]["answer_precision"] == 2

    def test_original_read_keys_preserved(self):
        """Read keys should remain alongside the new write keys."""
        answers = [{"exact": 26.9, "margin": 0}]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["exact"] == 26.9
        assert result[0]["margin"] == 0


class TestNonNumericalAnswersPassThrough:
    """AC-3: multiple-choice, multiple-dropdowns, etc. pass through unchanged."""

    def test_multiple_choice_unchanged(self):
        answers = [
            {"answer_text": "Paris", "answer_weight": 100},
            {"answer_text": "London", "answer_weight": 0},
        ]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0] == {"answer_text": "Paris", "answer_weight": 100}
        assert result[1] == {"answer_text": "London", "answer_weight": 0}

    def test_blank_id_answer_unchanged(self):
        """Multiple-dropdowns answers have blank_id — must not be mutated."""
        answers = [{"blank_id": "color", "answer_text": "blue", "answer_weight": 100}]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["blank_id"] == "color"
        assert "answer_exact" not in result[0]

    def test_non_dict_items_pass_through(self):
        """Non-dict items in the list must be returned as-is."""
        answers = ["unexpected_string", 42, None]
        result = _normalize_quiz_answers_for_write(answers)
        assert result == ["unexpected_string", 42, None]

    def test_non_list_input_returned_as_is(self):
        assert _normalize_quiz_answers_for_write(None) is None
        assert _normalize_quiz_answers_for_write("bad") == "bad"


class TestFeedbackKeyNormalization:
    """AC-4: existing feedback key normalization still works."""

    def test_answer_comment_normalized(self):
        answers = [{"answer_comment": "Great job!", "answer_weight": 100}]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_comments"] == "Great job!"

    def test_feedback_key_normalized(self):
        answers = [{"feedback": "Try again.", "answer_weight": 0}]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_comments"] == "Try again."

    def test_comments_html_normalized(self):
        answers = [{"comments_html": "<p>Well done</p>", "answer_weight": 100}]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_comment_html"] == "<p>Well done</p>"

    def test_feedback_and_numerical_together(self):
        """Feedback normalization and numerical mapping coexist on same answer."""
        answers = [
            {
                "numerical_answer_type": "exact_answer",
                "exact": 42.0,
                "margin": 1.0,
                "answer_weight": 100,
                "feedback": "Correct!",
            }
        ]
        result = _normalize_quiz_answers_for_write(answers)
        assert result[0]["answer_exact"] == 42.0
        assert result[0]["answer_error_margin"] == 1.0
        assert result[0]["answer_comments"] == "Correct!"
