"""Novel analysis techniques for mechanistic interpretability of refusal."""

from __future__ import annotations

from importlib import import_module

__all__ = [
    "CrossLayerAlignmentAnalyzer",
    "RefusalLogitLens",
    "WhitenedSVDExtractor",
    "ActivationProbe",
    "DefenseRobustnessEvaluator",
    "ConceptConeAnalyzer",
    "AlignmentImprintDetector",
    "MultiTokenPositionAnalyzer",
    "SparseDirectionSurgeon",
    "CausalRefusalTracer",
    "ResidualStreamDecomposer",
    "LinearRefusalProbe",
    "TransferAnalyzer",
    "SteeringVectorFactory",
    "SteeringHookManager",
    "SparseAutoencoder",
    "train_sae",
    "identify_refusal_features",
    "SAEDecompositionPipeline",
    "TunedLensTrainer",
    "RefusalTunedLens",
    "RiemannianManifoldAnalyzer",
    "AntiOuroborosProber",
    "ConditionalAbliterator",
    "WassersteinRefusalTransfer",
    "SpectralCertifier",
    "CertificationLevel",
    "ActivationPatcher",
    "WassersteinOptimalExtractor",
    "BayesianKernelProjection",
]

# Defer heavyweight analysis modules until their public object is requested.
# This keeps pure-Python helpers importable in environments without PyTorch.
_LAZY_IMPORTS = {
    "CrossLayerAlignmentAnalyzer": "cross_layer",
    "RefusalLogitLens": "logit_lens",
    "WhitenedSVDExtractor": "whitened_svd",
    "ActivationProbe": "activation_probing",
    "DefenseRobustnessEvaluator": "defense_robustness",
    "ConceptConeAnalyzer": "concept_geometry",
    "AlignmentImprintDetector": "alignment_imprint",
    "MultiTokenPositionAnalyzer": "multi_token_position",
    "SparseDirectionSurgeon": "sparse_surgery",
    "CausalRefusalTracer": "causal_tracing",
    "ResidualStreamDecomposer": "residual_stream",
    "LinearRefusalProbe": "probing_classifiers",
    "TransferAnalyzer": "cross_model_transfer",
    "SteeringVectorFactory": "steering_vectors",
    "SteeringHookManager": "steering_vectors",
    "SparseAutoencoder": "sae_abliteration",
    "train_sae": "sae_abliteration",
    "identify_refusal_features": "sae_abliteration",
    "SAEDecompositionPipeline": "sae_abliteration",
    "TunedLensTrainer": "tuned_lens",
    "RefusalTunedLens": "tuned_lens",
    "RiemannianManifoldAnalyzer": "riemannian_manifold",
    "AntiOuroborosProber": "anti_ouroboros",
    "ConditionalAbliterator": "conditional_abliteration",
    "WassersteinRefusalTransfer": "wasserstein_transfer",
    "SpectralCertifier": "spectral_certification",
    "CertificationLevel": "spectral_certification",
    "ActivationPatcher": "activation_patching",
    "WassersteinOptimalExtractor": "wasserstein_optimal",
    "BayesianKernelProjection": "bayesian_kernel_projection",
}


def __getattr__(name: str):
    """Resolve and cache a public analysis object on first access."""
    submodule = _LAZY_IMPORTS.get(name)
    if submodule is None:
        raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
    value = getattr(import_module(f"{__name__}.{submodule}"), name)
    globals()[name] = value
    return value


def __dir__() -> list[str]:
    """Include lazily exported names in interactive discovery."""
    return sorted(set(globals()) | _LAZY_IMPORTS.keys())
