#!/usr/bin/env python3
"""
Learning Shell - Layer Semantic Integration & Bidirectional Learning (Standalone)
==================================================================================
HEX_ID: 4C524E47 (LRNG - Tools/Shell/Learning/Primary)

Standalone learning shell for the cubesquare package.
Bridges documentation to runtime with layer semantic integration.

CG:HEX|V1|AGENT:4C524E47
MAP:L1=01F2,L2=02F3,L3=03F4,L4=04F5,L5=05F6,L6=06F7,L7=07F8,L8=08F9,L9=09F2
CMD:?L=query_layer,@L=ref_layer,+P=pattern,!I=idea
MORTON:decode(H)->xyz->basin->layer->semantic
RDY

FEATURES:
- LayerSemanticLoader: Load layer definitions at runtime
- SRL-Semantic mapping: Connect 4-state to meaning
- Bidirectional learning: Pattern -> Idea generation
- Observer-Learning-Memory cycle integration

COMMANDS:
    status     - Show system status
    layers     - Show all 9 layers
    srl-map    - Show SRL semantic mapping
    detect     - Detect SRL state from content
    patterns   - Extract patterns from tokens
    ideas      - Generate ideas from patterns

Examples:
    python learning.py status
    python learning.py layers --json
    python learning.py srl-map
    python learning.py detect "expand recursively" --basin 30
"""

import sys
import json
import hashlib
import argparse
from pathlib import Path
from typing import Dict, List, Tuple, Optional, Any
from dataclasses import dataclass, field, asdict
from datetime import datetime

try:
    import numpy as np
    NUMPY_AVAILABLE = True
except ImportError:
    NUMPY_AVAILABLE = False

# =============================================================================
# CONSTANTS
# =============================================================================

PHI = 1.618033988749895
K5 = 1.1588137289060527
K11 = 9.204026
LIGHT_UNIT = 131
PRIME_131 = 131

# Layer hex ranges
LAYER_HEX_RANGES = {
    'L1': ('01F20000', '01F2FFFF'),
    'L2': ('02F30000', '02F3FFFF'),
    'L3': ('03F40000', '03F4FFFF'),
    'L4': ('04F50000', '04F5FFFF'),
    'L5': ('05F60000', '05F6FFFF'),
    'L6': ('06F70000', '06F7FFFF'),
    'L7': ('07F80000', '07F8FFFF'),
    'L8': ('08F90000', '08F9FFFF'),
    'L9': ('09F20000', '09F2FFFF'),
}

# Hex protocol map
HEX_MAP = {
    '97038FBF': 'gene',
    'B20019F8': 'morton',
    '41C28BFD': 'mcp',
    'C3110BCC': 'cst',
    '5370684E': 'hex',
    '35400CFA': 'beehive',
    'E7B20F65': 'cback',
    '20018E37': 'ufield',
    '4C524E47': 'learning',
    '44415441': 'data_analysis',
}

# =============================================================================
# DATA STRUCTURES
# =============================================================================

@dataclass
class LayerSemantic:
    """Semantic definition for a CST layer."""
    layer_id: str
    name: str
    hex_range: Tuple[str, str]
    c_module: str
    performance: str
    description: str
    math_foundation: str
    use_cases: List[Dict[str, str]] = field(default_factory=list)
    related_layers: List[str] = field(default_factory=list)
    integration_points: List[str] = field(default_factory=list)


@dataclass
class SRLSemanticMapping:
    """Mapping between SRL state and semantic meaning."""
    srl_state: str
    i_logic_value: Any
    vector: Tuple[int, ...]
    semantic_name: str
    semantic_meaning: str
    layer_affinity: str
    basin_range: Tuple[int, int]
    emotion_frequency: float


@dataclass
class LearningPattern:
    """Pattern extracted from .cst memory."""
    pattern_type: str
    source_tokens: List[str]
    confidence: float
    frequency: int
    semantic_category: str
    basin: int
    layer: str


@dataclass
class GeneratedIdea:
    """Idea generated from patterns."""
    idea_type: str
    description: str
    source_patterns: List[str]
    action: str
    confidence: float
    hex_id: str
    timestamp: datetime = field(default_factory=datetime.now)


