"""
Belief Revision System - Domain Registry

Registry for domain-specific smoke test packs.
Enables pluggable domain extensions without modifying core code.
"""
from __future__ import annotations

from typing import Callable, Dict, List, Optional, Protocol, Tuple

# Type for smoke test results
SmokeTestResult = Tuple[int, int, List[str]]  # (tests_run, failures, messages)


class SmokeTestPack(Protocol):
    """
    Protocol for smoke test functions.

    Smoke tests verify domain invariants and return:
    - tests_run: Number of tests executed
    - failures: Number of failed tests
    - messages: List of diagnostic messages
    """
    def __call__(
        self,
        store: "CASStore",  # Forward reference to avoid circular import
        domain_id: str,
        world_label: str
    ) -> SmokeTestResult:
        ...


# Registry: domain_id -> level -> pack
_REGISTRY: Dict[str, Dict[str, SmokeTestPack]] = {}

# Module tracking for debugging
_MODULE_SOURCES: Dict[str, Dict[str, str]] = {}


def register(domain_id: str, pack: SmokeTestPack, level: str = "smoke") -> None:
    """
    Register a smoke test pack for a domain and level.

    Args:
        domain_id: Domain identifier (e.g., "writing", "biology")
        pack: Smoke test function
        level: Test level - conventionally "smoke", "regression", or "deep"
    """
    levels = _REGISTRY.setdefault(domain_id, {})
    levels[level] = pack


def auto_register(
    domain_id: str,
    module_name: str,
    pack: SmokeTestPack,
    level: str = "smoke"
) -> None:
    """
    Register with module source tracking (for auto-discovery).

    Args:
        domain_id: Domain identifier
        module_name: Source module name
        pack: Smoke test function
        level: Test level
    """
    register(domain_id, pack, level=level)
    sources = _MODULE_SOURCES.setdefault(domain_id, {})
    sources[level] = module_name


def get(domain_id: str, level: str = "smoke") -> Optional[SmokeTestPack]:
    """
    Get a smoke test pack for a domain and level.

    Args:
        domain_id: Domain identifier
        level: Test level

    Returns:
        Smoke test function or None if not registered
    """
    return _REGISTRY.get(domain_id, {}).get(level)


def get_levels(domain_id: str) -> List[str]:
    """Get all registered test levels for a domain."""
    return sorted(_REGISTRY.get(domain_id, {}).keys())


def registered_domains() -> List[str]:
    """Get all registered domain IDs."""
    return sorted(_REGISTRY.keys())


def get_module_source(domain_id: str, level: str = "smoke") -> Optional[str]:
    """Get the source module for a registered pack (for debugging)."""
    return _MODULE_SOURCES.get(domain_id, {}).get(level)


def clear() -> None:
    """Clear all registrations (for testing)."""
    _REGISTRY.clear()
    _MODULE_SOURCES.clear()


def summary() -> Dict[str, List[str]]:
    """Get summary of all registrations."""
    return {domain: get_levels(domain) for domain in registered_domains()}


# =============================================================================
# Convenience Decorator
# =============================================================================

def smoke_test(domain_id: str, level: str = "smoke"):
    """
    Decorator to register a function as a smoke test.

    Usage:
        @smoke_test("writing", level="smoke")
        def test_writing(store, domain_id, world_label):
            ...
            return (tests_run, failures, messages)
    """
    def decorator(fn: SmokeTestPack) -> SmokeTestPack:
        register(domain_id, fn, level=level)
        return fn
    return decorator
