#!/usr/bin/env python3
"""add_transcripts must stage the page body, never write directly to Canvas.

Companion regression to test_deploy_interactives_backup.py (#208):
add_transcripts.add_transcript_to_page used to call update_page directly
with only a pre-write backup as a rollback point, bypassing the Write
Safety Guard's stage -> preview -> push gate entirely. The fix routes the
write through staging_manager.stage() instead, so scripts/push_to_canvas.py
(backup -> push -> verify -> clear-staging) is the only way the change
reaches Canvas.
"""

import os
import sys
import unittest
from unittest import mock

HERE = os.path.dirname(os.path.abspath(__file__))
SCRIPTS = os.path.join(HERE, "..", "scripts")
sys.path.insert(0, SCRIPTS)

import add_transcripts as at  # noqa: E402
import canvas_api  # noqa: E402


class StageNotPushTest(unittest.TestCase):
    def _run(self, stage_result):
        config = {"course_id": "123"}
        original_body = (
            '<p>Intro</p><a href="/files/456">Video</a></a><h2>Next</h2>'
        )
        calls = []

        with mock.patch.object(
                at, "get_page",
                return_value={"body": original_body, "title": "M1 Lesson"}), \
             mock.patch.object(
                 at, "transcript_to_text", return_value="Hello world."), \
             mock.patch("os.path.exists", return_value=True), \
             mock.patch.object(
                 at.staging_manager, "stage",
                 side_effect=lambda *a, **k: (
                     calls.append(("stage", a, k)) or stage_result)), \
             mock.patch.object(canvas_api, "update_page") as upd:
            result = at.add_transcript_to_page(
                config, "m1-lesson", "/tmp/fake.vtt", "video", 456, "m1")
        return calls, upd, result

    def test_stages_instead_of_updating_page(self):
        calls, upd, result = self._run({"ok": True, "path": "/tmp/x"})
        kinds = [c[0] for c in calls]
        self.assertIn("stage", kinds)
        # The real canvas_api.update_page must never be called: staging +
        # push_to_canvas.py is the only authorized write path. Patching the
        # real function (not a stale import alias) keeps the guard sharp
        # against a future direct write (Write Safety Guard, #208).
        upd.assert_not_called()
        # staging_manager.stage(course_id, object_type, object_id, content, ...)
        stage_args = next(c[1] for c in calls if c[0] == "stage")
        stage_kwargs = next(c[2] for c in calls if c[0] == "stage")
        self.assertEqual(stage_args[0], "123")
        self.assertEqual(stage_args[1], "pages")
        self.assertEqual(stage_args[2], "m1-lesson")
        self.assertIn("Lecture Video Transcript", stage_args[3])
        self.assertEqual(stage_kwargs.get("title"), "M1 Lesson")
        self.assertTrue(result)

    def test_reports_failure_when_staging_fails(self):
        calls, upd, result = self._run({"ok": False, "error": "boom"})
        kinds = [c[0] for c in calls]
        self.assertIn("stage", kinds)
        upd.assert_not_called()
        self.assertFalse(result)


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