#!/usr/bin/env python3
"""
helix_cdc/core.py - Unified Helix Core with C-First Imports
============================================================

This module provides the canonical imports for Helix operations.
It tries C bindings first (60,000x faster) with Python fallback.

IMPORT THIS MODULE INSTEAD OF INDIVIDUAL FILES:

    from helix_cdc.core import (
        phi_delay,
        phi_stagger_delays,
        fibonacci_at,
        fast_grow_weights,
        get_backend_info,
    )

Session Reminder:
    Every new session should check:
    >>> from helix_cdc.core import get_backend_info
    >>> print(get_backend_info())
    {'using_c': True, 'backend': 'C (libhelix_cdc.so)', ...}
"""

from typing import Dict, Any, Optional, Tuple, List
import numpy as np

# ============================================================================
# C BINDINGS (60,000x faster)
# ============================================================================

_C_LIB = None
_USE_C = False

try:
    from helix_cdc.c_bindings import get_lib, HelixCDC
    _C_LIB = get_lib()
    if _C_LIB.available:
        _USE_C = True
except ImportError:
    pass

# ============================================================================
# GOLDEN RATIO CONSTANTS
# ============================================================================

import math
GOLDEN_RATIO = (1 + math.sqrt(5)) / 2  # Φ ≈ 1.618033988749895
FIBONACCI = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]


# ============================================================================
# PUBLIC API
# ============================================================================

def get_backend_info() -> Dict[str, Any]:
    """
    Get info about which backend is being used.

    Call this at the start of every session to verify C bindings are active.

    Returns:
        Dict with 'using_c', 'backend', 'speedup' keys
    """
    return {
        "using_c": _USE_C,
        "backend": "C (libhelix_cdc.so)" if _USE_C else "Python (fallback)",
        "speedup": "~60,000x" if _USE_C else "1x (baseline)",
        "lib_path": str(_C_LIB._lib_path) if _USE_C and hasattr(_C_LIB, '_lib_path') else None,
    }


def using_c() -> bool:
    """Check if C bindings are active."""
    return _USE_C


def phi_delay(base_delay: float, index: int) -> float:
    """Calculate Φ-staggered delay: base_delay * Φ^index"""
    if _USE_C:
        return _C_LIB.phi_delay(base_delay, index)
    return base_delay * (GOLDEN_RATIO ** index)


def phi_stagger_delays(
    count: int,
    base_delay: float = 0.1,
    max_delay: float = 5.0,
) -> List[float]:
    """Generate list of Φ-staggered delays."""
    if _USE_C:
        return list(_C_LIB.phi_stagger_delays(count, base_delay, max_delay))
    return [min(phi_delay(base_delay, i), max_delay) for i in range(count)]


def fibonacci_at(n: int) -> int:
    """Get Fibonacci number at index n."""
    if _USE_C:
        return _C_LIB.fibonacci_at(n)
    if n < len(FIBONACCI):
        return FIBONACCI[n]
    a, b = FIBONACCI[-2], FIBONACCI[-1]
    for _ in range(len(FIBONACCI), n + 1):
        a, b = b, a + b
    return b


def fast_grow_weights(
    genome_b64: str,
    n_values: int,
    layer_id: int = 0,
) -> np.ndarray:
    """
    Grow weight array from Base64 genome.

    Args:
        genome_b64: Base64-encoded genome bytes
        n_values: Number of FP32 values to generate
        layer_id: Layer ID for differentiation

    Returns:
        np.ndarray of shape (n_values,) with FP32 weights
    """
    if _USE_C:
        return _C_LIB.fast_grow_weights_b64(genome_b64, n_values, layer_id)

    # Python fallback (slow)
    import base64
    genome_bytes = base64.b64decode(genome_b64)
    seed = sum(genome_bytes) + layer_id * 0x9e3779b9
    rng = np.random.default_rng(seed & 0xFFFFFFFF)
    weights = rng.standard_normal(n_values).astype(np.float32)
    return np.tanh(weights)


def genome_random_search(
    target: np.ndarray,
    genome_len: int,
    layer_id: int = 0,
    n_iters: int = 10000,
    seed: int = 42,
) -> Tuple[str, float]:
    """
    Random search for genome that matches target weights.

    Returns:
        (best_genome_b64, best_error)
    """
    if _USE_C:
        return _C_LIB.genome_random_search(
            target.flatten().astype(np.float32),
            genome_len,
            layer_id,
            n_iters,
            seed,
        )

    raise NotImplementedError("genome_random_search requires C bindings")


# ============================================================================
# CLI
# ============================================================================

if __name__ == "__main__":
    import json
    info = get_backend_info()
    print("Helix Core Backend Info:")
    print(json.dumps(info, indent=2))

    if info["using_c"]:
        print("\n✓ C bindings active (60,000x speedup)")
    else:
        print("\n⚠ Python fallback (slow) - build C library with: cd c && make lib")
