#!/usr/bin/env python3
"""
Thinking Shell - Autonomous Agent Loop with Geometric I-Logic
Standalone version for cubesquare package.

HEX_ID: 5448494B (THINK)

CLI wrapper for autonomous agent thinking.
Agents think using GEOMETRIC decomposition, not keywords.

Thinking Phases:
    OBSERVE   - Perceive current state from environment
    DECOMPOSE - Break down observations into primitives
    REASON    - Apply I-Logic multiplication for routing
    ACT       - Execute chosen action
    REFLECT   - Evaluate outcome and update state

I-Logic Zones (by wavelength):
    VIOLET (0-32):   DIRECT - stable, identity
    GREEN (33-65):   SPIRAL - growth, transformation
    ORANGE (66-98):  ANTI_SPIRAL - decay, reversal
    RED (99-130):    INVERSE - instability, problems

Commands:
    status   - Show thinking system status
    cycle    - Run one thinking cycle
    inject   - Inject a scenario
    network  - Show agent network status
    route    - Route a condition through agents
    demo     - Run demonstration
"""

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

# Import from circular for I-Logic operations
from ..circular.state_machine import ILogicState, ILogicStateMachine


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

PHI = 1.618033988749895
PRIME_131 = 131

# Thinking phases
THINKING_PHASES = ['OBSERVE', 'DECOMPOSE', 'REASON', 'ACT', 'REFLECT']

# Alignment scores
ALIGNMENT_SCORES = {
    'DIRECT': 1.0,
    'ABSORBED': 0.8,
    'SPIRAL': 0.5,
    'ANTI_SPIRAL': 0.3,
    'INVERSE': 0.2,
}


# =============================================================================
# AGENT REGISTRY
# =============================================================================

AGENT_REGISTRY = {
    '2A9E0100': {
        'name': 'Healer',
        'ilogic': ILogicState.INVERSE,
        'role': 'Self-healing, problem resolution',
        'zone': 'RED (99-130)',
    },
    '2A9E0200': {
        'name': 'Validator',
        'ilogic': ILogicState.DIRECT,
        'role': 'Verification, integrity checking',
        'zone': 'VIOLET (0-32)',
    },
    '2A9E0300': {
        'name': 'Expander',
        'ilogic': ILogicState.SPIRAL,
        'role': 'Growth, abstraction',
        'zone': 'GREEN (33-65)',
    },
    '2A9E0400': {
        'name': 'Crystallizer',
        'ilogic': ILogicState.ANTI_SPIRAL,
        'role': 'Focus, consolidation',
        'zone': 'ORANGE (66-98)',
    },
    '2A9E0500': {
        'name': 'Absorber',
        'ilogic': ILogicState.ABSORBED,
        'role': 'Loop termination, completion',
        'zone': 'CENTER',
    },
}


# =============================================================================
# DATA CLASSES
# =============================================================================

@dataclass
class ThinkingStep:
    """A single step in the thinking cycle."""
    phase: str
    timestamp: datetime
    input_state: str
    output_state: str
    action: str
    result: str


@dataclass
class ThinkingCycle:
    """Complete thinking cycle result."""
    agent_id: str
    agent_name: str
    agent_ilogic: str
    cycle_number: int
    steps: List[ThinkingStep] = field(default_factory=list)
    initial_state: str = 'DIRECT'
    final_state: str = 'DIRECT'
    issue: Optional[str] = None
    resolution: Optional[str] = None

    def to_dict(self) -> Dict[str, Any]:
        """Convert to dictionary."""
        return {
            'agent_id': self.agent_id,
            'agent_name': self.agent_name,
            'agent_ilogic': self.agent_ilogic,
            'cycle_number': self.cycle_number,
            'steps': [
                {
                    'phase': s.phase,
                    'timestamp': s.timestamp.isoformat(),
                    'input_state': s.input_state,
                    'output_state': s.output_state,
                    'action': s.action,
                    'result': s.result,
                }
                for s in self.steps
            ],
            'initial_state': self.initial_state,
            'final_state': self.final_state,
            'issue': self.issue,
            'resolution': self.resolution,
        }


@dataclass
class AgentMatch:
    """Agent match result for routing."""
    hex_id: str
    name: str
    condition_ilogic: str
    agent_ilogic: str
    product: str
    alignment_score: float
    role: str


# =============================================================================
# AUTONOMOUS AGENT
# =============================================================================