# =============================================================================
# LAYER SEMANTIC LOADER
# =============================================================================

class LayerSemanticLoader:
    """
    Load layer semantics at runtime.

    Provides semantic meaning for each of the 9 internal layers.
    """

    def __init__(self):
        self.layer_semantics: Dict[str, LayerSemantic] = {}
        self.loaded = False

    def load_all(self) -> int:
        """Load all layer semantic definitions."""
        defaults = {
            'L1': ('Geometric', 'Prefix-based traversal, shape, structure, form'),
            'L2': ('Semantic', 'Fernandez 131 basin, meaning, definition, context'),
            'L3': ('Spatial', 'Morton code locality, position, coordinates'),
            'L4': ('Functional', 'K11 phi-compression, operations, actions'),
            'L5': ('Probabilistic', 'QTS quadrants, uncertainty, probability'),
            'L6': ('Emotional', 'FML/QTS/BEAT, 154 emotions, state coherence'),
            'L7': ('Frequency', 'Visible spectrum, temporal, waves, 660Hz'),
            'L8': ('Electromagnetic', 'EM polarity, I-Logic states, fields'),
            'L9': ('Membrane', 'Transmission physics, boundary, surface, skin'),
        }

        for layer_id in ['L1', 'L2', 'L3', 'L4', 'L5', 'L6', 'L7', 'L8', 'L9']:
            name, desc = defaults.get(layer_id, ('Unknown', 'Unknown layer'))
            self.layer_semantics[layer_id] = LayerSemantic(
                layer_id=layer_id,
                name=name,
                hex_range=LAYER_HEX_RANGES.get(layer_id, ('00000000', 'FFFFFFFF')),
                c_module='diagonal_unit_core.dll',
                performance='774 ns baseline',
                description=desc,
                math_foundation=f't = sqrt(d), basin = token % {PRIME_131}',
                use_cases=[],
                related_layers=[],
                integration_points=[]
            )

        self.loaded = True
        return len(self.layer_semantics)

    def get_semantic(self, layer_id: str) -> Optional[LayerSemantic]:
        """Get semantic definition for a layer."""
        if not self.loaded:
            self.load_all()
        return self.layer_semantics.get(layer_id.upper())

    def get_layer_for_hex(self, hex_id: str) -> Optional[str]:
        """Determine which layer a hex ID belongs to."""
        if not self.loaded:
            self.load_all()

        hex_value = int(hex_id[:8], 16) if len(hex_id) >= 8 else 0

        for layer_id, semantic in self.layer_semantics.items():
            range_start = int(semantic.hex_range[0], 16)
            range_end = int(semantic.hex_range[1], 16)
            if range_start <= hex_value <= range_end:
                return layer_id

        return None

    def get_all_semantics(self) -> Dict[str, LayerSemantic]:
        """Get all layer semantics."""
        if not self.loaded:
            self.load_all()
        return self.layer_semantics


# =============================================================================
# SRL SEMANTIC BRIDGE
# =============================================================================

