"""Tests for staged_key auto-clear on create_* success / failure.

Item 2 of feat/mlo-overclaim-staging-clear:
    create_page / create_quiz / create_assignment / create_discussion
    should call staging_manager.clear_staged(course_id, <type>, staged_key)
    when from_staging=True AND staged_key is provided AND the Canvas API call
    succeeds. On failure, staging must NOT be cleared. When staged_key is
    absent (None), there must be no crash and no clear call.

Strategy: patch canvas_api._clear_staged_on_success because staging_manager
is imported lazily inside that helper (not at module level), so module-level
patching would raise AttributeError.
"""
import logging
import os
import sys
import unittest
from unittest.mock import MagicMock, call, patch

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

import canvas_api


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


def _ok_resp(status=201, body=None):
    resp = MagicMock()
    resp.status_code = status
    resp.json.return_value = body or {"id": 42, "url": "test-page", "title": "T"}
    return resp


def _fail_resp():
    resp = MagicMock()
    resp.status_code = 500
    resp.text = "server error"
    resp.reason = "Internal Server Error"
    return resp


class TestStagedKeyAutoClear(unittest.TestCase):
    """Tests patch canvas_api._clear_staged_on_success (the lazy-import helper)."""

    # ------------------------------------------------------------------
    # create_page
    # ------------------------------------------------------------------

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_page_clears_staging_on_success(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(201, {"id": 1, "url": "my-page"})

        result = canvas_api.create_page(
            _mock_config(), "My Page", "<p>body</p>",
            from_staging=True, staged_key="my-page",
        )

        self.assertIsNotNone(result)
        mock_clear.assert_called_once_with(_mock_config(), "pages", "my-page")

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_page_does_not_clear_on_failure(self, mock_clear, mock_req):
        mock_req.return_value = _fail_resp()

        result = canvas_api.create_page(
            _mock_config(), "My Page", "<p>body</p>",
            from_staging=True, staged_key="my-page",
        )

        self.assertIsNone(result)
        mock_clear.assert_not_called()

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_page_no_crash_when_staged_key_absent(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(201, {"id": 1, "url": "p"})

        result = canvas_api.create_page(
            _mock_config(), "Page", "<p/>",
            from_staging=True,  # staged_key defaults to None
        )

        self.assertIsNotNone(result)
        mock_clear.assert_not_called()

    # ------------------------------------------------------------------
    # create_quiz
    # ------------------------------------------------------------------

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_quiz_clears_staging_on_success(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(200, {"id": 7, "title": "Quiz A"})

        result = canvas_api.create_quiz(
            _mock_config(), "Quiz A",
            from_staging=True, staged_key="quiz-a",
        )

        self.assertIsNotNone(result)
        mock_clear.assert_called_once_with(_mock_config(), "quizzes", "quiz-a")

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_quiz_does_not_clear_on_failure(self, mock_clear, mock_req):
        mock_req.return_value = _fail_resp()

        result = canvas_api.create_quiz(
            _mock_config(), "Quiz A",
            from_staging=True, staged_key="quiz-a",
        )

        self.assertIsNone(result)
        mock_clear.assert_not_called()

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_quiz_no_crash_when_staged_key_absent(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(200, {"id": 7, "title": "Quiz A"})

        result = canvas_api.create_quiz(
            _mock_config(), "Quiz A", from_staging=True,
        )

        self.assertIsNotNone(result)
        mock_clear.assert_not_called()

    # ------------------------------------------------------------------
    # create_assignment
    # ------------------------------------------------------------------

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_assignment_clears_staging_on_success(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(201, {"id": 9, "name": "Asn"})

        result = canvas_api.create_assignment(
            _mock_config(), "Asn",
            from_staging=True, staged_key="asn-key",
        )

        self.assertIsNotNone(result)
        mock_clear.assert_called_once_with(_mock_config(), "assignments", "asn-key")

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_assignment_does_not_clear_on_failure(self, mock_clear, mock_req):
        mock_req.return_value = _fail_resp()

        result = canvas_api.create_assignment(
            _mock_config(), "Asn",
            from_staging=True, staged_key="asn-key",
        )

        self.assertIsNone(result)
        mock_clear.assert_not_called()

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_assignment_no_crash_when_staged_key_absent(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(201, {"id": 9, "name": "Asn"})

        result = canvas_api.create_assignment(
            _mock_config(), "Asn", from_staging=True,
        )

        self.assertIsNotNone(result)
        mock_clear.assert_not_called()

    # ------------------------------------------------------------------
    # create_discussion
    # ------------------------------------------------------------------

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_discussion_clears_staging_on_success(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(200, {"id": 5, "title": "Disc"})

        result = canvas_api.create_discussion(
            _mock_config(), "Disc",
            from_staging=True, staged_key="disc-key",
        )

        self.assertIsNotNone(result)
        mock_clear.assert_called_once_with(_mock_config(), "discussions", "disc-key")

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_discussion_does_not_clear_on_failure(self, mock_clear, mock_req):
        mock_req.return_value = _fail_resp()

        result = canvas_api.create_discussion(
            _mock_config(), "Disc",
            from_staging=True, staged_key="disc-key",
        )

        self.assertIsNone(result)
        mock_clear.assert_not_called()

    @patch("canvas_api._request_with_retry")
    @patch("canvas_api._clear_staged_on_success")
    def test_create_discussion_no_crash_when_staged_key_absent(self, mock_clear, mock_req):
        mock_req.return_value = _ok_resp(200, {"id": 5, "title": "Disc"})

        result = canvas_api.create_discussion(
            _mock_config(), "Disc", from_staging=True,
        )

        self.assertIsNotNone(result)
        mock_clear.assert_not_called()


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