"""Tests for template_manager.py — verify save/list/get/delete surface.

Tests verify:
- save creates valid JSON with expected fields
- list returns summaries without structure
- get returns full structure
- delete removes the file
- no load mode exists (matches narrowed docs)
"""

import json
import os
import shutil
import sys
import unittest
from unittest.mock import patch, MagicMock

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

import template_manager
import canvas_api

PLUGIN_ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
TEMPLATES_DIR = os.path.join(PLUGIN_ROOT, "templates", "saved")


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"},
    }


# Fake course tree for save operations
FAKE_TREE = [
    {
        "id": 1, "name": "Module 1: Intro", "position": 1,
        "published": True, "items_count": 3,
        "items": [
            {"id": 10, "title": "Overview", "type": "Page",
             "indent": 0, "published": True, "page_url": "m1-overview",
             "content_id": None, "html_url": "", "external_url": ""},
            {"id": 11, "title": "Knowledge Check", "type": "Quiz",
             "indent": 0, "published": True, "page_url": "",
             "content_id": 500, "html_url": "", "external_url": ""},
            {"id": 12, "title": "Discussion", "type": "Discussion",
             "indent": 0, "published": False, "page_url": "",
             "content_id": 600, "html_url": "", "external_url": ""},
        ],
    },
]


class TestTemplateSave(unittest.TestCase):

    def setUp(self):
        self._saved_ids = []

    def tearDown(self):
        for tid in self._saved_ids:
            path = os.path.join(TEMPLATES_DIR, f"{tid}.json")
            if os.path.exists(path):
                os.remove(path)

    @patch("template_manager.canvas_api._request_with_retry")
    @patch("template_manager.course_navigator.fetch_course_tree",
           return_value=FAKE_TREE)
    def test_save_creates_valid_json(self, mock_tree, mock_api):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {"name": "Test Course"}
        mock_api.return_value = mock_resp

        template = template_manager.save_template(
            _mock_config(), "Test Template", "A test")
        self._saved_ids.append(template["id"])

        self.assertIn("id", template)
        self.assertTrue(template["id"].startswith("tmpl-"))
        self.assertEqual(template["name"], "Test Template")
        self.assertEqual(template["description"], "A test")
        self.assertEqual(template["module_count"], 1)
        self.assertEqual(template["item_count"], 3)
        self.assertEqual(template["source_course_id"], "99999")
        self.assertIn("created_at", template)
        self.assertIn("structure", template)

        # Verify file exists on disk
        path = os.path.join(TEMPLATES_DIR, f"{template['id']}.json")
        self.assertTrue(os.path.exists(path))

        # Verify structure content
        self.assertEqual(len(template["structure"]), 1)
        self.assertEqual(template["structure"][0]["name"], "Module 1: Intro")
        self.assertEqual(len(template["structure"][0]["items"]), 3)

    @patch("template_manager.canvas_api._request_with_retry")
    @patch("template_manager.course_navigator.fetch_course_tree",
           return_value=FAKE_TREE)
    def test_save_captures_item_types(self, mock_tree, mock_api):
        mock_resp = MagicMock()
        mock_resp.status_code = 200
        mock_resp.json.return_value = {"name": "Test Course"}
        mock_api.return_value = mock_resp

        template = template_manager.save_template(
            _mock_config(), "Type Test", "")
        self._saved_ids.append(template["id"])

        items = template["structure"][0]["items"]
        types = [i["item_type"] for i in items]
        self.assertEqual(types, ["Page", "Quiz", "Discussion"])


class TestTemplateList(unittest.TestCase):

    def setUp(self):
        os.makedirs(TEMPLATES_DIR, exist_ok=True)
        self._test_id = "tmpl-testlist12"
        test_template = {
            "id": self._test_id,
            "name": "List Test",
            "description": "For listing",
            "source_course_name": "Test Course",
            "module_count": 2,
            "item_count": 10,
            "created_at": "2026-01-01T00:00:00+00:00",
            "structure": [{"name": "Mod 1", "items": []}],
        }
        with open(os.path.join(TEMPLATES_DIR, f"{self._test_id}.json"),
                  "w") as f:
            json.dump(test_template, f)

    def tearDown(self):
        path = os.path.join(TEMPLATES_DIR, f"{self._test_id}.json")
        if os.path.exists(path):
            os.remove(path)

    def test_list_returns_summaries(self):
        templates = template_manager.list_templates()
        found = [t for t in templates if t["id"] == self._test_id]
        self.assertEqual(len(found), 1)
        t = found[0]
        self.assertEqual(t["name"], "List Test")
        self.assertEqual(t["module_count"], 2)
        # List should NOT include structure
        self.assertNotIn("structure", t)


class TestTemplateGet(unittest.TestCase):

    def setUp(self):
        os.makedirs(TEMPLATES_DIR, exist_ok=True)
        self._test_id = "tmpl-testget123"
        test_template = {
            "id": self._test_id,
            "name": "Get Test",
            "description": "For getting",
            "source_course_name": "Test Course",
            "module_count": 1,
            "item_count": 5,
            "created_at": "2026-01-01T00:00:00+00:00",
            "structure": [{"name": "Mod 1", "items": [{"title": "Page 1"}]}],
        }
        with open(os.path.join(TEMPLATES_DIR, f"{self._test_id}.json"),
                  "w") as f:
            json.dump(test_template, f)

    def tearDown(self):
        path = os.path.join(TEMPLATES_DIR, f"{self._test_id}.json")
        if os.path.exists(path):
            os.remove(path)

    def test_get_returns_full_structure(self):
        template = template_manager.get_template(self._test_id)
        self.assertIsNotNone(template)
        self.assertEqual(template["name"], "Get Test")
        self.assertIn("structure", template)
        self.assertEqual(len(template["structure"]), 1)

    def test_get_nonexistent_returns_none(self):
        template = template_manager.get_template("tmpl-doesnotexist")
        self.assertIsNone(template)


class TestTemplateDelete(unittest.TestCase):

    def setUp(self):
        os.makedirs(TEMPLATES_DIR, exist_ok=True)
        self._test_id = "tmpl-testdel123"
        test_template = {"id": self._test_id, "name": "Delete Test"}
        with open(os.path.join(TEMPLATES_DIR, f"{self._test_id}.json"),
                  "w") as f:
            json.dump(test_template, f)

    def test_delete_removes_file(self):
        result = template_manager.delete_template(self._test_id)
        self.assertTrue(result)
        path = os.path.join(TEMPLATES_DIR, f"{self._test_id}.json")
        self.assertFalse(os.path.exists(path))

    def test_delete_nonexistent_returns_false(self):
        result = template_manager.delete_template("tmpl-doesnotexist")
        self.assertFalse(result)


class TestNoLoadMode(unittest.TestCase):
    """Verify load mode does not exist — matches narrowed docs."""

    def test_no_load_function(self):
        self.assertFalse(hasattr(template_manager, "load_template"))

    def test_no_load_in_cli(self):
        """The CLI argparse should not accept --load."""
        import inspect
        source = inspect.getsource(template_manager.main)
        self.assertNotIn("--load", source)


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