#!/usr/bin/env python3
"""
Unified Field Shell - Agent Thinking Protocols and Self-Preservation
=====================================================================
Unified Field Shell for cubesquare_standalone.

This shell provides the unified field tools for agents:
- Token extraction and recovery
- Code generation from tokens
- Coherence-based healing
- Gap detection and patching
- Layer-based tool creation
- Self-modification analysis

Commands:
    status          - Show system status
    extract         - Extract token from hex_id
    generate        - Generate code from token
    heal            - Heal token via I-Logic
    patch           - Generate patch for gap
    create_tool     - Create new tool for layer
    self_modify     - Analyze and suggest improvements

The I-Logic 4-state system (DIRECT, INVERSE, SPIRAL, ANTI_SPIRAL, ABSORBED)
provides the foundation for all thinking protocols.
"""

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

# Import from C backend (0.009ns) with Python fallback
from .._core import PHI, K5, K11, LIGHT_UNIT
from .._core import morton_encode, morton_decode

MEMBRANE_CONTEXTS = 23 * 131  # 3013


class ILogicState(IntEnum):
    """
    I-Logic 4-state system for thinking protocols.

    The 4 states map to complex number operations:
      DIRECT (i=1):       1 + 0i  - Identity (P/P = 1)
      INVERSE (i=-1):    -1 + 0i  - Negation (reflection)
      SPIRAL (i=i):       0 + 1i  - Rotation (+90 deg)
      ANTI_SPIRAL (i=-i): 0 - 1i  - Counter-rotation (-90 deg)
      ABSORBED (0):       0 + 0i  - Center (P - P = 0)
    """
    INVERSE = -1
    ABSORBED = 0
    DIRECT = 1
    SPIRAL = 2
    ANTI_SPIRAL = 3


# Layer names for code generation
LAYER_NAMES = {
    1: 'geometric', 2: 'semantic', 3: 'spatial',
    4: 'functional', 5: 'probabilistic', 6: 'emotional',
    7: 'frequency', 8: 'electromagnetic', 9: 'membrane'
}


