"""
phi.embed — Core Φ embedding: (F, τ, δ) → 30-base hachimoji DNA

Combines all four layers into a single encoding pass.  This is the
only module that knows about the hachimoji alphabet and the DNA
sequence layout.

DNA layout (30 bases total):
  bases  0-7:   F(E) — byte-class frequencies on Δ₇
  bases  8-15:  τ(E) — parse tree node-type frequencies
  bases 16-23:  δ(E) — child-ordering frequencies
  bases 24-29:  Layer 4 consistency (G=pass, T=fail)

Dependencies: phi.charclass, phi.ast_parse, phi.consistency
"""

from __future__ import annotations

import hashlib
from typing import Dict, List, Optional

from .charclass import compute_F
from .ast_parse import compute_tau, compute_delta, NODE_TYPES
from .consistency import check_consistency, RULE_ORDER

# ── Hachimoji alphabet ───────────────────────────────────────────────────

HACHIMOJI_BASES = list("ABCGPSTZ")
INDEX_TO_BASE = dict(enumerate(HACHIMOJI_BASES))
BASE_TO_INDEX = {b: i for i, b in enumerate(HACHIMOJI_BASES)}


# ── Float-to-base conversion ─────────────────────────────────────────────

def _float_to_3bit(x: float) -> int:
    """Quantize a float [0, 1] to a 3-bit integer (0-7)."""
    return min(7, max(0, round(x * 7)))


def _vec_to_bases(values: List[float]) -> str:
    """Map floats in [0,1] to hachimoji bases (3 bits each, 8 bases)."""
    return "".join(INDEX_TO_BASE[_float_to_3bit(v)] for v in values)


# ── Core encoding ────────────────────────────────────────────────────────

def encode_phi(equation: str) -> Optional[Dict]:
    """Apply Φ mapping: equation string → 30-base hachimoji DNA sequence.

    The four layers are:
      1. F(E) — byte-class histogram (Δ₇)
      2. (implicit — derived from the phase-alphabet mapping)
      3. τ(E) + δ(E) — parse tree structure
      4. 6 consistency rules → primer-binding region

    Returns a dict with the DNA sequence and all intermediate values,
    or None if the equation is empty.

    The returned dict is the standard Φ encoding record consumed by
    phi.output (FASTQ, Adleman graph, PCR protocol).
    """
    if not equation or not equation.strip():
        return None

    F = compute_F(equation)
    consistency = check_consistency(equation)

    tau = compute_tau(equation)
    delta = compute_delta(equation)

    # Fallback for unparseable equations: uniform distribution
    # (encodes as all-A — "null structural signal")
    if tau is None:
        tau = [1.0 / len(NODE_TYPES)] * len(NODE_TYPES)

    # Encode each layer as 8 hachimoji bases
    F_dna = _vec_to_bases(F[:8])
    tau_dna = _vec_to_bases(tau[:8])
    delta_dna = _vec_to_bases(delta[:8]) if delta else "AAAAAAAA"

    # Layer 4: encode consistency G=pass T=fail
    consistency_dna = "".join("G" if consistency[r] else "T" for r in RULE_ORDER)
    full_sequence = F_dna + tau_dna + delta_dna + consistency_dna

    quality_scores = "".join("A" if v else "P" for v in consistency.values())
    seq_hash = hashlib.sha256(full_sequence.encode()).hexdigest()[:16]

    return {
        "equation": equation,
        "dna_sequence": full_sequence,
        "length": len(full_sequence),
        "bases": list(HACHIMOJI_BASES),
        "schema": "phi_embedding_v2",
        "F": [round(x, 4) for x in F],
        "tau": [round(x, 4) for x in tau],
        "delta": [round(x, 4) for x in delta] if delta else None,
        "F_dna": F_dna,
        "tau_dna": tau_dna,
        "delta_dna": delta_dna,
        "consistency": consistency,
        "consistency_pass": all(consistency.values()),
        "consistency_dna": consistency_dna,
        "quality_scores": quality_scores,
        "sha256_prefix": seq_hash,
        "pas_primer": "CCCCCC",
        "fail_primer": "AAAAAA",
    }
