#!/usr/bin/env python3
from __future__ import annotations

"""
Helix Pipeline Definitions (Grammar v2)

This module unifies:
    - The Helix8 pipeline semantics from CDR_Steven_Package/code/bloomos/programs.py
    - The named programs in helix_cdc/bloomos/helix_programs.json
    - The gate mutations (math_bias, code_bias, json_bias, balanced)

It does NOT enforce VM validity (the current VM still only accepts ABCDEFGH),
but it gives a canonical place to reason about:

    - What each codon does (semantically)
    - Which pipelines are intended for math/code/json
    - Which gate policies map to which programs

You can use this in dashboards, EchoBridge, experiment runners, etc.
"""

from dataclasses import dataclass
from pathlib import Path
from typing import Dict, List, Optional

from .helix_grammar import CODON_SEMANTICS, POSITION_SEMANTICS


BASE_PROGRAM = "ABCDEFGH"


@dataclass
class HelixPipeline:
    name: str
    sequence: str
    description: str
    intended_for: List[str]  # e.g. ["math"], ["code"], ["json", "reason"]
    gate_policy: Optional[str] = None  # math_bias, code_bias, json_bias, balanced


def default_pipelines() -> Dict[str, HelixPipeline]:
    """
    Return canonical pipelines based on CDR programs.py + your helix_programs.json.

    Note: Even if the current VM chokes on non-ABCDEFGH sequences, these
    remain SEMANTIC definitions for future-compatible VM versions.
    """
    pipelines: Dict[str, HelixPipeline] = {}

    # Baseline: ABCDEFGH
    pipelines["BALANCED64"] = HelixPipeline(
        name="BALANCED64",
        sequence="ABCDEFGH",
        description="Baseline Helix8 pipeline (no gate mutation).",
        intended_for=["general", "balanced"],
        gate_policy="balanced",
    )

    # Gate-mutation programs (from CDR programs.py)
    # Position 4 = gate position (E by default)
    # math_bias: E -> G -> ABCDGFGH
    pipelines["MATH_PIPE_CDR"] = HelixPipeline(
        name="MATH_PIPE_CDR",
        sequence="ABCDGFGH",
        description=(
            "Math-biased pipeline: softmax gate at position 4. "
            "From CDR programs.py math_bias policy."
        ),
        intended_for=["math", "reason"],
        gate_policy="math_bias",
    )

    # code_bias: E -> A -> ABCDAFGH
    pipelines["CODE_PIPE_CDR"] = HelixPipeline(
        name="CODE_PIPE_CDR",
        sequence="ABCDAFGH",
        description=(
            "Code-biased pipeline: CTX_GATHER at gate position. "
            "From CDR programs.py code_bias policy."
        ),
        intended_for=["code"],
        gate_policy="code_bias",
    )

    # json_bias: E -> B -> ABCDBFGH
    pipelines["JSON_PIPE_CDR"] = HelixPipeline(
        name="JSON_PIPE_CDR",
        sequence="ABCDBFGH",
        description=(
            "JSON/structure-biased pipeline: EMBED at gate position. "
            "From CDR programs.py json_bias policy."
        ),
        intended_for=["json", "structure"],
        gate_policy="json_bias",
    )

    return pipelines


def describe_pipeline(name: str) -> str:
    """
    Return a human-readable description of a pipeline, including per-position roles.
    """
    pipes = default_pipelines()
    if name not in pipes:
        return f"Unknown pipeline: {name}"

    p = pipes[name]
    seq = p.sequence
    lines: List[str] = []
    lines.append(f"Pipeline: {p.name}")
    lines.append(f"Sequence: {seq}")
    lines.append(f"Intended for: {', '.join(p.intended_for) or 'unspecified'}")
    if p.gate_policy:
        lines.append(f"Gate policy: {p.gate_policy}")
    lines.append(f"Description: {p.description}")
    lines.append("")
    lines.append("Positions:")
    for i, c in enumerate(seq):
        pos_sem = POSITION_SEMANTICS.get(i, {})
        cod_sem = CODON_SEMANTICS.get(c, {})
        lines.append(
            f"  [{i}] {c} :: "
            f"pos_role={pos_sem.get('role')} "
            f"phase={pos_sem.get('phase')} "
            f"codon_name={cod_sem.get('name')}"
        )
    return "\n".join(lines)


def pipelines_for_task(task_type: str) -> List[HelixPipeline]:
    """
    Suggest pipelines for a given BloomOS task_type.
    """
    tt = task_type.lower()
    pipes = default_pipelines()
    out: List[HelixPipeline] = []
    for p in pipes.values():
        if "general" in p.intended_for:
            out.append(p)
        elif tt in p.intended_for:
            out.append(p)
    return out


def load_external_pipelines(path: Path) -> Dict[str, HelixPipeline]:
    """
    Stub for future use: load additional pipelines from JSON.

    For now, just returns default_pipelines().
    """
    return default_pipelines()


if __name__ == "__main__":
    # Quick demo for manual CLI testing:
    for name in default_pipelines().keys():
        print(describe_pipeline(name))
        print("-" * 60)
