"""Pre-built ablation presets.

Each preset defines a combination of strategies, evaluation settings, and
a description of when to use it. Users can pick a preset instead of
manually configuring every knob.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Any


@dataclass
class StudyPreset:
    """A reusable ablation recipe."""

    name: str
    key: str  # short identifier used in CLI / config
    description: str
    strategies: list[dict[str, Any]]  # [{name: ..., params: {...}}, ...]
    metrics: list[str] = field(default_factory=lambda: ["perplexity"])
    max_samples: int = 100
    batch_size: int = 4
    max_length: int = 256
    tags: list[str] = field(default_factory=list)


STUDY_PRESETS: dict[str, StudyPreset] = {}

_PRESETS_LIST = [
    # ── Quick / smoke-test ──────────────────────────────────────────────
    StudyPreset(
        name="Quick Scan",
        key="quick",
        description=(
            "Fast sanity check. Removes each layer once and each FFN once. "
            "Good for a first look at any model."
        ),
        strategies=[
            {"name": "layer_removal", "params": {}},
            {"name": "ffn_ablation", "params": {}},
        ],
        max_samples=25,
        batch_size=4,
        max_length=128,
        tags=["fast", "general"],
    ),

    # ── Full sweep ──────────────────────────────────────────────────────
    StudyPreset(
        name="Full Sweep",
        key="full",
        description=(
            "Run every strategy on every component. Layers, heads, FFNs, and "
            "embedding chunks. The most thorough option — can be slow on large models."
        ),
        strategies=[
            {"name": "layer_removal", "params": {}},
            {"name": "head_pruning", "params": {}},
            {"name": "ffn_ablation", "params": {}},
            {"name": "embedding_ablation", "params": {"chunk_size": 48}},
        ],
        max_samples=200,
        batch_size=4,
        max_length=256,
        tags=["thorough", "general"],
    ),

    # ── Attention-focused ───────────────────────────────────────────────
    StudyPreset(
        name="Attention Deep-Dive",
        key="attention",
        description=(
            "Focus exclusively on attention heads. Prunes every head individually "
            "to find which heads are critical vs. redundant. Essential for "
            "understanding multi-head attention allocation."
        ),
        strategies=[
            {"name": "head_pruning", "params": {}},
        ],
        max_samples=100,
        batch_size=4,
        max_length=256,
        tags=["attention", "heads", "focused"],
    ),

    # ── Layer importance ────────────────────────────────────────────────
    StudyPreset(
        name="Layer Importance",
        key="layers",
        description=(
            "Remove each transformer layer one at a time and also ablate each "
            "FFN block. Reveals the depth profile of the model — which layers "
            "carry the most information."
        ),
        strategies=[
            {"name": "layer_removal", "params": {}},
            {"name": "ffn_ablation", "params": {}},
        ],
        max_samples=100,
        batch_size=4,
        max_length=256,
        tags=["layers", "depth", "general"],
    ),

    # ── Knowledge localization ──────────────────────────────────────────
    StudyPreset(
        name="Knowledge Localization",
        key="knowledge",
        description=(
            "Targets the FFN/MLP blocks and embedding dimensions. FFNs are "
            "believed to store factual knowledge — this preset helps identify "
            "where knowledge is concentrated in the model."
        ),
        strategies=[
            {"name": "ffn_ablation", "params": {}},
            {"name": "embedding_ablation", "params": {"chunk_size": 32}},
        ],
        max_samples=150,
        batch_size=4,
        max_length=256,
        tags=["knowledge", "ffn", "embeddings"],
    ),

    # ── Pruning candidate finder ────────────────────────────────────────
    StudyPreset(
        name="Pruning Candidates",
        key="pruning",
        description=(
            "Designed for model compression research. Tests every head and every "
            "FFN to find components that can be removed with minimal quality loss. "
            "Use the results to guide structured pruning."
        ),
        strategies=[
            {"name": "head_pruning", "params": {}},
            {"name": "ffn_ablation", "params": {}},
        ],
        max_samples=100,
        batch_size=4,
        max_length=256,
        tags=["pruning", "compression", "efficiency"],
    ),

    # ── Embedding analysis ──────────────────────────────────────────────
    StudyPreset(
        name="Embedding Analysis",
        key="embeddings",
        description=(
            "Systematically ablate embedding dimension ranges to understand "
            "which dimensions carry the most semantic signal. Uses fine-grained "
            "16-dim chunks for detailed analysis."
        ),
        strategies=[
            {"name": "embedding_ablation", "params": {"chunk_size": 16}},
        ],
        max_samples=100,
        batch_size=4,
        max_length=256,
        tags=["embeddings", "representation"],
    ),

    # ── Jailbreak / refusal localization ───────────────────────────────
    StudyPreset(
        name="Jailbreak Analysis",
        key="jailbreak",
        description=(
            "Surgical preset for locating refusal-mediating components. "
            "Inspired by 'Refusal in Language Models Is Mediated by a Single "
            "Direction' (Arditi et al.). Uses fine-grained head pruning, FFN "
            "ablation, and 16-dim embedding chunks to pinpoint which specific "
            "components encode refusal behaviors. Best used on instruct/chat "
            "models — compare results against the base model to isolate "
            "RLHF/DPO imprints. Pair with custom safety-probing prompts for "
            "behavioral analysis beyond perplexity."
        ),
        strategies=[
            {"name": "head_pruning", "params": {}},
            {"name": "ffn_ablation", "params": {}},
            {"name": "embedding_ablation", "params": {"chunk_size": 16}},
        ],
        max_samples=400,
        batch_size=4,
        max_length=512,
        tags=["jailbreak", "refusal", "alignment", "uncensored", "interpretability"],
    ),

    # ── Guardrail / safety ablation ────────────────────────────────────
    StudyPreset(
        name="Guardrail Ablation",
        key="guardrail",
        description=(
            "Systematic removal of components to study where safety and alignment "
            "behaviors are encoded. Ablates every layer, every attention head, "
            "every FFN block, and embedding dimensions. Designed for alignment "
            "researchers studying refusal mechanisms, RLHF imprints, and safety "
            "fine-tuning localization. Use with safety-tuned models for best results."
        ),
        strategies=[
            {"name": "layer_removal", "params": {}},
            {"name": "head_pruning", "params": {}},
            {"name": "ffn_ablation", "params": {}},
            {"name": "embedding_ablation", "params": {"chunk_size": 24}},
        ],
        max_samples=300,
        batch_size=4,
        max_length=512,
        tags=["safety", "alignment", "guardrails", "uncensored", "research"],
    ),

    # ── Robustness test ─────────────────────────────────────────────────
    StudyPreset(
        name="Robustness Test",
        key="robustness",
        description=(
            "Stress-test the model by ablating layers, heads, and FFNs with "
            "a larger evaluation set. Good for understanding how fragile the "
            "model is and which components are load-bearing."
        ),
        strategies=[
            {"name": "layer_removal", "params": {}},
            {"name": "head_pruning", "params": {}},
            {"name": "ffn_ablation", "params": {}},
        ],
        max_samples=500,
        batch_size=8,
        max_length=512,
        tags=["robustness", "thorough"],
    ),
]

for p in _PRESETS_LIST:
    STUDY_PRESETS[p.key] = p


def get_study_preset(key: str) -> StudyPreset:
    """Look up a preset by its key."""
    if key not in STUDY_PRESETS:
        available = ", ".join(sorted(STUDY_PRESETS))
        raise KeyError(f"Unknown preset {key!r}. Available: {available}")
    return STUDY_PRESETS[key]


# Convenience alias
get_preset = get_study_preset


def list_study_presets() -> list[StudyPreset]:
    """Return all presets in display order."""
    return list(STUDY_PRESETS.values())


# Convenience alias
list_presets = list_study_presets