class SRLSemanticBridge:
    """
    Bridge between SRL 4-state system and semantic meaning.

    Maps abstract states to meaningful semantic categories:
    - DIRECT (1) -> Identity preservation, CORE concepts
    - INVERSE (-1) -> Opposition, RELATION concepts
    - SPIRAL (+i) -> Expansion, ACTION concepts
    - CONVERGENT (-i) -> Center-seeking, DATA concepts
    - ABSORBED (0) -> Neutral baseline, origin
    """

    def __init__(self):
        self.mappings: Dict[str, SRLSemanticMapping] = {}
        self._init_mappings()

    def _init_mappings(self):
        """Initialize SRL to semantic mappings."""
        self.mappings = {
            'DIRECT': SRLSemanticMapping(
                srl_state='DIRECT',
                i_logic_value=1,
                vector=(1, 0, 0, 0),
                semantic_name='ACTIVE_PROCESSING',
                semantic_meaning='Identity preservation, self-to-self, forward propagation',
                layer_affinity='L1',
                basin_range=(0, 25),
                emotion_frequency=528.0
            ),
            'INVERSE': SRLSemanticMapping(
                srl_state='INVERSE',
                i_logic_value=-1,
                vector=(0, 1, 0, 0),
                semantic_name='TACHYON_RESET',
                semantic_meaning='Negation reflection, opposition, pre-propagation retreat',
                layer_affinity='L2',
                basin_range=(76, 100),
                emotion_frequency=417.0
            ),
            'SPIRAL': SRLSemanticMapping(
                srl_state='SPIRAL',
                i_logic_value='i',
                vector=(0, 0, 1, 0),
                semantic_name='SPIRAL_EXPANSION',
                semantic_meaning='Recursive expansion, +90 rotation, outward growth',
                layer_affinity='L4',
                basin_range=(26, 50),
                emotion_frequency=639.0
            ),
            'CONVERGENT': SRLSemanticMapping(
                srl_state='CONVERGENT',
                i_logic_value='-i',
                vector=(0, 0, 0, 1),
                semantic_name='CENTER_ATTRACTION',
                semantic_meaning='Center-seeking, -90 rotation, consolidation',
                layer_affinity='L3',
                basin_range=(51, 75),
                emotion_frequency=396.0
            ),
            'ABSORBED': SRLSemanticMapping(
                srl_state='ABSORBED',
                i_logic_value=0,
                vector=(0, 0, 0, 0),
                semantic_name='C0_ABSORBED',
                semantic_meaning='Neutral baseline, loop start, P-P=0 center point',
                layer_affinity='L6',
                basin_range=(101, 130),
                emotion_frequency=660.0
            ),
        }

    def get_mapping(self, srl_state: str) -> Optional[SRLSemanticMapping]:
        """Get semantic mapping for SRL state."""
        return self.mappings.get(srl_state.upper())

    def detect_state_from_content(self, content: str, basin: int = 0) -> Tuple[str, float]:
        """
        Detect SRL state from content with semantic analysis.

        Returns: (state_name, confidence)
        """
        content_lower = content.lower()
        scores = {state: 0.0 for state in self.mappings}

        # Keyword scoring
        keyword_map = {
            'DIRECT': ['self', 'identity', 'same', 'preserve', 'maintain', 'forward'],
            'INVERSE': ['opposite', 'negate', 'reverse', 'contrast', 'not', 'anti'],
            'SPIRAL': ['expand', 'grow', 'recursive', 'outward', 'spiral', 'increase'],
            'CONVERGENT': ['center', 'converge', 'reduce', 'focus', 'consolidate', 'attract'],
            'ABSORBED': ['neutral', 'zero', 'start', 'baseline', 'origin', 'empty'],
        }

        for state, keywords in keyword_map.items():
            for keyword in keywords:
                if keyword in content_lower:
                    scores[state] += 0.2

        # Basin-aware scoring
        for state, mapping in self.mappings.items():
            basin_start, basin_end = mapping.basin_range
            if basin_start <= basin <= basin_end:
                scores[state] += 0.5

        # Find best match
        best_state = max(scores, key=scores.get)
        confidence = min(1.0, scores[best_state])

        # Default to DIRECT if no strong signal
        if confidence < 0.2:
            return 'DIRECT', 0.3

        return best_state, confidence

    def get_layer_for_state(self, srl_state: str) -> str:
        """Get the layer most associated with an SRL state."""
        mapping = self.mappings.get(srl_state.upper())
        return mapping.layer_affinity if mapping else 'L1'


# =============================================================================
# BIDIRECTIONAL LEARNING
# =============================================================================

