#!/usr/bin/env python3
"""
sym.py
------
Universal .sym capsule format for BloomOS.

Unifies KRISPER + Bio_Poetica into a 4D JSON structure:
- data: payload
- context: metadata layer
- time: temporal anchor
- meaning: semantic layer

This is the universal format for all BloomOS capsules.
"""

from __future__ import annotations

import time
import json
import hashlib
from dataclasses import dataclass, field, asdict
from typing import Dict, Any, Optional, List

from .reflex import ReflexAnchor, insert_reflex_anchor
from .identity import SoulAnchor, create_soul_anchor


@dataclass
class SymCapsule:
    """
    Universal .sym capsule format.

    4D structure:
    - data: the actual payload
    - context: metadata and environment
    - time: temporal anchoring
    - meaning: semantic interpretation layer
    """
    # Core data
    data: Any

    # Context layer
    context: Dict[str, Any] = field(default_factory=dict)

    # Temporal layer
    time_created: float = field(default_factory=time.time)
    time_modified: float = field(default_factory=time.time)
    version: str = "1.0"

    # Meaning layer
    meaning: Dict[str, Any] = field(default_factory=dict)

    # Anchors
    reflex_anchors: List[Dict] = field(default_factory=list)
    soul: Optional[Dict] = None

    # JUNK segments (entropy buffers)
    junk: List[bytes] = field(default_factory=list)

    # Provenance
    source: str = "unknown"
    creator: str = "system"

    # --- Substrate metadata (Phase 16: Superglyph integration) ---
    substrate: str = "helix64"
    """Name of the physical symbol substrate that produced this capsule.
    Examples: 'helix64', 'superglyph', 'mixed'."""

    engine: Optional[str] = None
    """Human-readable engine descriptor.
    Examples: 'BloomOS/Helix64', 'Superglyph/AgenticCell', 'Echo/Helix64'."""

    engine_meta: Dict[str, Any] = field(default_factory=dict)
    """Arbitrary engine-specific metadata.
    For Superglyph this might include:
        - genome_path
        - lobe_name
        - regen_backend
    """


def sym_capsule(
    data: Any,
    context: Optional[Dict[str, Any]] = None,
    meaning: Optional[Dict[str, Any]] = None,
    version: str = "1.0",
    source: str = "unknown",
    creator: str = "system",
    add_soul: bool = True,
    add_reflex: bool = True,
    substrate: str = "helix64",
    engine: Optional[str] = None,
    engine_meta: Optional[Dict[str, Any]] = None,
) -> SymCapsule:
    """
    Create a .sym capsule.

    Args:
        data: Payload data
        context: Context metadata
        meaning: Semantic interpretation
        version: Capsule version
        source: Source system (krisper, bio_poetica, dispatcher, etc.)
        creator: Creator identifier
        add_soul: Whether to add soul anchor
        add_reflex: Whether to add reflex anchor
        substrate: Physical symbol substrate (helix64, superglyph, mixed)
        engine: Human-readable engine descriptor
        engine_meta: Engine-specific metadata

    Returns:
        SymCapsule object
    """
    capsule = SymCapsule(
        data=data,
        context=context or {},
        meaning=meaning or {},
        version=version,
        source=source,
        creator=creator,
        substrate=substrate,
        engine=engine or "BloomOS/Helix64",
        engine_meta=engine_meta or {},
    )

    # Add soul anchor
    if add_soul:
        seed = hashlib.sha256(str(data).encode()).hexdigest()[:16]
        soul = create_soul_anchor(seed, creator, metadata={"source": source})
        capsule.soul = asdict(soul)

    # Add reflex anchor
    if add_reflex:
        task_id = capsule.soul["soul_id"][:16] if capsule.soul else "unknown"
        anchor = insert_reflex_anchor(
            task_id=task_id,
            context=str(data)[:100],
            anchor_type="capsule_reflex"
        )
        capsule.reflex_anchors.append(asdict(anchor))

    return capsule


def capsule_to_json(capsule: SymCapsule) -> str:
    """Serialize capsule to JSON."""
    d = asdict(capsule)
    # Convert bytes to hex for JSON
    d["junk"] = [j.hex() if isinstance(j, bytes) else j for j in d["junk"]]
    return json.dumps(d, indent=2, sort_keys=True, default=str)


def capsule_from_json(json_str: str) -> SymCapsule:
    """Deserialize capsule from JSON."""
    d = json.loads(json_str)
    # Convert hex back to bytes
    d["junk"] = [bytes.fromhex(j) if isinstance(j, str) else j for j in d.get("junk", [])]
    return SymCapsule(**d)


