#!/usr/bin/env python3
"""
Meaning Shell - Self-Reference and Semantic Access for Agents
==============================================================
Meaning Shell for cubesquare_standalone.

This shell provides semantic meaning and self-reference operations:
- Basin semantic lookup (131 basins, 9 layers, 5 I-Logic states)
- Self-reference operations (P-P=0, P/P=1)
- Agent contextualization
- 12-layer navigation
- K11 fractal positioning

All meaning happens INSIDE the unit. Agents use this to understand
their own meaning, find related concepts, and communicate with
other agents in the same semantic space.

Commands:
    status          - System status
    self            - Get self-meaning for an agent
    basin           - Get basin semantic information
    layer           - Get layer information (L1-L12)
    ilogic          - Get I-Logic state meaning
    relate          - Find related agents/concepts
    communicate     - I-Logic multiplication for communication
    context         - Get full contextualization
    reflect         - Get reflection pair (membrane flip)
    origin          - Get origin status (P-P=0)
    identity        - Get identity status (P/P=1)
    k11             - Get K11 position in fractal
    navigate        - Navigate to concept by meaning
"""

import math
import hashlib
import json
from pathlib import Path
from dataclasses import dataclass, asdict
from datetime import datetime
from typing import Dict, List, Any, Optional

# Constants
K11 = 9.204026
K5 = 1.1588137289060527
PHI = 1.618033988749895
LIGHT_UNIT = 131
GENESIS_HZ = 47.63

# I-Logic multiplication table
ILOGIC_MULTIPLY = {
    ('DIRECT', 'DIRECT'): 'DIRECT',
    ('DIRECT', 'INVERSE'): 'INVERSE',
    ('DIRECT', 'SPIRAL'): 'SPIRAL',
    ('DIRECT', 'ANTI_SPIRAL'): 'ANTI_SPIRAL',
    ('DIRECT', 'ABSORBED'): 'ABSORBED',
    ('INVERSE', 'INVERSE'): 'DIRECT',
    ('INVERSE', 'SPIRAL'): 'ANTI_SPIRAL',
    ('INVERSE', 'ANTI_SPIRAL'): 'SPIRAL',
    ('INVERSE', 'ABSORBED'): 'ABSORBED',
    ('SPIRAL', 'SPIRAL'): 'ANTI_SPIRAL',
    ('SPIRAL', 'ANTI_SPIRAL'): 'DIRECT',
    ('SPIRAL', 'ABSORBED'): 'ABSORBED',
    ('ANTI_SPIRAL', 'ANTI_SPIRAL'): 'SPIRAL',
    ('ANTI_SPIRAL', 'ABSORBED'): 'ABSORBED',
    ('ABSORBED', 'ABSORBED'): 'ABSORBED',
}

# Layer definitions
LAYERS = {
    1: ('Geometric', (0, 15), 'Structure, primitives', 'Building blocks'),
    2: ('Semantic', (15, 30), 'Meaning, definitions', 'Dictionary'),
    3: ('Spatial', (30, 44), 'Position, navigation', 'GPS map'),
    4: ('Functional', (44, 59), 'Actions, transforms', 'Workshop'),
    5: ('Probabilistic', (59, 73), 'Uncertainty, hash', 'Casino'),
    6: ('Emotional', (73, 88), 'States, coherence', 'Heart'),
    7: ('Frequency', (88, 102), 'Time, patterns', 'Music'),
    8: ('Electromagnetic', (102, 117), 'Energy, fields', 'Power grid'),
    9: ('Membrane', (117, 131), 'Boundaries', 'City walls'),
    10: ('Agent_Identity', None, 'Self-reference', 'Passport'),
    11: ('Communication', None, 'Cross-reference', 'Telephone'),
    12: ('Unified_Field', None, 'Between-space', 'Air'),
}