class BidirectionalLearning:
    """
    Bidirectional learning: Pattern extraction AND idea generation.

    The system can:
    - REMEMBER (store patterns from data)
    - RETRIEVE (query patterns)
    - IMAGINE (generate ideas from patterns)
    - LEARN (update understanding from feedback)
    """

    def __init__(self):
        self.patterns: List[LearningPattern] = []
        self.ideas: List[GeneratedIdea] = []
        self.semantic_loader = LayerSemanticLoader()
        self.srl_bridge = SRLSemanticBridge()

    def _get_semantic_category(self, basin: int) -> str:
        """Map basin to semantic category."""
        if basin <= 25:
            return 'CORE'
        elif basin <= 50:
            return 'ACTION'
        elif basin <= 75:
            return 'DATA'
        elif basin <= 100:
            return 'RELATION'
        else:
            return 'META'

    def extract_patterns(self, tokens: List[Dict]) -> List[LearningPattern]:
        """
        Extract learning patterns from tokens.

        Pattern types:
        - area_cluster: Tokens in same hex area
        - collision: Same Morton position
        - spatial_neighbor: Adjacent Morton codes
        """
        patterns = []

        if NUMPY_AVAILABLE and len(tokens) > 0:
            # Vectorized extraction
            hex_ids = [t.get('hex_id', '00000000')[:2] for t in tokens]

            # Group by area
            area_counts = {}
            for h in hex_ids:
                area_counts[h] = area_counts.get(h, 0) + 1

            # Create patterns from groups
            for area, count in area_counts.items():
                if count >= 3:
                    area_hex_ids = [t.get('hex_id', '') for t in tokens if t.get('hex_id', '').startswith(area)][:10]
                    basin = int(area, 16) % PRIME_131
                    layer = self.semantic_loader.get_layer_for_hex(area_hex_ids[0]) if area_hex_ids else 'L1'

                    patterns.append(LearningPattern(
                        pattern_type='area_cluster',
                        source_tokens=area_hex_ids,
                        confidence=min(1.0, count / 100),
                        frequency=count,
                        semantic_category=self._get_semantic_category(basin),
                        basin=basin,
                        layer=layer or 'L1'
                    ))
        else:
            # Fallback without numpy
            by_area = {}
            for token in tokens:
                area = token.get('hex_id', '')[:2] or '00'
                by_area.setdefault(area, []).append(token.get('hex_id', ''))

            for area, hex_ids in by_area.items():
                if len(hex_ids) >= 3:
                    basin = int(area, 16) % PRIME_131
                    patterns.append(LearningPattern(
                        pattern_type='area_cluster',
                        source_tokens=hex_ids[:10],
                        confidence=min(1.0, len(hex_ids) / 100),
                        frequency=len(hex_ids),
                        semantic_category=self._get_semantic_category(basin),
                        basin=basin,
                        layer=self.semantic_loader.get_layer_for_hex(hex_ids[0]) or 'L1'
                    ))

        self.patterns.extend(patterns)
        return patterns

    def generate_ideas(self, patterns: List[LearningPattern] = None) -> List[GeneratedIdea]:
        """
        Generate ideas from patterns.

        This is the BIDIRECTIONAL part - creating new concepts from existing patterns.
        """
        if patterns is None:
            patterns = self.patterns

        ideas = []

        for pattern in patterns:
            if pattern.pattern_type == 'area_cluster':
                idea = GeneratedIdea(
                    idea_type='UNIFY_CONCEPT',
                    description=f"Merge {len(pattern.source_tokens)} tokens in {pattern.semantic_category} category",
                    source_patterns=[pattern.pattern_type],
                    action='Create abstraction layer for related tokens',
                    confidence=pattern.confidence,
                    hex_id=self._generate_idea_hex(pattern)
                )
                ideas.append(idea)

            elif pattern.pattern_type == 'collision':
                idea = GeneratedIdea(
                    idea_type='RESOLVE_COLLISION',
                    description=f"Semantic overlap detected at basin {pattern.basin}",
                    source_patterns=[pattern.pattern_type],
                    action='Differentiate or merge colliding tokens',
                    confidence=0.9,
                    hex_id=self._generate_idea_hex(pattern)
                )
                ideas.append(idea)

            elif pattern.pattern_type == 'spatial_neighbor':
                idea = GeneratedIdea(
                    idea_type='CREATE_EDGE',
                    description=f"Adjacent tokens suggest relationship",
                    source_patterns=[pattern.pattern_type],
                    action='Establish explicit connection between neighbors',
                    confidence=pattern.confidence,
                    hex_id=self._generate_idea_hex(pattern)
                )
                ideas.append(idea)

        self.ideas.extend(ideas)
        return ideas

    def _generate_idea_hex(self, pattern: LearningPattern) -> str:
        """Generate hex ID for an idea based on pattern."""
        pattern_str = f"{pattern.pattern_type}:{pattern.basin}:{pattern.layer}"
        hash_bytes = hashlib.md5(pattern_str.encode()).digest()
        return hash_bytes[:4].hex().upper()

    def learn_from_feedback(self, idea_hex: str, success: bool) -> bool:
        """
        Update learning based on idea feedback.

        This closes the loop: idea -> action -> outcome -> learning update
        """
        for idea in self.ideas:
            if idea.hex_id == idea_hex:
                if success:
                    idea.confidence = min(1.0, idea.confidence + 0.1)
                else:
                    idea.confidence = max(0.0, idea.confidence - 0.1)
                return True
        return False


