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

"""
Seed Expansion API

Wrapper around CDR_Steven_Package `helix_core` modules:

    /home/voidstr3m33/CDR_Steven_Package/code/helix_core/

We expose simple, safe functions:

    encode_text_to_seed(text) -> bytes
    regrow_seed(seed, depth=256) -> Any
    dynamic_dimension(seed_or_text) -> float

This keeps all CDR-specific logic in one place and lets other modules
(EchoBridge, BloomOS loops, experiments) call a clean interface.
"""

import math
from collections import Counter
from dataclasses import dataclass
from pathlib import Path
from typing import Any, Optional

import os
import sys


# Default CDR root; can be overridden via env var
DEFAULT_CDR_ROOT = Path(
    os.environ.get("CDR_ROOT", "/home/voidstr3m33/CDR_Steven_Package")
)

HELIX_CORE_PATH = DEFAULT_CDR_ROOT / "code" / "helix_core"


def _ensure_helix_core_on_path() -> None:
    """
    Add helix_core directory to sys.path if not already present.
    """
    hc_str = str(HELIX_CORE_PATH)
    if hc_str not in sys.path:
        sys.path.append(hc_str)


@dataclass
class SeedInfo:
    seed_bytes: bytes
    entropy_class: Optional[float]
    dimension_hint: Optional[int]
    sha256_prefix: Optional[bytes]
    seed_entropy: Optional[float] = None  # Shannon entropy of seed bytes


def compute_seed_entropy(seed_bytes: bytes) -> float:
    """
    Compute Shannon entropy of seed bytes (bits/byte).

    This measures the information density of the seed itself,
    useful for adaptive learning signals.

    Args:
        seed_bytes: Raw seed bytes

    Returns:
        Entropy in bits per byte (0-8 range)
    """
    if not seed_bytes:
        return 0.0

    freq = Counter(seed_bytes)
    total = len(seed_bytes)

    entropy = 0.0
    for count in freq.values():
        if count > 0:
            p = count / total
            entropy -= p * math.log2(p)

    return entropy


def get_dynamic_lattice_D(d_override: Optional[int] = None) -> int:
    """
    Get the current DynamicLattice dimensional depth from CDR.

    This uses the CDR helix_dynamic_d.DynamicLattice, which reads
    from HELIX_D environment variable or defaults to 72.

    Args:
        d_override: Explicit D value to use (bypasses lattice)

    Returns:
        Dimensional depth (1-72)
    """
    if d_override is not None:
        return max(1, min(72, d_override))

    _ensure_helix_core_on_path()
    try:
        from helix_dynamic_d import DynamicLattice  # type: ignore
        lattice = DynamicLattice()
        return lattice.D
    except ImportError:
        # Fallback to environment or default
        return int(os.environ.get("HELIX_D", "72"))


def encode_text_to_seed(text: str) -> SeedInfo:
    """
    Encode text into a CDR seed using helix_encode.

    Returns a SeedInfo struct with header info if available.
    """
    _ensure_helix_core_on_path()
    try:
        import helix_encode  # type: ignore
    except ImportError as e:
        raise RuntimeError(
            f"helix_encode not available at {HELIX_CORE_PATH}. "
            f"Ensure CDR_Steven_Package is present."
        ) from e

    # We don't know exact API, so we defensively try common patterns.
    # You can refine this once you inspect helix_encode.py more closely.
    if hasattr(helix_encode, "encode_text_to_seed"):
        seed = helix_encode.encode_text_to_seed(text)
    elif hasattr(helix_encode, "encode"):
        seed = helix_encode.encode(text)
    elif hasattr(helix_encode, "encode_text"):
        seed = helix_encode.encode_text(text)
    else:
        raise RuntimeError(
            "helix_encode module does not expose encode_text_to_seed or encode(). "
            "Please adapt seed_api.encode_text_to_seed() to match the real API."
        )

    # seed is expected to be bytes; header parsing is left as a future refinement.
    if isinstance(seed, str):
        seed = seed.encode("utf-8")

    # Compute seed entropy
    seed_ent = compute_seed_entropy(seed)

    # Get lattice D
    lattice_d = get_dynamic_lattice_D()

    return SeedInfo(
        seed_bytes=seed,
        entropy_class=None,
        dimension_hint=lattice_d,
        sha256_prefix=None,
        seed_entropy=seed_ent,
    )


def regrow_seed(seed: bytes, depth: int = 256) -> Any:
    """
    Regrow a seed into a manifold/object using helix_regrow.

    depth: granularity level (e.g. 64, 256, 1024)
    """
    _ensure_helix_core_on_path()
    try:
        import helix_regrow  # type: ignore
    except ImportError as e:
        raise RuntimeError(
            f"helix_regrow not available at {HELIX_CORE_PATH}. "
            f"Ensure CDR_Steven_Package is present."
        ) from e

    if hasattr(helix_regrow, "regrow"):
        return helix_regrow.regrow(seed, depth=depth)
    elif hasattr(helix_regrow, "regrow_seed"):
        return helix_regrow.regrow_seed(seed, depth)
    elif hasattr(helix_regrow, "regenerate"):
        return helix_regrow.regenerate(seed, depth=depth)
    else:
        raise RuntimeError(
            "helix_regrow module does not expose regrow() or regrow_seed(). "
            "Please adapt seed_api.regrow_seed() to match the real API."
        )


def dynamic_dimension_from_text(text: str) -> Optional[float]:
    """
    Use helix_dynamic_d to estimate D(X) for given text.
    """
    _ensure_helix_core_on_path()
    try:
        import helix_dynamic_d  # type: ignore
    except ImportError:
        return None

    if hasattr(helix_dynamic_d, "estimate_d_for_text"):
        return float(helix_dynamic_d.estimate_d_for_text(text))
    elif hasattr(helix_dynamic_d, "estimate_d"):
        return float(helix_dynamic_d.estimate_d(text))
    elif hasattr(helix_dynamic_d, "compute_d"):
        return float(helix_dynamic_d.compute_d(text))
    return None


if __name__ == "__main__":
    # Simple manual smoke test
    s = "hello from Helix64 + CDR"
    print("Encoding:", s)
    try:
        info = encode_text_to_seed(s)
        print("Seed length:", len(info.seed_bytes))
    except Exception as e:
        print(f"encode_text_to_seed failed (expected if API mismatch): {e}")