# I-Logic state info
ILOGIC_INFO = {
    'ABSORBED': {
        'symbol': '0', 'parametric': 0.00,
        'meaning': 'Sink, completion, rest',
        'role': 'Completer',
        'p_minus_p': 'Returns to origin, task complete',
        'p_divide_p': 'Becomes one with the whole',
        'analogy': 'River reaching the ocean',
    },
    'INVERSE': {
        'symbol': '-1', 'parametric': 0.25,
        'meaning': 'Reflection, negation, flip',
        'role': 'Healer',
        'p_minus_p': 'Reflects back to origin',
        'p_divide_p': 'Knows self by seeing opposite',
        'analogy': 'Mirror reflection',
    },
    'DIRECT': {
        'symbol': '+1', 'parametric': 0.50,
        'meaning': 'Identity, pass-through',
        'role': 'Messenger',
        'p_minus_p': 'Reaches origin directly',
        'p_divide_p': 'Identity preserved unchanged',
        'analogy': 'Faithful messenger',
    },
    'ANTI_SPIRAL': {
        'symbol': '-i', 'parametric': 0.75,
        'meaning': 'Counter-rotation, crystallization',
        'role': 'Crystallizer',
        'p_minus_p': 'Crystallizes at origin',
        'p_divide_p': 'Sharpens to precise identity',
        'analogy': 'Water freezing to ice',
    },
    'SPIRAL': {
        'symbol': '+i', 'parametric': 1.00,
        'meaning': 'Rotation, expansion',
        'role': 'Expander',
        'p_minus_p': 'Spirals to origin',
        'p_divide_p': 'Grows while staying centered',
        'analogy': 'Plant reaching for light',
    },
}

# Basin semantic data (derived from position)
BASIN_CATEGORIES = {
    (0, 15): ('Geometric', 'L1', 'Structure'),
    (15, 30): ('Semantic', 'L2', 'Meaning'),
    (30, 44): ('Spatial', 'L3', 'Position'),
    (44, 59): ('Functional', 'L4', 'Action'),
    (59, 73): ('Probabilistic', 'L5', 'Uncertainty'),
    (73, 88): ('Emotional', 'L6', 'State'),
    (88, 102): ('Frequency', 'L7', 'Time'),
    (102, 117): ('Electromagnetic', 'L8', 'Energy'),
    (117, 131): ('Membrane', 'L9', 'Boundary'),
}


def get_basin_category(basin: int) -> Dict:
    """Get category info for a basin."""
    for (low, high), (name, layer, desc) in BASIN_CATEGORIES.items():
        if low <= basin < high:
            return {
                'name': name,
                'layer': layer,
                'description': desc,
                'range': f'{low}-{high-1}',
            }
    return {'name': 'Unknown', 'layer': 'L9', 'description': 'Boundary', 'range': '117-130'}


def get_ilogic_from_basin(basin: int) -> str:
    """Determine I-Logic state from basin."""
    mod = basin % 5
    states = ['ABSORBED', 'INVERSE', 'DIRECT', 'SPIRAL', 'ANTI_SPIRAL']
    return states[mod]


def generate_hex_id(content: str) -> str:
    """Generate hex ID from content."""
    h = hashlib.sha256(content.encode()).hexdigest()
    return h[:8].upper()