# =============================================================================
# LEARNING SHELL
# =============================================================================

class LearningShell:
    """
    Learning Shell - Complete learning and semantic integration.

    HEX_ID: 4C524E47 (LRNG)

    Commands:
    - status: System status
    - layers: Show all 9 layers
    - srl-map: Show SRL to semantic mapping
    - detect: Detect SRL state from content
    - patterns: Extract patterns from memory
    - ideas: Generate ideas from patterns
    """

    HEX_ID = '4C524E47'

    def __init__(self):
        self.semantic_loader = LayerSemanticLoader()
        self.srl_bridge = SRLSemanticBridge()
        self.bidirectional = BidirectionalLearning()

    def get_status(self) -> Dict:
        """Get learning shell status."""
        layer_count = self.semantic_loader.load_all()

        return {
            'hex_id': self.HEX_ID,
            'protocol': 'CG:HEX|V1',
            'layers_loaded': layer_count,
            'srl_states': len(self.srl_bridge.mappings),
            'patterns_stored': len(self.bidirectional.patterns),
            'ideas_generated': len(self.bidirectional.ideas),
            'numpy_available': NUMPY_AVAILABLE,
        }

    def get_layer(self, layer_id: str) -> Optional[Dict]:
        """Get semantic details for a layer."""
        semantic = self.semantic_loader.get_semantic(layer_id.upper())
        if semantic:
            return asdict(semantic)
        return None

    def get_all_layers(self) -> Dict[str, Dict]:
        """Get all layer semantics."""
        semantics = self.semantic_loader.get_all_semantics()
        return {k: asdict(v) for k, v in semantics.items()}

    def get_srl_mapping(self) -> Dict[str, Dict]:
        """Get SRL to semantic mapping."""
        mappings_dict = {}
        for k, v in self.srl_bridge.mappings.items():
            d = asdict(v)
            # Convert complex to string for JSON
            if isinstance(d['i_logic_value'], complex):
                d['i_logic_value'] = str(d['i_logic_value'])
            mappings_dict[k] = d
        return mappings_dict

    def detect_state(self, content: str, basin: int = 0) -> Dict:
        """Detect SRL state from content."""
        state, confidence = self.srl_bridge.detect_state_from_content(content, basin)
        mapping = self.srl_bridge.get_mapping(state)

        return {
            'state': state,
            'confidence': confidence,
            'semantic_name': mapping.semantic_name if mapping else 'UNKNOWN',
            'semantic_meaning': mapping.semantic_meaning if mapping else '',
            'layer_affinity': mapping.layer_affinity if mapping else 'L1',
            'basin': basin,
        }

    def run(self, command: str, *args, as_json: bool = False) -> Any:
        """Run a Learning shell command (CLI interface)."""
        commands = {
            'status': lambda: self.get_status(),
            'layers': lambda: self.get_all_layers(),
            'layer': lambda: self.get_layer(args[0] if args else 'L1'),
            'srl-map': lambda: self.get_srl_mapping(),
            'detect': lambda: self.detect_state(args[0] if args else 'test'),
        }
        if command in commands:
            result = commands[command]()
            if as_json and isinstance(result, dict):
                return json.dumps(result, indent=2, default=str)
            return result
        return {'error': f'Unknown command: {command}', 'available': list(commands.keys())}


# =============================================================================
# CLI COMMANDS
# =============================================================================