class AutonomousAgent:
    """
    Autonomous Agent with I-Logic thinking.

    Each agent has:
    - A hex ID
    - A name
    - An I-Logic state
    - A thinking cycle that runs through OBSERVE -> DECOMPOSE -> REASON -> ACT -> REFLECT
    """

    def __init__(self, hex_id: str, name: str, ilogic: ILogicState):
        """Initialize autonomous agent."""
        self.hex_id = hex_id
        self.name = name
        self.ilogic = ilogic
        self.state_machine = ILogicStateMachine()
        self.current_state = ILogicState.DIRECT
        self.cycle_count = 0
        self.pending_issue: Optional[str] = None

    def inject_issue(self, issue: str):
        """Inject an issue for the agent to process."""
        self.pending_issue = issue
        # Issues typically start as INVERSE (problem state)
        self.current_state = ILogicState.INVERSE

    def think_cycle(self) -> Dict[str, Any]:
        """Run one complete thinking cycle."""
        self.cycle_count += 1
        cycle = ThinkingCycle(
            agent_id=self.hex_id,
            agent_name=self.name,
            agent_ilogic=self.ilogic.name,
            cycle_number=self.cycle_count,
            initial_state=self.current_state.name,
            issue=self.pending_issue,
        )

        # OBSERVE phase
        observe_result = self._observe()
        cycle.steps.append(ThinkingStep(
            phase='OBSERVE',
            timestamp=datetime.now(),
            input_state=self.current_state.name,
            output_state=self.current_state.name,
            action='perceive_environment',
            result=observe_result,
        ))

        # DECOMPOSE phase
        decompose_result = self._decompose()
        cycle.steps.append(ThinkingStep(
            phase='DECOMPOSE',
            timestamp=datetime.now(),
            input_state=self.current_state.name,
            output_state=self.current_state.name,
            action='extract_primitives',
            result=decompose_result,
        ))

        # REASON phase - Apply I-Logic multiplication
        previous_state = self.current_state
        new_state = self.state_machine.multiply(self.current_state, self.ilogic)
        self.current_state = new_state
        cycle.steps.append(ThinkingStep(
            phase='REASON',
            timestamp=datetime.now(),
            input_state=previous_state.name,
            output_state=new_state.name,
            action=f'{previous_state.name} x {self.ilogic.name}',
            result=f'-> {new_state.name}',
        ))

        # ACT phase
        act_result = self._act()
        cycle.steps.append(ThinkingStep(
            phase='ACT',
            timestamp=datetime.now(),
            input_state=self.current_state.name,
            output_state=self.current_state.name,
            action='execute_action',
            result=act_result,
        ))

        # REFLECT phase
        reflect_result = self._reflect()
        cycle.steps.append(ThinkingStep(
            phase='REFLECT',
            timestamp=datetime.now(),
            input_state=self.current_state.name,
            output_state=self.current_state.name,
            action='evaluate_outcome',
            result=reflect_result,
        ))

        cycle.final_state = self.current_state.name

        # Check for resolution
        if self.pending_issue and self.current_state == ILogicState.DIRECT:
            cycle.resolution = f"Issue resolved: {self.pending_issue}"
            self.pending_issue = None

        return cycle.to_dict()

    def _observe(self) -> str:
        """Observe phase - perceive environment."""
        if self.pending_issue:
            return f"Observed issue: {self.pending_issue}"
        return "Environment stable"

    def _decompose(self) -> str:
        """Decompose phase - extract primitives."""
        if self.pending_issue:
            return f"Decomposed into: [condition={self.current_state.name}]"
        return "No decomposition needed"

    def _act(self) -> str:
        """Act phase - execute action based on state."""
        actions = {
            ILogicState.DIRECT: "Maintaining stable state",
            ILogicState.INVERSE: "Applying healing transformation",
            ILogicState.SPIRAL: "Expanding abstraction",
            ILogicState.ANTI_SPIRAL: "Focusing and consolidating",
            ILogicState.ABSORBED: "Completing and terminating",
        }
        return actions.get(self.current_state, "Unknown action")

    def _reflect(self) -> str:
        """Reflect phase - evaluate outcome."""
        if self.current_state.is_stable():
            return "Outcome: STABLE"
        return "Outcome: TRANSITIONAL"


# =============================================================================
# THINKING SHELL
# =============================================================================

