"""Enforcement for rules/02-billing-boundary.md.

The dependency between the two modules points one way: items knows nothing of
billing, and billing knows nothing of items. This test reads the import graph
rather than trusting a convention, because the last time the boundary was
crossed it was crossed by accident and nobody noticed until an unrelated
refactor of item storage broke invoicing.
"""

import ast
from pathlib import Path

SRC = Path(__file__).resolve().parent.parent / "src"

# module directory -> import prefixes it may not reach for
FORBIDDEN = {
    "billing": ("src.items", "items"),
}


def _imported_modules(path):
    """Every module name this file imports, as dotted strings."""
    tree = ast.parse(path.read_text(encoding="utf-8"), filename=str(path))
    names = []
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            names.extend(alias.name for alias in node.names)
        elif isinstance(node, ast.ImportFrom):
            # level > 0 is a relative import, which cannot leave the package
            if node.level == 0 and node.module:
                names.append(node.module)
    return names


def test_billing_does_not_import_items():
    violations = []
    for module_dir, forbidden in FORBIDDEN.items():
        for path in (SRC / module_dir).rglob("*.py"):
            for imported in _imported_modules(path):
                if any(
                    imported == bad or imported.startswith(bad + ".")
                    for bad in forbidden
                ):
                    violations.append(f"{path.relative_to(SRC.parent)} imports {imported}")
    assert not violations, (
        "rules/02-billing-boundary.md violated: " + "; ".join(violations)
    )


def test_the_boundary_check_can_actually_fail(tmp_path):
    """A check that cannot fail is decoration. Prove this one detects a violation."""
    offender = tmp_path / "offender.py"
    offender.write_text("from src.items.model import Item\n", encoding="utf-8")
    imported = _imported_modules(offender)
    assert any(name.startswith("src.items") for name in imported)