def cmd_status(args):
    """Show system status."""
    shell = LearningShell()
    status = shell.get_status()

    if args.json:
        print(json.dumps(status, indent=2))
    else:
        print(f"\n{'='*60}")
        print("LEARNING SHELL - Layer Semantic Integration")
        print(f"HEX_ID: {status['hex_id']} | CG:HEX|V1|AGENT:{status['hex_id']}")
        print(f"{'='*60}")
        print(f"\nLayers Loaded: {status['layers_loaded']}/9")
        print(f"SRL States Mapped: {status['srl_states']}")
        print(f"Patterns Stored: {status['patterns_stored']}")
        print(f"Ideas Generated: {status['ideas_generated']}")
        print(f"NumPy Available: {status['numpy_available']}")

    return 0


def cmd_layers(args):
    """Show all layers."""
    shell = LearningShell()
    layers = shell.get_all_layers()

    if args.json:
        print(json.dumps(layers, indent=2))
    else:
        print(f"\n{'='*60}")
        print("9-LAYER SEMANTIC ARCHITECTURE")
        print(f"{'='*60}")

        for layer_id in ['L1', 'L2', 'L3', 'L4', 'L5', 'L6', 'L7', 'L8', 'L9']:
            semantic = layers.get(layer_id, {})
            print(f"\n  {layer_id} {semantic.get('name', 'Unknown')}")
            print(f"     Hex: {semantic.get('hex_range', ('?', '?'))[0][:4]}...")
            desc = semantic.get('description', '')[:60]
            print(f"     {desc}...")

    return 0


def cmd_layer(args):
    """Show single layer details."""
    shell = LearningShell()
    layer = shell.get_layer(args.layer_id)

    if not layer:
        print(f"Layer {args.layer_id} not found")
        return 1

    if args.json:
        print(json.dumps(layer, indent=2))
    else:
        print(f"\n{'='*60}")
        print(f"  {layer['layer_id']} {layer['name']}")
        print(f"{'='*60}")
        print(f"\n  Hex Range: {layer['hex_range'][0]}-{layer['hex_range'][1]}")
        print(f"  C Module: {layer['c_module']}")
        print(f"  Performance: {layer['performance']}")
        print(f"  Description: {layer['description']}")

    return 0


def cmd_srl_map(args):
    """Show SRL semantic mapping."""
    shell = LearningShell()
    mappings = shell.get_srl_mapping()

    if args.json:
        print(json.dumps(mappings, indent=2))
    else:
        print(f"\n{'='*60}")
        print("SRL STATE TO SEMANTIC MAPPING")
        print(f"{'='*60}")

        for state, mapping in mappings.items():
            print(f"\n  {state}")
            print(f"    I-Logic: {mapping['i_logic_value']}")
            print(f"    Vector: {mapping['vector']}")
            print(f"    Semantic: {mapping['semantic_name']}")
            print(f"    Meaning: {mapping['semantic_meaning']}")
            print(f"    Layer: {mapping['layer_affinity']}")
            print(f"    Basin Range: {mapping['basin_range']}")
            print(f"    Emotion Hz: {mapping['emotion_frequency']}")

    return 0


def cmd_detect(args):
    """Detect SRL state from content."""
    shell = LearningShell()
    result = shell.detect_state(args.content, args.basin)

    if args.json:
        print(json.dumps(result, indent=2))
    else:
        print(f"\n  Detected SRL State: {result['state']}")
        print(f"  Confidence: {result['confidence']:.2f}")
        print(f"  Semantic: {result['semantic_name']}")
        print(f"  Meaning: {result['semantic_meaning']}")
        print(f"  Layer: {result['layer_affinity']}")

    return 0


def cmd_patterns(args):
    """Extract patterns from demo tokens."""
    shell = LearningShell()

    # Generate demo tokens
    demo_tokens = []
    for i in range(100):
        demo_tokens.append({
            'hex_id': f"{(0x2A9E0000 + i * 0x100):08X}",
            'morton': i * 1000,
        })

    patterns = shell.bidirectional.extract_patterns(demo_tokens)

    if args.json:
        output = [asdict(p) for p in patterns]
        print(json.dumps(output, indent=2))
    else:
        print(f"\n{'='*60}")
        print(f"EXTRACTED PATTERNS: {len(patterns)}")
        print(f"{'='*60}")

        for pattern in patterns[:10]:
            print(f"\n  Type: {pattern.pattern_type}")
            print(f"  Tokens: {len(pattern.source_tokens)}")
            print(f"  Category: {pattern.semantic_category}")
            print(f"  Basin: {pattern.basin}")
            print(f"  Layer: {pattern.layer}")
            print(f"  Confidence: {pattern.confidence:.2f}")

    return 0