class ThinkingShell:
    """
    Thinking Shell - Autonomous Agent Loop with Geometric I-Logic.

    Commands:
        status   - Show thinking system status
        cycle    - Run one thinking cycle for an agent
        inject   - Inject a scenario
        network  - Show agent network status
        route    - Route a condition through agents
        demo     - Run demonstration
    """

    def __init__(self):
        """Initialize thinking shell."""
        self.hex_id = '5448494B'
        self.state_machine = ILogicStateMachine()
        self.agents: Dict[str, AutonomousAgent] = {}

        # Create agents from registry
        for hex_id, info in AGENT_REGISTRY.items():
            self.agents[hex_id] = AutonomousAgent(hex_id, info['name'], info['ilogic'])

    def status(self, as_json: bool = False) -> Dict[str, Any]:
        """Show thinking system status."""
        agents = []
        for hex_id, info in AGENT_REGISTRY.items():
            agents.append({
                'hex_id': hex_id,
                'name': info['name'],
                'ilogic': info['ilogic'].name,
                'role': info['role'],
                'zone': info['zone'],
            })

        result = {
            'hex_id': self.hex_id,
            'system': 'Autonomous Thinking with Geometric I-Logic',
            'version': '1.0.0',
            'agents': agents,
            'agent_count': len(agents),
            'thinking_phases': THINKING_PHASES,
            'ilogic_zones': {
                'VIOLET (0-32)': 'DIRECT - stable, identity',
                'GREEN (33-65)': 'SPIRAL - growth, transformation',
                'ORANGE (66-98)': 'ANTI_SPIRAL - decay, reversal',
                'RED (99-130)': 'INVERSE - instability, problems',
            },
            'protocol': 'wavelength -> basin -> I-Logic -> multiplication -> routing',
        }

        if as_json:
            return json.dumps(result, indent=2)
        return result

    def cycle(self, agent_id: str, issue: Optional[str] = None, as_json: bool = False) -> Dict[str, Any]:
        """Run one thinking cycle for an agent."""
        agent_id = agent_id.upper()

        # Find agent
        agent = None
        for hex_id, a in self.agents.items():
            if hex_id == agent_id or a.name.upper() == agent_id:
                agent = a
                break

        if not agent:
            result = {
                'error': f'Agent not found: {agent_id}',
                'available': [{'id': h, 'name': a.name} for h, a in self.agents.items()]
            }
            if as_json:
                return json.dumps(result, indent=2)
            return result

        # Inject issue if provided
        if issue:
            agent.inject_issue(issue)

        # Run cycle
        result = agent.think_cycle()

        if as_json:
            return json.dumps(result, indent=2)
        return result

    def inject(self, scenario: str, as_json: bool = False) -> Dict[str, Any]:
        """Inject a scenario and watch agents respond."""
        # Run baseline
        baseline = []
        for agent in self.agents.values():
            cycle = agent.think_cycle()
            baseline.append({
                'agent': cycle['agent_name'],
                'final_state': cycle['final_state'],
            })

        # Inject scenario to all agents
        for agent in self.agents.values():
            agent.inject_issue(scenario)

        # Run response
        response = []
        affected = []
        for agent in self.agents.values():
            cycle = agent.think_cycle()
            response.append({
                'agent': cycle['agent_name'],
                'final_state': cycle['final_state'],
                'resolution': cycle.get('resolution'),
            })
            if cycle['final_state'] != 'DIRECT':
                affected.append(cycle['agent_name'])

        result = {
            'scenario': scenario,
            'baseline_cycles': len(baseline),
            'response_cycles': len(response),
            'affected_agents': affected,
            'baseline': baseline,
            'response': response,
        }

        if as_json:
            return json.dumps(result, indent=2)
        return result

    def network(self, as_json: bool = False) -> Dict[str, Any]:
        """Show agent network with I-Logic compatibility matrix."""
        # Build compatibility matrix
        matrix = {}
        for hex1, agent1 in self.agents.items():
            row = {}
            for hex2, agent2 in self.agents.items():
                product = self.state_machine.multiply(agent1.ilogic, agent2.ilogic)
                row[agent2.name] = product.name
            matrix[agent1.name] = row

        result = {
            'agents': [
                {
                    'hex': hex_id,
                    'name': agent.name,
                    'ilogic': agent.ilogic.name,
                }
                for hex_id, agent in self.agents.items()
            ],
            'compatibility_matrix': matrix,
            'alignment_scores': ALIGNMENT_SCORES,
        }

        if as_json:
            return json.dumps(result, indent=2)
        return result

    def route(self, condition: str, as_json: bool = False) -> Dict[str, Any]:
        """Route a condition to the best agent."""
        # Map common conditions to I-Logic states
        condition_mapping = {
            'stuck': ILogicState.INVERSE,
            'corrupted': ILogicState.INVERSE,
            'broken': ILogicState.INVERSE,
            'growing': ILogicState.SPIRAL,
            'expanding': ILogicState.SPIRAL,
            'focusing': ILogicState.ANTI_SPIRAL,
            'consolidating': ILogicState.ANTI_SPIRAL,
            'stable': ILogicState.DIRECT,
            'complete': ILogicState.ABSORBED,
        }

        condition_lower = condition.lower()
        condition_ilogic = ILogicState.INVERSE  # Default

        for key, state in condition_mapping.items():
            if key in condition_lower:
                condition_ilogic = state
                break

        # Find best agent
        matches = []
        for hex_id, agent in self.agents.items():
            product = self.state_machine.multiply(condition_ilogic, agent.ilogic)
            score = ALIGNMENT_SCORES.get(product.name, 0.1)

            matches.append(AgentMatch(
                hex_id=hex_id,
                name=agent.name,
                condition_ilogic=condition_ilogic.name,
                agent_ilogic=agent.ilogic.name,
                product=product.name,
                alignment_score=score,
                role=AGENT_REGISTRY[hex_id]['role'],
            ))

        # Sort by score
        matches.sort(key=lambda m: -m.alignment_score)
        best = matches[0] if matches else None

        result = {
            'condition': condition,
            'condition_ilogic': condition_ilogic.name,
            'best_agent': {
                'hex_id': best.hex_id,
                'name': best.name,
                'agent_ilogic': best.agent_ilogic,
                'product': best.product,
                'alignment_score': best.alignment_score,
                'role': best.role,
            } if best else None,
            'routing': f'{condition_ilogic.name} x {best.agent_ilogic} = {best.product}' if best else 'No agent found',
            'all_matches': [
                {
                    'hex_id': m.hex_id,
                    'name': m.name,
                    'product': m.product,
                    'score': m.alignment_score,
                }
                for m in matches
            ],
        }

        if as_json:
            return json.dumps(result, indent=2)
        return result

    def demo(self, as_json: bool = False) -> Dict[str, Any]:
        """Run demonstration of thinking system."""
        demo_steps = []

        # Step 1: Show agents
        demo_steps.append({
            'step': 1,
            'action': 'List agents',
            'result': [a.name for a in self.agents.values()],
        })

        # Step 2: Run baseline cycle
        healer = self.agents.get('2A9E0100')
        if healer:
            cycle1 = healer.think_cycle()
            demo_steps.append({
                'step': 2,
                'action': 'Baseline cycle (Healer)',
                'result': cycle1['final_state'],
            })

        # Step 3: Inject issue
        if healer:
            healer.inject_issue("system is stuck")
            cycle2 = healer.think_cycle()
            demo_steps.append({
                'step': 3,
                'action': 'Inject issue and cycle',
                'issue': 'system is stuck',
                'result': cycle2['final_state'],
                'resolution': cycle2.get('resolution'),
            })

        # Step 4: Route a condition
        route_result = self.route("corrupted data")
        demo_steps.append({
            'step': 4,
            'action': 'Route condition',
            'condition': 'corrupted data',
            'best_agent': route_result.get('best_agent', {}).get('name'),
        })

        result = {
            'demo': 'Autonomous Thinking Demonstration',
            'steps': demo_steps,
            'success': True,
        }

        if as_json:
            return json.dumps(result, indent=2)
        return result

    def run(self, command: str, *args, as_json: bool = False) -> Any:
        """Run a thinking shell command."""
        commands = {
            'status': lambda: self.status(as_json),
            'cycle': lambda: self.cycle(args[0], args[1] if len(args) > 1 else None, as_json) if args else {'error': 'Agent ID required'},
            'inject': lambda: self.inject(args[0], as_json) if args else {'error': 'Scenario required'},
            'network': lambda: self.network(as_json),
            'route': lambda: self.route(args[0], as_json) if args else {'error': 'Condition required'},
            'demo': lambda: self.demo(as_json),
        }

        if command in commands:
            return commands[command]()
        else:
            return {'error': f'Unknown command: {command}', 'available': list(commands.keys())}
