"""Smoke + happy-path tests for alignment_validator.

Verifies the renamed module imports cleanly, the gap analysis function
runs on a minimal fixture, and the public entry points used by other
scripts (preflight_checks, deterministic_checks) remain stable.
"""
import os
import sys
from unittest.mock import patch

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


def test_module_imports():
    import alignment_validator  # noqa: F401
    import blooms  # noqa: F401
    # Backward-compat: Bloom helpers used to live in alignment_graph.py.
    # blooms.py is the canonical home; alignment_validator must not require
    # blooms imports to function.
    assert hasattr(alignment_validator, "extract_clos")
    assert hasattr(alignment_validator, "analyze_gaps")
    assert hasattr(alignment_validator, "calculate_coverage")
    assert hasattr(alignment_validator, "validate_graph")


def test_analyze_gaps_on_empty_graph_flags_missing_pieces():
    import alignment_validator as av

    empty_graph = {
        "clos": [],
        "mlos": [],
        "materials": [],
        "assessments": [],
    }
    gaps = av.analyze_gaps(empty_graph)

    assert isinstance(gaps, dict)
    # An empty graph must produce a structured gap report even when every
    # bucket is empty — callers depend on the keys being present.
    for key in ("clos_without_summative", "modules_without_formative", "orphan_assessments", "orphan_materials"):
        assert key in gaps, f"analyze_gaps missing key {key!r}"


def test_calculate_coverage_returns_dict_on_empty_graph():
    import alignment_validator as av

    empty_graph = {
        "clos": [],
        "mlos": [],
        "materials": [],
        "assessments": [],
    }
    coverage = av.calculate_coverage(empty_graph)
    assert isinstance(coverage, dict)


def test_list_assignments_call_replaces_removed_helper():
    """Regression: extract_assessments used canvas_api.get_assignments_with_rubrics
    which never existed. Phase 3 fix routes through list_assignments() instead.
    Verify it's the call site we expect so future refactors don't reintroduce
    the broken helper name.
    """
    import alignment_validator as av

    fake_assignments = [
        {"id": 1, "rubric": [{"description": "x"}], "discussion_topic": None},
        {"id": 2, "use_rubric_for_grading": True, "discussion_topic": {"id": 99}},
    ]
    course_config = {"modules": [{"number": 1, "assessments": {"knowledge_check": True}}]}
    tree = []  # empty Canvas tree — function should still build rubric_map without crashing

    with patch("canvas_api.list_assignments", return_value=fake_assignments) as mock_la:
        result = av.extract_assessments({"course_id": "1"}, course_config, tree)
        assert mock_la.called, "extract_assessments must call canvas_api.list_assignments"
        assert isinstance(result, list)
