"""
Helix64 Program Loader - Load and resolve named programs from helix_programs.json
"""

import json
import re
from pathlib import Path
from typing import Dict, Optional, Tuple

# Path to helix_programs.json
PROGRAMS_JSON_PATH = Path(__file__).parent / "helix_programs.json"

# Cache loaded programs
_PROGRAMS_CACHE: Optional[Dict] = None


def _load_programs() -> Dict:
    """Load programs from JSON file (cached)."""
    global _PROGRAMS_CACHE
    if _PROGRAMS_CACHE is None:
        if PROGRAMS_JSON_PATH.exists():
            with open(PROGRAMS_JSON_PATH, "r", encoding="utf-8") as f:
                _PROGRAMS_CACHE = json.load(f)
        else:
            # Fallback if JSON doesn't exist yet
            _PROGRAMS_CACHE = {
                "programs": {
                    "BALANCED64": {"sequence": "ABCDEFGH"},
                },
                "task_to_program": {}
            }
    return _PROGRAMS_CACHE


def is_valid_codon_sequence(seq: str) -> bool:
    """Check if string is a valid 8-codon sequence (A-H only)."""
    if not seq or len(seq) != 8:
        return False
    return bool(re.match(r'^[A-Ha-h]{8}$', seq))


def resolve_program(program_input: Optional[str]) -> Tuple[str, str]:
    """
    Resolve a program input to a sequence.

    Args:
        program_input: Either:
            - Named program: "MATH64_ALPHA", "CODE64_ALPHA", etc.
            - Raw sequence: "BGGDDGEA"
            - None: returns default ABCDEFGH

    Returns:
        Tuple of (sequence, program_name)
        - sequence: The 8-codon sequence
        - program_name: The name used (e.g., "MATH64_ALPHA" or "custom:BGGDDGEA")
    """
    if program_input is None:
        return "ABCDEFGH", "BALANCED64"

    # Normalize to uppercase
    program_input = program_input.upper()

    # Check if it's a raw 8-codon sequence
    if is_valid_codon_sequence(program_input):
        return program_input, f"custom:{program_input}"

    # Look up named program
    data = _load_programs()
    programs = data.get("programs", {})

    if program_input in programs:
        seq = programs[program_input].get("sequence", "ABCDEFGH")
        return seq, program_input

    # Unknown name - return as-is (might be a gate policy name)
    return "ABCDEFGH", f"unknown:{program_input}"


def get_program_for_task(task_type: str) -> Tuple[str, str]:
    """
    Get the optimal program for a task type.

    Returns:
        Tuple of (sequence, program_name)
    """
    data = _load_programs()
    task_to_program = data.get("task_to_program", {})

    program_name = task_to_program.get(task_type, "BALANCED64")
    return resolve_program(program_name)


def list_programs() -> Dict[str, str]:
    """List all named programs and their sequences."""
    data = _load_programs()
    programs = data.get("programs", {})
    return {name: p.get("sequence", "?") for name, p in programs.items()}


def get_program_info(program_name: str) -> Optional[Dict]:
    """Get full info about a named program."""
    data = _load_programs()
    programs = data.get("programs", {})
    return programs.get(program_name)