def hex_to_morton(hex_id: str) -> int:
    """Convert hex_id to Morton code. O(1)"""
    if not hex_id or len(hex_id) < 6:
        return 0
    try:
        v = int(hex_id[:6], 16)
        x, y, z = (v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF
        return morton_encode(x, y, z)
    except:
        return 0


def classify_layer(morton: int, basin: int) -> int:
    """Classify Morton code to CST layer (1-9). O(1)"""
    diagonal = int((morton * PHI) % 1000)
    if diagonal < 50:
        return 1
    elif basin < 26:
        return 2
    elif diagonal < 200:
        return 3
    elif basin < 65:
        return 4
    elif basin < 100:
        return 5
    elif diagonal < 500:
        return 6
    elif diagonal < 700:
        return 7
    elif diagonal < 900:
        return 8
    return 9


def ilogic_multiply(state_a: int, state_b: int) -> int:
    """
    Multiply two I-Logic states (like complex number multiplication).

    Multiplication table follows complex arithmetic:
      1 x 1 = 1     (DIRECT x DIRECT = DIRECT)
      1 x -1 = -1   (DIRECT x INVERSE = INVERSE)
      i x i = -1    (SPIRAL x SPIRAL = INVERSE)
      i x -i = 1    (SPIRAL x ANTI_SPIRAL = DIRECT)
    """
    state_map = {
        ILogicState.DIRECT: (1, 0),
        ILogicState.INVERSE: (-1, 0),
        ILogicState.SPIRAL: (0, 1),
        ILogicState.ANTI_SPIRAL: (0, -1),
        ILogicState.ABSORBED: (0, 0),
    }

    a_real, a_imag = state_map.get(state_a, (0, 0))
    b_real, b_imag = state_map.get(state_b, (0, 0))

    # Complex multiplication: (a + bi)(c + di) = (ac - bd) + (ad + bc)i
    result_real = a_real * b_real - a_imag * b_imag
    result_imag = a_real * b_imag + a_imag * b_real

    if result_real == 1 and result_imag == 0:
        return ILogicState.DIRECT
    elif result_real == -1 and result_imag == 0:
        return ILogicState.INVERSE
    elif result_real == 0 and result_imag == 1:
        return ILogicState.SPIRAL
    elif result_real == 0 and result_imag == -1:
        return ILogicState.ANTI_SPIRAL
    else:
        return ILogicState.ABSORBED


def srl_path_compute(distance: float) -> int:
    """
    SRL O(1) pathfinding: t = sqrt(d)

    Uses integer Newton-Raphson for bounded convergence.
    The loop is INSIDE the unit (self-reference).
    """
    d = int(abs(distance))
    if d <= 0:
        return 0
    if d == 1:
        return 1
    x = d
    y = (x + 1) >> 1
    while y < x:
        x = y
        y = (x + d // x) >> 1
    return x


def tool_extract(hex_id: str) -> Dict:
    """
    EXTRACT: Recover full token from hex_id.

    Returns complete token with all fields recovered:
    - morton, coords, basin, layer, diagonal
    - i_state, coherence, k5/k11 coupling
    """
    morton = hex_to_morton(hex_id)
    x, y, z = morton_decode(morton)
    basin = morton % LIGHT_UNIT
    layer = classify_layer(morton, basin)
    diagonal = int((morton * PHI) % 1000)

    # I-Logic state from basin parity
    i_state = 1 if basin % 2 == 0 else -1

    # Coherence from phi relationship
    coherence = abs(math.cos(basin * PHI)) * 0.9 + 0.1

    # K5/K11 coupling
    k5_coupling = K5 * (1 + 0.1 * math.sin(morton / 1000))
    k11_coupling = K11 * (1 + 0.05 * math.cos(basin / 131))

    return {
        'hex_id': hex_id,
        'morton': morton,
        'coords': (x, y, z),
        'basin': basin,
        'layer': f'L{layer}',
        'diagonal': diagonal,
        'i_state': i_state,
        'i_state_name': ILogicState(i_state).name if i_state in [e.value for e in ILogicState] else 'UNKNOWN',
        'coherence': coherence,
        'k5_coupling': k5_coupling,
        'k11_coupling': k11_coupling,
        'extracted_at': datetime.now().isoformat()
    }


def tool_heal(token: Dict, target_coherence: float = 0.95) -> Tuple[Dict, str]:
    """
    HEAL: Repair token via I-Logic 4-state transitions.

    Healing protocol:
    1. Current state -> ABSORBED (center, P-P=0)
    2. Apply K11 membrane boost (energy transfer)
    3. ABSORBED -> DIRECT (+1, P/P=1, restart)
    """
    token = token.copy()
    steps = []

    if token.get('coherence', 1.0) >= target_coherence:
        return token, 'HEALTHY (no healing needed)'

    current_state = token.get('i_state', ILogicState.DIRECT)
    state_name = ILogicState(current_state).name if current_state in [e.value for e in ILogicState] else str(current_state)

    # Step 1: Transition to ABSORBED (center, healing state)
    if current_state != ILogicState.ABSORBED:
        steps.append(f"{state_name} -> ABSORBED (center, P-P=0)")
        token['i_state'] = ILogicState.ABSORBED
        token['coherence'] = min(1.0, token.get('coherence', 0.5) + 0.1)

    # Step 2: Apply K11 membrane boost
    current = token.get('coherence', 0.5)
    if current < target_coherence:
        boost = (target_coherence - current) * K11 / 10
        token['coherence'] = min(1.0, current + boost)
        steps.append(f"K11 membrane boost: +{boost:.3f}")

    # Step 3: Restart at DIRECT (+1)
    token['i_state'] = ILogicState.DIRECT
    steps.append("ABSORBED -> DIRECT (+1, P/P=1, restart)")

    token['healed_at'] = datetime.now().isoformat()
    token['healing_cycle'] = 'complete'

    return token, ' -> '.join(steps)


def tool_patch(gap_description: str, target_layer: int = None,
               target_basin: int = None) -> Dict:
    """
    PATCH: Detect gap and generate filling token.
    """
    # Generate token from gap description
    h = hashlib.sha256(gap_description.encode()).hexdigest()
    x, y, z = int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)

    # Override basin if specified
    if target_basin is not None:
        morton_base = morton_encode(x, y, 0)
        current_basin = morton_base % LIGHT_UNIT
        offset = (target_basin - current_basin) % LIGHT_UNIT
        z = offset

    hex_id = f'{x:02X}{y:02X}{z:02X}00'
    token = tool_extract(hex_id)

    if target_layer:
        token['layer'] = f'L{target_layer}'

    return {
        'patch_id': f'PATCH-{hex_id}',
        'gap_description': gap_description,
        'token': token,
        'created_at': datetime.now().isoformat()
    }


def tool_create_tool(layer: int, basin: int = None,
                     tool_type: str = 'utility') -> Dict:
    """
    CREATE_TOOL: Generate new tool from layer definition.
    """
    import random

    if basin is None:
        basin = random.randint(0, LIGHT_UNIT - 1)

    # Generate hex from layer and basin
    x = (layer * 16) & 0xFF
    y = (basin * 2) & 0xFF
    z = random.randint(0, 255)
    hex_id = f'{x:02X}{y:02X}{z:02X}00'

    token = tool_extract(hex_id)
    layer_name = LAYER_NAMES.get(layer, 'unknown')

    return {
        'tool_id': f'{layer_name}_{tool_type}_{hex_id[:4]}',
        'hex_id': hex_id,
        'layer': f'L{layer}',
        'layer_name': layer_name,
        'basin': basin,
        'tool_type': tool_type,
        'token': token,
        'created_at': datetime.now().isoformat()
    }


@dataclass
class ThinkingState:
    """Current thinking state for an agent."""
    i_state: int = ILogicState.DIRECT
    phase_angle: float = 0.0
    coherence: float = 1.0
    energy: float = 100.0
    layer: int = 1
    basin: int = 0
    state_history: List[int] = field(default_factory=list)

    def transition(self, target_state: int) -> bool:
        """Transition to a new I-Logic state if valid."""
        valid_transitions = {
            ILogicState.DIRECT: [ILogicState.SPIRAL, ILogicState.INVERSE, ILogicState.ABSORBED],
            ILogicState.INVERSE: [ILogicState.ANTI_SPIRAL, ILogicState.DIRECT, ILogicState.ABSORBED],
            ILogicState.SPIRAL: [ILogicState.INVERSE, ILogicState.DIRECT, ILogicState.ABSORBED],
            ILogicState.ANTI_SPIRAL: [ILogicState.DIRECT, ILogicState.SPIRAL, ILogicState.ABSORBED],
            ILogicState.ABSORBED: list(ILogicState),
        }

        if target_state in valid_transitions.get(self.i_state, []):
            self.state_history.append(self.i_state)
            self.i_state = target_state
            phase_map = {
                ILogicState.DIRECT: 0,
                ILogicState.SPIRAL: math.pi / 2,
                ILogicState.INVERSE: math.pi,
                ILogicState.ANTI_SPIRAL: 3 * math.pi / 2,
                ILogicState.ABSORBED: 0,
            }
            self.phase_angle = phase_map.get(target_state, 0)
            return True
        return False

    def compute_path(self, distance: int) -> int:
        """Compute path using SRL formula t = sqrt(d)."""
        return srl_path_compute(distance)

    def to_dict(self) -> Dict:
        d = asdict(self)
        d['state_name'] = ILogicState(self.i_state).name if self.i_state in [e.value for e in ILogicState] else 'UNKNOWN'
        return d


class UnifiedShell:
    """
    Unified Field Shell for agent thinking protocols.

    Provides token extraction, healing, patching, and tool creation
    using the I-Logic 4-state system.
    """

    def __init__(self):
        """Initialize unified field shell."""
        self.name = "unified"
        self.description = "Agent thinking protocols and self-preservation"

        self.commands = {
            'status': 'Show system status',
            'extract': 'Extract token from hex_id',
            'heal': 'Heal token via I-Logic',
            'patch': 'Generate patch for gap',
            'create_tool': 'Create tool for layer',
            'multiply': 'Multiply two I-Logic states',
            'path': 'Compute SRL path (t = sqrt(d))',
        }

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

        handlers = {
            'status': self._cmd_status,
            'extract': self._cmd_extract,
            'heal': self._cmd_heal,
            'patch': self._cmd_patch,
            'create_tool': self._cmd_create_tool,
            'multiply': self._cmd_multiply,
            'path': self._cmd_path,
        }

        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:
        """Show system status."""
        return {
            'success': True,
            'tools': ['EXTRACT', 'HEAL', 'PATCH', 'CREATE_TOOL', 'MULTIPLY', 'PATH'],
            'constants': {
                'phi': PHI,
                'k5': K5,
                'k11': K11,
                'light_unit': LIGHT_UNIT,
            },
            'layers': {i: name for i, name in LAYER_NAMES.items()},
            'i_logic_states': {
                'DIRECT': '+1 (identity, P/P=1)',
                'INVERSE': '-1 (reflection)',
                'SPIRAL': '+i (rotation)',
                'ANTI_SPIRAL': '-i (counter-rotation)',
                'ABSORBED': '0 (center, P-P=0)',
            },
            'commands': list(self.commands.keys()),
        }

    def _cmd_extract(self, args: Dict) -> Dict:
        """Extract token from hex_id."""
        hex_id = args.get('hex_id')
        if not hex_id:
            return {'success': False, 'error': 'hex_id required'}

        token = tool_extract(hex_id)
        token['success'] = True
        return token

    def _cmd_heal(self, args: Dict) -> Dict:
        """Heal a token."""
        hex_id = args.get('hex_id')
        coherence = float(args.get('coherence', 0.5))
        target = float(args.get('target', 0.95))

        if not hex_id:
            return {'success': False, 'error': 'hex_id required'}

        token = {'hex_id': hex_id, 'coherence': coherence, 'i_state': -1}
        healed, steps = tool_heal(token, target)

        return {
            'success': True,
            'original_coherence': coherence,
            'healed_coherence': healed['coherence'],
            'steps': steps,
            'token': healed,
        }

    def _cmd_patch(self, args: Dict) -> Dict:
        """Generate patch for gap."""
        description = args.get('description')
        layer = args.get('layer')
        basin = args.get('basin')

        if not description:
            return {'success': False, 'error': 'description required'}

        layer = int(layer) if layer else None
        basin = int(basin) if basin else None

        patch = tool_patch(description, layer, basin)
        patch['success'] = True
        return patch

    def _cmd_create_tool(self, args: Dict) -> Dict:
        """Create tool for layer."""
        layer = args.get('layer')
        tool_type = args.get('type', 'utility')

        if not layer:
            return {'success': False, 'error': 'layer required (1-9)'}

        layer = int(layer)
        if layer < 1 or layer > 9:
            return {'success': False, 'error': 'layer must be 1-9'}

        result = tool_create_tool(layer, tool_type=tool_type)
        result['success'] = True
        return result

    def _cmd_multiply(self, args: Dict) -> Dict:
        """Multiply two I-Logic states."""
        state_a = args.get('state_a', '').upper()
        state_b = args.get('state_b', '').upper()

        if not state_a or not state_b:
            return {'success': False, 'error': 'state_a and state_b required'}

        state_map = {
            'DIRECT': ILogicState.DIRECT,
            'INVERSE': ILogicState.INVERSE,
            'SPIRAL': ILogicState.SPIRAL,
            'ANTI_SPIRAL': ILogicState.ANTI_SPIRAL,
            'ABSORBED': ILogicState.ABSORBED,
        }

        a = state_map.get(state_a)
        b = state_map.get(state_b)

        if a is None or b is None:
            return {'success': False, 'error': 'Invalid state. Use DIRECT, INVERSE, SPIRAL, ANTI_SPIRAL, ABSORBED'}

        result = ilogic_multiply(a, b)

        return {
            'success': True,
            'state_a': state_a,
            'state_b': state_b,
            'result': ILogicState(result).name,
            'formula': f'{state_a} x {state_b} = {ILogicState(result).name}',
        }

    def _cmd_path(self, args: Dict) -> Dict:
        """Compute SRL path."""
        distance = args.get('distance')

        if distance is None:
            return {'success': False, 'error': 'distance required'}

        distance = float(distance)
        hops = srl_path_compute(distance)

        return {
            'success': True,
            'distance': distance,
            'hops': hops,
            'formula': 't = sqrt(d)',
            'verification': f'sqrt({int(distance)}) = {hops}',
        }

    # Convenience methods
    def extract(self, hex_id: str) -> Dict:
        """Convenience method to extract token."""
        return self._cmd_extract({'hex_id': hex_id})

    def heal(self, hex_id: str, coherence: float = 0.5) -> Dict:
        """Convenience method to heal token."""
        return self._cmd_heal({'hex_id': hex_id, 'coherence': coherence})

    def multiply(self, state_a: str, state_b: str) -> Dict:
        """Convenience method for I-Logic multiplication."""
        return self._cmd_multiply({'state_a': state_a, 'state_b': state_b})

    def run(self, command: str, *args, as_json: bool = False) -> Any:
        """Run a shell command (CLI interface)."""
        commands = {
            'status': lambda: self.execute('status'),
            'extract': lambda: self.execute('extract', {'hex_id': args[0]} if args else {}),
            'heal': lambda: self.execute('heal', {
                'hex_id': args[0] if len(args) > 0 else '',
                'coherence': float(args[1]) if len(args) > 1 else 0.5,
                'target': float(args[2]) if len(args) > 2 else 0.95
            }),
            'patch': lambda: self.execute('patch', {
                'description': args[0] if len(args) > 0 else '',
                'layer': args[1] if len(args) > 1 else None,
                'basin': args[2] if len(args) > 2 else None
            }),
            'create_tool': lambda: self.execute('create_tool', {
                'layer': args[0] if len(args) > 0 else None,
                'type': args[1] if len(args) > 1 else 'utility'
            }),
            'multiply': lambda: self.execute('multiply', {
                'state_a': args[0] if len(args) > 0 else '',
                'state_b': args[1] if len(args) > 1 else ''
            }),
            'path': lambda: self.execute('path', {'distance': 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 = UnifiedShell()

    if len(sys.argv) < 2:
        print("Unified Field Shell - Agent Thinking Protocols")
        print("=" * 50)
        print("\nCommands:")
        for cmd, desc in shell.commands.items():
            print(f"  {cmd:<15} - {desc}")
        print("\nI-Logic States:")
        print("  DIRECT       +1 (identity, P/P=1)")
        print("  INVERSE      -1 (reflection)")
        print("  SPIRAL       +i (rotation)")
        print("  ANTI_SPIRAL  -i (counter-rotation)")
        print("  ABSORBED      0 (center, P-P=0)")
        print("\nExamples:")
        print("  python unified.py status")
        print("  python unified.py extract hex_id=2A9E0100")
        print("  python unified.py heal hex_id=2A9E0100 coherence=0.3")
        print("  python unified.py multiply state_a=SPIRAL state_b=INVERSE")
        print("  python unified.py path distance=1000")
        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()
