"""
I-Logic Shell - I-Logic Operations
Standalone version for cubesquare package.
"""

import json
from typing import Dict, Any, List
from ..circular.state_machine import ILogicState, ILogicStateMachine, _STATE_MULTIPLY_TABLE


class ILogicShell:
    """
    I-Logic Shell.

    Provides I-Logic operations:
    - State multiplication
    - Route prediction
    - Composition
    """

    def __init__(self):
        """Initialize I-Logic shell."""
        self.state_machine = ILogicStateMachine()
        self.states = {
            'DIRECT': ILogicState.DIRECT,
            'INVERSE': ILogicState.INVERSE,
            'SPIRAL': ILogicState.SPIRAL,
            'ANTI_SPIRAL': ILogicState.ANTI_SPIRAL,
            'ABSORBED': ILogicState.ABSORBED,
        }

    def status(self, as_json: bool = False) -> Dict[str, Any]:
        """Get I-Logic system status."""
        result = {
            'system': 'I-Logic Shell',
            'version': '1.0.0',
            'states': list(self.states.keys()),
            'state_count': len(self.states),
            'properties': {
                'identity': 'DIRECT',
                'absorbing': 'ABSORBED',
                'period_4': ['SPIRAL', 'ANTI_SPIRAL'],
                'involution': 'INVERSE',
            },
            'status': 'operational',
        }

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

    def multiply(self, state1: str, state2: str, as_json: bool = False) -> Dict[str, Any]:
        """Multiply two I-Logic states."""
        state1 = state1.upper()
        state2 = state2.upper()

        if state1 not in self.states:
            return {'error': f'Unknown state: {state1}'}
        if state2 not in self.states:
            return {'error': f'Unknown state: {state2}'}

        s1 = self.states[state1]
        s2 = self.states[state2]
        result_state = self.state_machine.multiply(s1, s2)

        result = {
            'state1': state1,
            'state2': state2,
            'result': result_state.name,
            'operation': f'{state1} x {state2} = {result_state.name}',
            'is_stable': result_state.is_stable(),
        }

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

    def compose(self, states_str: str, as_json: bool = False) -> Dict[str, Any]:
        """Compose a chain of I-Logic states."""
        state_names = [s.strip().upper() for s in states_str.split(',')]

        for name in state_names:
            if name not in self.states:
                return {'error': f'Unknown state: {name}'}

        # Start with first state
        result_state = self.states[state_names[0]]
        steps = [{'step': 0, 'state': state_names[0], 'result': state_names[0]}]

        for i, name in enumerate(state_names[1:], 1):
            next_state = self.states[name]
            new_result = self.state_machine.multiply(result_state, next_state)
            steps.append({
                'step': i,
                'state': name,
                'operation': f'{result_state.name} x {name}',
                'result': new_result.name,
            })
            result_state = new_result

        result = {
            'input': state_names,
            'final_state': result_state.name,
            'is_stable': result_state.is_stable(),
            'steps': steps,
        }

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

    def predict(self, route_str: str, as_json: bool = False) -> Dict[str, Any]:
        """Predict route outcome from agent:state pairs."""
        # Parse route string: "gateway:DIRECT,firewall:INVERSE,sink:ABSORBED"
        pairs = [p.strip() for p in route_str.split(',')]

        agents = []
        for pair in pairs:
            if ':' not in pair:
                return {'error': f'Invalid format: {pair}. Expected agent:STATE'}
            agent, state = pair.split(':')
            state = state.strip().upper()
            if state not in self.states:
                return {'error': f'Unknown state: {state}'}
            agents.append({'agent': agent.strip(), 'state': state})

        # Start with DIRECT (identity)
        signal = self.states['DIRECT']
        trace = []

        for i, agent in enumerate(agents):
            agent_state = self.states[agent['state']]
            new_signal = self.state_machine.multiply(signal, agent_state)

            trace.append({
                'step': i + 1,
                'agent': agent['agent'],
                'agent_state': agent['state'],
                'signal_in': signal.name,
                'signal_out': new_signal.name,
            })

            signal = new_signal

            # Check for termination
            if signal == ILogicState.ABSORBED:
                break

        result = {
            'route': route_str,
            'agent_count': len(agents),
            'final_state': signal.name,
            'terminated_early': signal == ILogicState.ABSORBED and len(trace) < len(agents),
            'steps_executed': len(trace),
            'trace': trace,
        }

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

    def test(self, as_json: bool = False) -> Dict[str, Any]:
        """Run I-Logic algebra tests."""
        tests = []

        # Test 1: Identity (DIRECT)
        for state in self.states:
            result = self.state_machine.multiply(self.states['DIRECT'], self.states[state])
            tests.append({
                'test': f'DIRECT x {state}',
                'expected': state,
                'actual': result.name,
                'passed': result.name == state,
            })

        # Test 2: Involution (INVERSE x INVERSE = DIRECT)
        result = self.state_machine.multiply(self.states['INVERSE'], self.states['INVERSE'])
        tests.append({
            'test': 'INVERSE x INVERSE',
            'expected': 'DIRECT',
            'actual': result.name,
            'passed': result.name == 'DIRECT',
        })

        # Test 3: Absorption
        for state in self.states:
            result = self.state_machine.multiply(self.states['ABSORBED'], self.states[state])
            tests.append({
                'test': f'ABSORBED x {state}',
                'expected': 'ABSORBED',
                'actual': result.name,
                'passed': result.name == 'ABSORBED',
            })

        passed = sum(1 for t in tests if t['passed'])
        total = len(tests)

        result = {
            'tests': tests,
            'passed': passed,
            'total': total,
            'all_passed': passed == total,
        }

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

    def run(self, command: str, *args, as_json: bool = False) -> Any:
        """Run an I-Logic shell command."""
        commands = {
            'status': lambda: self.status(as_json),
            'multiply': lambda: self.multiply(args[0], args[1], as_json) if len(args) >= 2 else {'error': 'Two states required'},
            'compose': lambda: self.compose(args[0], as_json) if args else {'error': 'States required (comma-separated)'},
            'predict': lambda: self.predict(args[0], as_json) if args else {'error': 'Route required'},
            'test': lambda: self.test(as_json),
        }

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