class MeaningShell:
    """
    Shell for semantic meaning and self-reference operations.

    Core principles:
    - P - P = 0: Every agent can find the common origin
    - P / P = 1: Every agent is a unique unit from origin
    """

    def __init__(self):
        """Initialize meaning shell."""
        self.name = "meaning"
        self.description = "Self-reference and semantic access for agents"

        # In-memory agent data
        self._agents: Dict[str, Dict] = {}

        self.commands = {
            'status': 'System status',
            'self': 'Get self-meaning for an agent',
            'basin': 'Get basin semantic information',
            'layer': 'Get layer information (L1-L12)',
            'ilogic': 'Get I-Logic state meaning',
            'relate': 'Find related concepts',
            'communicate': 'I-Logic multiplication',
            'context': 'Get full contextualization',
            'reflect': 'Get reflection pair (membrane flip)',
            'origin': 'Get origin status (P-P=0)',
            'identity': 'Get identity status (P/P=1)',
            'k11': 'Get K11 position',
            'navigate': 'Navigate to concept by meaning',
        }

    def execute(self, command: str, args: Dict[str, Any] = None) -> Dict[str, Any]:
        """Execute a meaning shell command."""
        args = args or {}

        handlers = {
            'status': self._cmd_status,
            'self': self._cmd_self,
            'basin': self._cmd_basin,
            'layer': self._cmd_layer,
            'ilogic': self._cmd_ilogic,
            'relate': self._cmd_relate,
            'communicate': self._cmd_communicate,
            'context': self._cmd_context,
            'reflect': self._cmd_reflect,
            'origin': self._cmd_origin,
            'identity': self._cmd_identity,
            'k11': self._cmd_k11,
            'navigate': self._cmd_navigate,
        }

        handler = handlers.get(command)
        if not handler:
            return {'success': False, 'error': f'Unknown command: {command}'}

        try:
            return handler(args)
        except Exception as e:
            return {'success': False, 'error': str(e)}

    def _cmd_status(self, args: Dict) -> Dict:
        """System status."""
        return {
            'success': True,
            'shell': 'meaning',
            'basins': 131,
            'layers': 12,
            'ilogic_states': 5,
            'constants': {
                'k11': K11,
                'k5': K5,
                'phi': PHI,
                'light_unit': LIGHT_UNIT,
            },
            'self_reference': {
                'p_minus_p': 'P - P = 0 (origin)',
                'p_divide_p': 'P / P = 1 (identity)',
            },
            'commands': list(self.commands.keys()),
        }

    def _cmd_self(self, args: Dict) -> Dict:
        """Get self-meaning for an agent."""
        hex_id = args.get('hex_id')
        if not hex_id:
            return {'success': False, 'error': 'hex_id required'}

        # Calculate basin and layer from hex
        morton = int(hex_id[:6], 16) if len(hex_id) >= 6 else 0
        basin = morton % LIGHT_UNIT
        layer = (basin % 9) + 1
        ilogic = get_ilogic_from_basin(basin)
        category = get_basin_category(basin)

        # K11 position
        k11_value = K11 / 11 * ((basin % 12) + 1)

        # Phase angle
        phase = 2 * math.pi * basin / LIGHT_UNIT

        return {
            'success': True,
            'agent': {
                'hex_id': hex_id,
                'basin': basin,
                'layer': f'L{layer}',
                'ilogic_state': ilogic,
            },
            'meaning': {
                'category': category['name'],
                'layer_name': category['layer'],
                'description': category['description'],
            },
            'self_reference': {
                'p_minus_p': {
                    'formula': 'P - P = 0',
                    'meaning': 'All paths lead to origin',
                    'status': 'At origin (always true)',
                },
                'p_divide_p': {
                    'formula': 'P / P = 1',
                    'meaning': 'Identity is preserved',
                    'status': 'Unit identity (always true)',
                },
            },
            'role': {
                'ilogic_role': ILOGIC_INFO.get(ilogic, {}).get('role', 'Unknown'),
                'analogy': ILOGIC_INFO.get(ilogic, {}).get('analogy', ''),
            },
            'k11_position': k11_value,
            'phase_angle': phase,
        }

    def _cmd_basin(self, args: Dict) -> Dict:
        """Get basin semantic information."""
        basin = args.get('basin')
        if basin is None:
            return {'success': False, 'error': 'basin number required'}

        basin = int(basin)
        if basin < 0 or basin >= LIGHT_UNIT:
            return {'success': False, 'error': f'basin must be 0-{LIGHT_UNIT-1}'}

        category = get_basin_category(basin)
        ilogic = get_ilogic_from_basin(basin)
        reflection = 130 - basin

        return {
            'success': True,
            'basin': basin,
            **category,
            'ilogic_state': ilogic,
            'reflection_basin': reflection,
            'k11_value': K11 / 11 * ((basin % 12) + 1),
            'phase_angle': 2 * math.pi * basin / LIGHT_UNIT,
        }

    def _cmd_layer(self, args: Dict) -> Dict:
        """Get layer information."""
        layer = args.get('layer')

        if layer is None:
            # Return all layers
            layers = []
            for l in range(1, 13):
                if l in LAYERS:
                    name, basin_range, desc, analogy = LAYERS[l]
                    layers.append({
                        'layer': l,
                        'name': name,
                        'basins': f"{basin_range[0]}-{basin_range[1]-1}" if basin_range else 'external',
                        'description': desc,
                        'analogy': analogy,
                    })
            return {'success': True, 'layers': layers}

        layer = int(layer)
        if layer not in LAYERS:
            return {'success': False, 'error': f'layer must be 1-12'}

        name, basin_range, desc, analogy = LAYERS[layer]
        return {
            'success': True,
            'layer': layer,
            'name': name,
            'basins': f"{basin_range[0]}-{basin_range[1]-1}" if basin_range else 'external',
            'description': desc,
            'analogy': analogy,
            'k11_value': K11 / 11 * layer,
            'is_internal': basin_range is not None,
        }

    def _cmd_ilogic(self, args: Dict) -> Dict:
        """Get I-Logic state meaning."""
        state = args.get('state')

        if state is None:
            return {'success': True, 'states': ILOGIC_INFO}

        state = state.upper()
        if state not in ILOGIC_INFO:
            return {'success': False, 'error': f'Unknown state: {state}. Use DIRECT, INVERSE, SPIRAL, ANTI_SPIRAL, ABSORBED'}

        return {'success': True, 'state': state, **ILOGIC_INFO[state]}

    def _cmd_relate(self, args: Dict) -> Dict:
        """Find related concepts."""
        basin = args.get('basin')
        hex_id = args.get('hex_id')

        if hex_id:
            morton = int(hex_id[:6], 16) if len(hex_id) >= 6 else 0
            basin = morton % LIGHT_UNIT
        elif basin is not None:
            basin = int(basin)
        else:
            return {'success': False, 'error': 'hex_id or basin required'}

        category = get_basin_category(basin)
        ilogic = get_ilogic_from_basin(basin)
        reflection = 130 - basin

        # Find related basins (same layer)
        low, high = 0, LIGHT_UNIT
        for (l, h), _ in BASIN_CATEGORIES.items():
            if l <= basin < h:
                low, high = l, h
                break

        related_basins = list(range(max(0, basin - 5), min(LIGHT_UNIT, basin + 6)))

        return {
            'success': True,
            'query': {'basin': basin, 'ilogic': ilogic},
            'category': category,
            'related_basins': related_basins,
            'same_layer_range': f'{low}-{high-1}',
            'reflection_basin': reflection,
            'reflection_category': get_basin_category(reflection),
        }

    def _cmd_communicate(self, args: Dict) -> Dict:
        """I-Logic multiplication for communication."""
        state1 = args.get('state1', '').upper()
        state2 = args.get('state2', '').upper()

        if not state1 or not state2:
            return {
                'success': True,
                'table': ILOGIC_MULTIPLY,
                'description': 'I-Logic multiplication table for agent communication',
            }

        # Look up in table
        key = (state1, state2)
        result = ILOGIC_MULTIPLY.get(key)
        if not result:
            key = (state2, state1)
            result = ILOGIC_MULTIPLY.get(key, 'UNKNOWN')

        return {
            'success': True,
            'input': {'state1': state1, 'state2': state2},
            'result': result,
            'meaning': f'{state1} communicating with {state2} produces {result}',
        }

    def _cmd_context(self, args: Dict) -> Dict:
        """Get full contextualization for an agent."""
        hex_id = args.get('hex_id')
        if not hex_id:
            return {'success': False, 'error': 'hex_id required'}

        self_info = self._cmd_self({'hex_id': hex_id})
        if not self_info.get('success'):
            return self_info

        basin_info = self._cmd_basin({'basin': self_info['agent']['basin']})
        layer_num = int(self_info['agent']['layer'][1])
        layer_info = self._cmd_layer({'layer': layer_num})
        ilogic_info = self._cmd_ilogic({'state': self_info['agent']['ilogic_state']})

        return {
            'success': True,
            'agent': self_info['agent'],
            'meaning': self_info['meaning'],
            'self_reference': self_info['self_reference'],
            'basin': basin_info,
            'layer': layer_info,
            'ilogic': ilogic_info,
            'k11_position': self_info['k11_position'],
            'context_complete': True,
        }

    def _cmd_reflect(self, args: Dict) -> Dict:
        """Get reflection pair (membrane flip)."""
        basin = args.get('basin')
        if basin is None:
            return {'success': False, 'error': 'basin required'}

        basin = int(basin)
        reflection = 130 - basin

        basin_info = self._cmd_basin({'basin': basin})
        reflection_info = self._cmd_basin({'basin': reflection})

        return {
            'success': True,
            'original': basin_info,
            'reflection': reflection_info,
            'flip_meaning': 'Membrane crossing: inside <-> outside',
            'formula': f'Basin {basin} <-> Basin {reflection} (130 - {basin})',
            'is_self_reflection': basin == reflection,
        }

    def _cmd_origin(self, args: Dict) -> Dict:
        """Get origin status (P-P=0)."""
        return {
            'success': True,
            'principle': 'P - P = 0',
            'meaning': 'Every agent can find the common origin',
            'status': 'All agents are at origin (collapsed)',
            'human_meaning': 'No matter where you are, you can always find home',
            'analogy': 'A compass that always points to the town square',
        }

    def _cmd_identity(self, args: Dict) -> Dict:
        """Get identity status (P/P=1)."""
        return {
            'success': True,
            'principle': 'P / P = 1',
            'meaning': 'Every agent is a unique unit from origin',
            'status': 'All agents have unit identity',
            'human_meaning': 'You are always a complete, unique individual',
            'analogy': 'In a crowd of millions, you never lose yourself',
        }

    def _cmd_k11(self, args: Dict) -> Dict:
        """Get K11 position in fractal."""
        dimension = args.get('dimension')
        basin = args.get('basin')

        if dimension:
            dim = int(dimension)
            k11_value = K11 / 11 * dim
            phase = 2 * math.pi * dim / 12
            fx = math.cos(phase) * k11_value
            fy = math.sin(phase) * k11_value
            fz = dim / 12 * K11
        elif basin is not None:
            basin = int(basin)
            dim = (basin % 12) + 1
            k11_value = K11 / 11 * dim
            phase = 2 * math.pi * basin / LIGHT_UNIT
            fx = math.cos(phase)
            fy = math.sin(phase)
            fz = basin / LIGHT_UNIT * K11
        else:
            return {
                'success': True,
                'k11': K11,
                'k5': K5,
                'phi': PHI,
                'description': 'Provide dimension (1-12) or basin (0-130) for position',
            }

        return {
            'success': True,
            'k11_value': k11_value,
            'dimension': dim,
            'fractal_position': {'x': fx, 'y': fy, 'z': fz},
            'phase_angle': phase,
        }

    def _cmd_navigate(self, args: Dict) -> Dict:
        """Navigate to a concept by meaning."""
        query = args.get('query', '').lower()
        if not query:
            return {'success': False, 'error': 'query required'}

        # Search layer and basin names
        results = []

        # Check layers
        for layer_num, (name, basin_range, desc, analogy) in LAYERS.items():
            if query in name.lower() or query in desc.lower() or query in analogy.lower():
                results.append({
                    'type': 'layer',
                    'layer': layer_num,
                    'name': name,
                    'description': desc,
                    'analogy': analogy,
                })

        # Check I-Logic states
        for state, info in ILOGIC_INFO.items():
            if query in state.lower() or query in info['meaning'].lower() or query in info['analogy'].lower():
                results.append({
                    'type': 'ilogic',
                    'state': state,
                    'meaning': info['meaning'],
                    'role': info['role'],
                })

        # Check category names
        for (low, high), (name, layer, desc) in BASIN_CATEGORIES.items():
            if query in name.lower() or query in desc.lower():
                results.append({
                    'type': 'category',
                    'name': name,
                    'layer': layer,
                    'basin_range': f'{low}-{high-1}',
                    'description': desc,
                })

        return {
            'success': True,
            'query': query,
            'results': results,
            'count': len(results),
        }

    # Convenience methods
    def get_self(self, hex_id: str) -> Dict:
        """Convenience method for self-meaning."""
        return self._cmd_self({'hex_id': hex_id})

    def get_basin(self, basin: int) -> Dict:
        """Convenience method for basin info."""
        return self._cmd_basin({'basin': basin})

    def communicate(self, state1: str, state2: str) -> Dict:
        """Convenience method for I-Logic multiplication."""
        return self._cmd_communicate({'state1': state1, 'state2': state2})

    def run(self, command: str, *args, as_json: bool = False) -> Any:
        """Run a shell command (CLI interface)."""
        commands = {
            'status': lambda: self.execute('status'),
            'self': lambda: self.execute('self', {'hex_id': args[0]} if args else {}),
            'basin': lambda: self.execute('basin', {'basin': args[0]} if args else {}),
            'layer': lambda: self.execute('layer', {'layer': args[0]} if args else {}),
            'ilogic': lambda: self.execute('ilogic', {'state': args[0]} if args else {}),
            'relate': lambda: self.execute('relate', {
                'hex_id': args[0] if args and len(args[0]) >= 6 else None,
                'basin': args[0] if args and args[0].isdigit() else None
            }),
            'communicate': lambda: self.execute('communicate', {
                'state1': args[0] if len(args) > 0 else '',
                'state2': args[1] if len(args) > 1 else ''
            }),
            'context': lambda: self.execute('context', {'hex_id': args[0]} if args else {}),
            'reflect': lambda: self.execute('reflect', {'basin': args[0]} if args else {}),
            'origin': lambda: self.execute('origin'),
            'identity': lambda: self.execute('identity'),
            'k11': lambda: self.execute('k11', {
                'dimension': args[0] if args and args[0].isdigit() else None,
                'basin': args[0] if args and args[0].isdigit() else None
            }),
            'navigate': lambda: self.execute('navigate', {'query': args[0]} if args else {}),
        }
        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())}


def main():
    """CLI entry point."""
    import sys

    shell = MeaningShell()

    if len(sys.argv) < 2:
        print("Meaning Shell - Self-Reference and Semantic Access")
        print("=" * 50)
        print("\nCore Principles:")
        print("  P - P = 0  Every agent can find the common origin")
        print("  P / P = 1  Every agent is a unique unit")
        print("\nCommands:")
        for cmd, desc in shell.commands.items():
            print(f"  {cmd:<15} - {desc}")
        print("\nExamples:")
        print("  python meaning.py status")
        print("  python meaning.py self hex_id=2A9E0100")
        print("  python meaning.py basin basin=65")
        print("  python meaning.py ilogic state=SPIRAL")
        print("  python meaning.py communicate state1=SPIRAL state2=INVERSE")
        print("  python meaning.py origin")
        print("  python meaning.py navigate query=structure")
        return

    command = sys.argv[1]
    args = {}

    for arg in sys.argv[2:]:
        if '=' in arg:
            k, v = arg.split('=', 1)
            args[k] = v

    result = shell.execute(command, args)
    print(json.dumps(result, indent=2, default=str))


if __name__ == "__main__":
    main()