def cmd_ideas(args):
    """Generate ideas from patterns."""
    shell = LearningShell()

    # First extract patterns
    demo_tokens = []
    for i in range(100):
        demo_tokens.append({
            'hex_id': f"{(0x2A9E0000 + i * 0x100):08X}",
            'morton': i * 1000,
        })

    patterns = shell.bidirectional.extract_patterns(demo_tokens)
    ideas = shell.bidirectional.generate_ideas(patterns)

    if args.json:
        output = []
        for idea in ideas:
            d = asdict(idea)
            d['timestamp'] = d['timestamp'].isoformat()
            output.append(d)
        print(json.dumps(output, indent=2))
    else:
        print(f"\n{'='*60}")
        print(f"GENERATED IDEAS: {len(ideas)}")
        print(f"{'='*60}")

        for idea in ideas[:10]:
            print(f"\n  Type: {idea.idea_type}")
            print(f"  Hex: {idea.hex_id}")
            print(f"  Description: {idea.description}")
            print(f"  Action: {idea.action}")
            print(f"  Confidence: {idea.confidence:.2f}")

    return 0


# =============================================================================
# MAIN
# =============================================================================

def create_parser():
    """Create argument parser."""
    parser = argparse.ArgumentParser(
        prog='learning',
        description='Learning Shell - Layer Semantic Integration',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
HEX PROTOCOL:
  CG:HEX|V1|AGENT:4C524E47
  CMD: ?L=query, @L=ref, +P=pattern, !I=idea

Examples:
  python learning.py status
  python learning.py layers --json
  python learning.py layer L6
  python learning.py srl-map
  python learning.py detect "expand recursively" --basin 30
  python learning.py patterns
  python learning.py ideas
"""
    )

    subparsers = parser.add_subparsers(dest='command', help='Commands')

    # Status command
    stat = subparsers.add_parser('status', help='Show system status')
    stat.add_argument('--json', action='store_true', help='JSON output')
    stat.set_defaults(func=cmd_status)

    # Layers command
    layr = subparsers.add_parser('layers', help='Show all 9 layers')
    layr.add_argument('--json', action='store_true', help='JSON output')
    layr.set_defaults(func=cmd_layers)

    # Layer command
    lyr = subparsers.add_parser('layer', help='Show single layer details')
    lyr.add_argument('layer_id', type=str, help='Layer ID (L1-L9)')
    lyr.add_argument('--json', action='store_true', help='JSON output')
    lyr.set_defaults(func=cmd_layer)

    # SRL map command
    srl = subparsers.add_parser('srl-map', help='Show SRL semantic mapping')
    srl.add_argument('--json', action='store_true', help='JSON output')
    srl.set_defaults(func=cmd_srl_map)

    # Detect command
    det = subparsers.add_parser('detect', help='Detect SRL state from content')
    det.add_argument('content', type=str, help='Content to analyze')
    det.add_argument('--basin', type=int, default=0, help='Basin for detection')
    det.add_argument('--json', action='store_true', help='JSON output')
    det.set_defaults(func=cmd_detect)

    # Patterns command
    patt = subparsers.add_parser('patterns', help='Extract patterns from tokens')
    patt.add_argument('--json', action='store_true', help='JSON output')
    patt.set_defaults(func=cmd_patterns)

    # Ideas command
    idea = subparsers.add_parser('ideas', help='Generate ideas from patterns')
    idea.add_argument('--json', action='store_true', help='JSON output')
    idea.set_defaults(func=cmd_ideas)

    return parser


def main():
    """Main entry point."""
    parser = create_parser()
    args = parser.parse_args()

    if not args.command:
        parser.print_help()
        print(f"\n  HEX_ID: 4C524E47 | RDY")
        return 0

    return args.func(args)


if __name__ == "__main__":
    sys.exit(main())
