"""
BloomOS Position 4 Gate Selection Logic

FITTED from full experiment suite (2025-11-21):
- math_bias (G): code +0.032, json -0.051, math +0.009, reason +0.020
- code_bias (A): code +0.003, json +0.038, math -0.059, reason -0.006
- json_bias (B): code -0.013, json -0.074, math +0.003, reason +0.058
- balanced (E): code +0.011, json +0.042, math +0.027, reason +0.005
- image_bias (C): code -0.023, json +0.021, math +0.001, reason -0.074
- audio_bias (D): code -0.010, json +0.024, math +0.020, reason -0.003

NOTE: Gate names reflect original intent, not measured behavior.
      json_bias is actually BAD for json tasks (-0.074).
      Use fit_gate_effects_from_summary.py to re-fit after more experiments.
"""

from typing import Dict, List, Tuple

# Gate policies - FITTED from bloomos_experiment_runner.py batch summary
GATE_POLICIES = {
    "math_bias": {
        "codon": "G",  # E→G
        "expected_effects": {
            "math": +0.008783,
            "code": +0.031523,
            "json": -0.051357,
            "reason": +0.019782
        },
        "description": "Fitted: best for code (+0.032), hurts json (-0.051)"
    },
    "code_bias": {
        "codon": "A",  # E→A
        "expected_effects": {
            "math": -0.059174,
            "code": +0.003323,
            "json": +0.038255,
            "reason": -0.006004
        },
        "description": "Fitted: hurts math (-0.059), mild json boost (+0.038)"
    },
    "json_bias": {
        "codon": "B",  # E→B
        "expected_effects": {
            "math": +0.003000,
            "code": -0.012965,
            "json": -0.073924,
            "reason": +0.058351
        },
        "description": "Fitted: INVERTED - bad for json (-0.074), good for reason (+0.058)"
    },
    "balanced": {
        "codon": "E",  # E→E (identity)
        "expected_effects": {
            "math": +0.027235,
            "code": +0.010707,
            "json": +0.042053,
            "reason": +0.005417
        },
        "description": "Fitted: generally positive across all anchors"
    },
    "image_bias": {
        "codon": "C",  # E→C
        "expected_effects": {
            "math": +0.000510,
            "code": -0.022859,
            "json": +0.020586,
            "reason": -0.074284,
            "image": +0.25  # placeholder - no image experiments yet
        },
        "description": "Fitted: worst for reason (-0.074), needs image experiments"
    },
    "audio_bias": {
        "codon": "D",  # E→D
        "expected_effects": {
            "math": +0.019646,
            "code": -0.009727,
            "json": +0.024387,
            "reason": -0.003262,
            "audio": +0.25  # placeholder - no audio experiments yet
        },
        "description": "Fitted: mild effects, needs audio experiments"
    }
}

# Default anchor mappings for common task types
DEFAULT_ANCHORS = {
    "math": ["math"],
    "code": ["code"],
    "json": ["json"],
    "search": ["code", "json"],  # Search uses code+json
    "reason": ["math", "code"],  # Reasoning uses math+code
    "text": ["code"],
    "query": ["json"],
    # New modalities
    "image": ["image"],          # Image processing
    "audio": ["audio"],          # Audio processing
    "vision": ["image", "code"], # Vision + code hybrid
}

# Task type → gate policy mapping
TASK_TO_GATE = {
    "math": "math_bias",
    "code": "code_bias",
    "json": "json_bias",
    "search": "code_bias",   # Search tends toward code/json
    "reason": "math_bias",   # Reasoning uses math
    "text": "balanced",
    "query": "json_bias",
    # New modalities
    "image": "image_bias",   # Image processing tasks
    "audio": "audio_bias",   # Audio processing tasks
    "vision": "image_bias",  # Vision tasks
}


def resolve_anchors(task_type: str, anchors_override: List[str] = None) -> List[str]:
    """
    Resolve which anchors to use for a given task.

    Args:
        task_type: Task category (math, code, json, etc.)
        anchors_override: User-provided anchors (takes precedence)

    Returns:
        List of anchor names to use
    """
    if anchors_override:
        return anchors_override
    return DEFAULT_ANCHORS.get(task_type, ["code"])  # Default to code if unknown


def choose_gate(task_type: str, gate_override: str = None) -> Tuple[str, Dict]:
    """
    Choose gate policy for a given task.

    Args:
        task_type: Task category (math, code, json, etc.)
        gate_override: User-provided gate policy (takes precedence)

    Returns:
        Tuple of (gate_policy_name, gate_config)
    """
    if gate_override and gate_override in GATE_POLICIES:
        return gate_override, GATE_POLICIES[gate_override]

    # Auto-select based on task type
    policy_name = TASK_TO_GATE.get(task_type, "balanced")
    return policy_name, GATE_POLICIES[policy_name]


def apply_gate_to_program(base_program: str, gate_policy: Dict, position: int = 4) -> str:
    """
    Apply gate policy to program by substituting codon at given position.

    Args:
        base_program: Base Helix64 program (e.g., "ABCDEFGH")
        gate_policy: Gate policy dict with "codon" key
        position: Position to mutate (default: 4, zero-indexed)

    Returns:
        Modified program with gate codon substituted
    """
    if len(base_program) <= position:
        raise ValueError(f"Program '{base_program}' too short for position {position}")

    codon = gate_policy["codon"]
    return base_program[:position] + codon + base_program[position + 1:]