def capsule_id(capsule: SymCapsule) -> str:
    """Get unique ID for capsule (uses soul_id if available)."""
    if capsule.soul:
        return capsule.soul.get("soul_id", "")[:32]
    return hashlib.sha256(str(capsule.data).encode()).hexdigest()[:32]


# ============================================================================
# KRISPER/BIO_POETICA BRIDGES
# ============================================================================

def lower_krisper_to_sym(krsp: Dict[str, Any]) -> SymCapsule:
    """
    Lower KRISPER gene format to .sym capsule.

    Args:
        krsp: KRISPER gene dict with genes, meta, etc.

    Returns:
        SymCapsule
    """
    return sym_capsule(
        data=krsp.get("genes", []),
        context=krsp.get("meta", {}),
        meaning={
            "program_name": krsp.get("meta", {}).get("program_name"),
            "gene_count": len(krsp.get("genes", [])),
        },
        version=krsp.get("krsp_version", "1"),
        source="krisper",
    )


def lower_bio_poetica_to_sym(text: str, intents: List[tuple]) -> SymCapsule:
    """
    Lower Bio_Poetica interpretation to .sym capsule.

    Args:
        text: Original poetic text
        intents: Parsed intents [(type, target), ...]

    Returns:
        SymCapsule
    """
    return sym_capsule(
        data=text,
        context={"original_text": text},
        meaning={
            "intents": [{"type": t, "target": tgt} for t, tgt in intents],
            "poetic": True,
        },
        source="bio_poetica",
    )


def lower_task_to_sym(
    task_type: str,
    description: str,
    program: str,
    result: Dict[str, Any],
    *,
    substrate: str = "helix64",
    engine: Optional[str] = None,
    engine_meta: Optional[Dict[str, Any]] = None,
) -> SymCapsule:
    """
    Lower a BloomOS task result to .sym capsule.

    Args:
        task_type: Task category
        description: Task description
        program: Helix8 program used
        result: Backplane result dict
        substrate: Physical symbol substrate (helix64, superglyph, mixed)
        engine: Human-readable engine descriptor
        engine_meta: Engine-specific metadata (genome_path, lobe_name, etc.)

    Returns:
        SymCapsule
    """
    return sym_capsule(
        data=result,
        context={
            "task_type": task_type,
            "description": description,
            "program": program,
        },
        meaning={
            "gate_policy": result.get("gate", {}).get("policy"),
            "gate_mutation": f"{result.get('gate', {}).get('gate_op_before')} → {result.get('gate', {}).get('gate_op_after')}",
            "logits_mean": result.get("logits_mean"),
        },
        source="dispatcher",
        substrate=substrate,
        engine=engine,
        engine_meta=engine_meta,
    )


# ============================================================================
# DEMO
# ============================================================================

def _demo():
    """Demonstrate .sym capsule format."""
    print("=" * 70)
    print("UNIVERSAL .SYM CAPSULE FORMAT DEMO")
    print("=" * 70)
    print()

    # Create a capsule
    capsule = sym_capsule(
        data={"equation": "2x + 5 = 13", "solution": "x = 4"},
        context={"task_type": "math", "program": "ABCDGFGH"},
        meaning={"domain": "algebra", "difficulty": "easy"},
        source="dispatcher",
        creator="user:josh",
    )

    print("CAPSULE STRUCTURE:")
    print(f"  ID: {capsule_id(capsule)}")
    print(f"  Source: {capsule.source}")
    print(f"  Creator: {capsule.creator}")
    print(f"  Version: {capsule.version}")
    print()

    print("DATA LAYER:")
    print(f"  {capsule.data}")
    print()

    print("CONTEXT LAYER:")
    print(f"  {capsule.context}")
    print()

    print("MEANING LAYER:")
    print(f"  {capsule.meaning}")
    print()

    print("SOUL ANCHOR:")
    if capsule.soul:
        print(f"  Soul ID: {capsule.soul['soul_id'][:32]}...")
        print(f"  Creator: {capsule.soul['creator']}")
    print()

    print("REFLEX ANCHORS:")
    for anchor in capsule.reflex_anchors:
        print(f"  {anchor['anchor_id'][:16]}... ({anchor['anchor_type']})")
    print()

    # Serialize/deserialize test
    json_str = capsule_to_json(capsule)
    restored = capsule_from_json(json_str)
    print(f"SERIALIZATION: {'OK' if capsule_id(capsule) == capsule_id(restored) else 'FAIL'}")
    print()

    print("=" * 70)


if __name__ == "__main__":
    _demo()
