"""Tests for post_write_verify.py — verify strictness and failure modes.

All Canvas API calls are mocked. Tests verify:
- verify_quiz returns ok:false on expected count/points mismatch
- verify_quiz returns ok:true when expectations match
- verify_page/assignment/discussion return ok:false on 404
"""

import os
import sys
import unittest
from unittest.mock import patch

sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts"))

import post_write_verify


def _mock_config():
    return {
        "token": "fake",
        "domain": "canvas.test.edu",
        "course_id": "99999",
        "base_url": "https://canvas.test.edu/api/v1",
        "course_url": "https://canvas.test.edu/api/v1/courses/99999",
        "headers": {"Authorization": "Bearer fake"},
    }


class TestVerifyQuizStrict(unittest.TestCase):
    """verify_quiz must hard-fail when expected values don't match."""

    @patch("post_write_verify.get_quiz_questions")
    @patch("post_write_verify.get_quiz")
    def test_matching_expectations_returns_ok(self, mock_get, mock_qs):
        mock_get.return_value = {
            "title": "Quiz 1", "published": False,
            "points_possible": 15, "question_count": 5,
            "allowed_attempts": 2, "time_limit": None,
        }
        mock_qs.return_value = [{}] * 5
        result = post_write_verify.verify_quiz(
            _mock_config(), "100",
            expected_points=15, expected_questions=5)
        self.assertTrue(result["ok"])
        self.assertEqual(result["question_count"], 5)
        self.assertEqual(result["points_possible"], 15)

    @patch("post_write_verify.get_quiz_questions")
    @patch("post_write_verify.get_quiz")
    def test_question_count_mismatch_returns_failure(self, mock_get, mock_qs):
        mock_get.return_value = {
            "title": "Quiz 1", "published": False,
            "points_possible": 9, "question_count": 3,
            "allowed_attempts": 2, "time_limit": None,
        }
        mock_qs.return_value = [{}] * 3
        result = post_write_verify.verify_quiz(
            _mock_config(), "100",
            expected_points=9, expected_questions=5)
        self.assertFalse(result["ok"])
        self.assertIn("Question count mismatch", result["error"])

    @patch("post_write_verify.get_quiz_questions")
    @patch("post_write_verify.get_quiz")
    def test_points_mismatch_returns_failure(self, mock_get, mock_qs):
        mock_get.return_value = {
            "title": "Quiz 1", "published": False,
            "points_possible": 0, "question_count": 5,
            "allowed_attempts": 2, "time_limit": None,
        }
        mock_qs.return_value = [{}] * 5
        result = post_write_verify.verify_quiz(
            _mock_config(), "100",
            expected_points=15, expected_questions=5)
        self.assertFalse(result["ok"])
        self.assertIn("Points mismatch", result["error"])

    @patch("post_write_verify.get_quiz_questions")
    @patch("post_write_verify.get_quiz")
    def test_both_mismatch_returns_combined_error(self, mock_get, mock_qs):
        mock_get.return_value = {
            "title": "Quiz 1", "published": False,
            "points_possible": 0, "question_count": 0,
            "allowed_attempts": 2, "time_limit": None,
        }
        mock_qs.return_value = []
        result = post_write_verify.verify_quiz(
            _mock_config(), "100",
            expected_points=15, expected_questions=5)
        self.assertFalse(result["ok"])
        self.assertIn("Points mismatch", result["error"])
        self.assertIn("Question count mismatch", result["error"])

    @patch("post_write_verify.get_quiz_questions")
    @patch("post_write_verify.get_quiz")
    def test_no_expectations_returns_ok_with_warnings(self, mock_get, mock_qs):
        mock_get.return_value = {
            "title": "Quiz 1", "published": False,
            "points_possible": 0, "question_count": 0,
            "allowed_attempts": 2, "time_limit": None,
        }
        mock_qs.return_value = []
        result = post_write_verify.verify_quiz(_mock_config(), "100")
        self.assertTrue(result["ok"])
        self.assertTrue(len(result["warnings"]) > 0)

    @patch("post_write_verify.get_quiz", return_value=None)
    def test_quiz_not_found_returns_failure(self, mock_get):
        result = post_write_verify.verify_quiz(_mock_config(), "999")
        self.assertFalse(result["ok"])
        self.assertIn("not found", result["error"])

    @patch("post_write_verify.get_quiz_questions")
    @patch("post_write_verify.get_quiz")
    def test_zero_expected_questions_enforced(self, mock_get, mock_qs):
        """Explicit expected_questions=0 must fail if Canvas has questions."""
        mock_get.return_value = {
            "title": "Quiz 1", "published": False,
            "points_possible": 15, "question_count": 3,
            "allowed_attempts": 2, "time_limit": None,
        }
        mock_qs.return_value = [{}] * 3
        result = post_write_verify.verify_quiz(
            _mock_config(), "100",
            expected_points=0, expected_questions=0)
        self.assertFalse(result["ok"])


class TestVerifyPage404(unittest.TestCase):

    @patch("post_write_verify.get_page", return_value=None)
    def test_page_not_found(self, mock_get):
        result = post_write_verify.verify_page(_mock_config(), "nonexistent")
        self.assertFalse(result["ok"])
        self.assertIn("not found", result["error"])


class TestVerifyAssignment404(unittest.TestCase):

    @patch("post_write_verify.get_assignment", return_value=None)
    def test_assignment_not_found(self, mock_get):
        result = post_write_verify.verify_assignment(_mock_config(), "999")
        self.assertFalse(result["ok"])
        self.assertIn("not found", result["error"])


class TestVerifyDiscussion404(unittest.TestCase):

    @patch("post_write_verify.get_discussion", return_value=None)
    def test_discussion_not_found(self, mock_get):
        result = post_write_verify.verify_discussion(_mock_config(), "999")
        self.assertFalse(result["ok"])
        self.assertIn("not found", result["error"])


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