"""Cubesquare CLI

Command-line interface for cubesquare standalone package.
Routes to 7 core shells: cst, i_logic, circular, primitives, predict, beehive, performance
"""
from __future__ import annotations

import argparse
import json
import sys
from pathlib import Path


# Shell registry - 35 shells organized by category
SHELLS = {
    # Core (7)
    'cst': 'CST 9-layer operations (layers, basins)',
    'i_logic': 'I-Logic 4-state algebra (multiply, compose, predict)',
    'circular': 'Circular system (SRL, K11, intrinsic)',
    'primitives': 'Verified O(1) primitives (Morton, Basin, SRL)',
    'predict': 'Route prediction via I-Logic',
    'beehive': 'Token clustering and indexing',
    'performance': 'C backend benchmarks and tests',
    # Physics (5)
    'time': 'Time physics: t = sqrt(d)',
    'distance': 'Distance metrics: Morton, Euclidean, Manhattan',
    'mass': 'Mass coupling: K11, momentum, center-of-mass',
    'gravity': 'Celestial primes: Earth 6584, Sun 2179, orbits',
    'epicycle': 'Resonance, breeding, spherical harmonics',
    # Agent (5)
    'agent': 'Agent onboarding and contextualization',
    'gene': '48^3 matrix identity and reproduction',
    'unified': 'I-Logic thinking protocols',
    'manifold': 'The Square: K5=41.7Hz bubble frequency',
    'meaning': 'Self-reference: P-P=0, P/P=1',
    # Semantic (5)
    'semantic': 'Language to geometry decomposition',
    'language': 'Machine-to-human semantic bridge',
    'basin_dict': 'Zipf-based FML basin assignment',
    'light': 'Light Unit <-> Basin <-> Layer mapping',
    'thinking': 'OBSERVE->DECOMPOSE->REASON->ACT loop',
    # Data (5)
    'ecosystem': 'Token relationships: 67K+ connections',
    'data_analysis': 'Pattern detection and idea generation',
    'telemetry': 'Agent telemetry: hex + emotion (pure Python)',
    'condition': 'Semantic condition encoding',
    'fml': 'FML 9-layer token encoding',
    # Infrastructure (8)
    'srl': 'Square Root Loop: O(1) pathfinding',
    'basin': 'Basin computation and distribution',
    'world': 'World coordinate mapping',
    'cypher': 'Graph query language interface',
    'sql': 'SQL query interface',
    'twelve': 'L10-L12 external layer operations',
    'learning': 'Learning and adaptation patterns',
    'validation': 'System validation and verification',
}

from .ui import launch as ui_launch
from .explain import explain

def cmd_ui(args):
    """Launch the visualizer."""
    try:
        ui_launch()
    except Exception as e:
        print(f"Error launching UI: {e}")
        sys.exit(1)

def cmd_explain(args):
    """Deep interpret a token."""
    try:
        result = explain(args.identifier)
        print(result)
    except Exception as e:
        print(f"Error explaining token: {e}")
        sys.exit(1)




def get_shell(name: str):
    """Get shell instance by name."""
    from .shells import (
        # Core
        CSTShell, ILogicShell, CircularShell,
        PrimitivesShell, PredictShell, BeehiveShell, PerformanceShell,
        # Physics
        TimeShell, DistanceShell, MassShell, GravityShell, EpicycleShell,
        # Agent
        AgentShell, GeneShell, UnifiedShell, ManifoldShell, MeaningShell,
        # Semantic
        SemanticShell, LanguageShell, BasinDictShell, LightShell, ThinkingShell,
        # Data
        EcosystemShell, DataAnalysisShell, TelemetryShell, ConditionEncoder, FMLEncoder,
        # Infrastructure
        SRLShell, BasinShell, WorldShell, CypherShell, SQLShell,
        TwelveShell, LearningShell, ValidationShell,
    )

    shells = {
        # Core (7)
        'cst': CSTShell,
        'i_logic': ILogicShell,
        'circular': CircularShell,
        'primitives': PrimitivesShell,
        'predict': PredictShell,
        'beehive': BeehiveShell,
        'performance': PerformanceShell,
        # Physics (5)
        'time': TimeShell,
        'distance': DistanceShell,
        'mass': MassShell,
        'gravity': GravityShell,
        'epicycle': EpicycleShell,
        # Agent (5)
        'agent': AgentShell,
        'gene': GeneShell,
        'unified': UnifiedShell,
        'manifold': ManifoldShell,
        'meaning': MeaningShell,
        # Semantic (5)
        'semantic': SemanticShell,
        'language': LanguageShell,
        'basin_dict': BasinDictShell,
        'light': LightShell,
        'thinking': ThinkingShell,
        # Data (5)
        'ecosystem': EcosystemShell,
        'data_analysis': DataAnalysisShell,
        'telemetry': TelemetryShell,
        'condition': ConditionEncoder,
        'fml': FMLEncoder,
        # Infrastructure (8)
        'srl': SRLShell,
        'basin': BasinShell,
        'world': WorldShell,
        'cypher': CypherShell,
        'sql': SQLShell,
        'twelve': TwelveShell,
        'learning': LearningShell,
        'validation': ValidationShell,
    }

    if name in shells:
        return shells[name]()
    return None


def main():
    """Main CLI entry point."""
    parser = argparse.ArgumentParser(
        prog="cubesquare",
        description="Cubesquare - Instant Semantic Memory for AI"
    )

    parser.add_argument("--status", action="store_true", help="Show system status")
    parser.add_argument("--list", action="store_true", help="List all shells")
    parser.add_argument("--json", action="store_true", help="Output as JSON")

    subparsers = parser.add_subparsers(dest="command_name", help="Available commands")

    # Command: primitives
    p_prim = subparsers.add_parser('primitives', help='Show verified primitives')
    p_prim.add_argument('operation', nargs='?', default='status', help='Primitive operation (morton, basin, srl, i_logic)')
    p_prim.add_argument('--json', action='store_true', help='JSON output')
    p_prim.set_defaults(func=cmd_primitives)

    # Command: ilogic
    p_ilogic = subparsers.add_parser('ilogic', help='I-Logic operations')
    p_ilogic.add_argument('operation', help='Operation (multiply, compose, predict, test, status)')
    p_ilogic.add_argument('args', nargs='*', help='Arguments for operation')
    p_ilogic.add_argument('--json', action='store_true', help='JSON output')
    p_ilogic.set_defaults(func=cmd_ilogic)


    # Command: ui
    p_ui = subparsers.add_parser('ui', help='Launch visualizer')
    p_ui.set_defaults(func=cmd_ui)

    # Command: explain
    p_explain = subparsers.add_parser('explain', help='Deep interpret a token')
    p_explain.add_argument('identifier', help='Hex ID or file path to explain')
    p_explain.set_defaults(func=cmd_explain)

    # Shell commands (for backward compatibility or dynamic shell loading)
    # This subparser will handle the existing shell logic
    p_shell = subparsers.add_parser('shell', help='Run a specific shell command')
    p_shell.add_argument("shell_name", nargs="?", help="Shell name (cst, i_logic, circular, etc.)")
    p_shell.add_argument("shell_command", nargs="?", default="status", help="Shell command")
    p_shell.add_argument("shell_args", nargs="*", help="Command arguments")
    p_shell.set_defaults(func=lambda args: handle_shell_command(args, args.json))

    # Parse arguments
    args = parser.parse_args()

    # Handle subcommands
    if hasattr(args, 'func'):
        args.func(args)
        return

    json_output = args.json if hasattr(args, 'json') else False

    # Handle --list
    if args.list:
        print("CUBESQUARE SHELLS")
        print("=" * 50)
        for name, desc in SHELLS.items():
            print(f"  {name:<12}  {desc}")
        print(f"\nTotal: {len(SHELLS)} shells")
        return

    # Handle --status
    if args.status or (not args.shell):
        cmd_status(json_output)
        return

    # Handle shell commands
    if args.shell in SHELLS:
        shell = get_shell(args.shell)
        if shell:
            result = shell.run(args.command, *args.args, as_json=json_output)
            if json_output and isinstance(result, str):
                print(result)
            elif isinstance(result, dict):
                if json_output:
                    print(json.dumps(result, indent=2))
                else:
                    for k, v in result.items():
                        print(f"{k}: {v}")
            else:
                print(result)
        else:
            print(f"Error: Could not load shell '{args.shell}'")
    else:
        # Backward compatibility with old commands
        if args.shell == "status":
            cmd_status(json_output)
        elif args.shell == "benchmark":
            cmd_benchmark_simple()
        else:
            print(f"Unknown shell: {args.shell}")
            print(f"Available: {', '.join(SHELLS.keys())}")


def cmd_status(json_output: bool = False):
    """Show system status."""
    from ._core import PHI, K5, K11, PRIME_131

    # Check native DLLs
    native_path = Path(__file__).parent.parent / "native" / "hex_core"
    dll_count = len(list(native_path.glob("*.dll"))) if native_path.exists() else 0

    # Check beehive data
    data_path = Path(__file__).parent.parent / "data" / "beehive"
    data_loaded = (data_path / "beehive_index.json").exists() if data_path.exists() else False

    s = {
        "version": "1.0.0",
        "package": "cubesquare_standalone",
        "shells": len(SHELLS),
        "shell_list": list(SHELLS.keys()),
        "layers": 9,
        "basins": PRIME_131,
        "native_dlls": dll_count,
        "native_backend": dll_count > 0,
        "beehive_data": data_loaded,
        "constants": {
            "PHI": PHI,
            "K5": K5,
            "K11": K11,
            "PRIME_131": PRIME_131,
        },
        "primitives": {
            "morton": "O(1), 21 ops",
            "basin": "O(1), 8 ops",
            "srl": "O(1), <=25 iter",
            "i_logic": "O(1) per mult",
        },
    }

    if json_output:
        print(json.dumps(s, indent=2))
    else:
        print("CUBESQUARE STANDALONE")
        print("=" * 50)
        print(f"Version:         {s['version']}")
        print(f"Shells:          {s['shells']} ({', '.join(s['shell_list'])})")
        print(f"Layers:          L1-L9 (9 CST layers)")
        print(f"Basins:          {s['basins']} Fernandez basins")
        print(f"Native DLLs:     {s['native_dlls']} ({'loaded' if s['native_backend'] else 'using Python fallback'})")
        print(f"Beehive Data:    {'loaded' if s['beehive_data'] else 'not loaded'}")
        print(f"\nVerified Primitives:")
        for name, complexity in s['primitives'].items():
            print(f"  {name:<12}: {complexity}")
        print(f"\nConstants: PHI={PHI:.6f}, K5={K5:.6f}, K11={K11}, PRIME_131={PRIME_131}")


def cmd_benchmark_simple():
    """Run simple benchmark."""
    from .shells import PerformanceShell
    shell = PerformanceShell()
    result = shell.benchmark(as_json=False)
    print("BENCHMARK RESULTS")
    print("=" * 50)
    print(f"Backend: {result['backend']}")
    for bench in result['benchmarks']:
        print(f"  {bench['test']:<20}: {bench['per_op_us']:.3f} us/op ({bench['ops_per_sec']:,} ops/sec)")


def cmd_benchmark(args):
    """Run performance benchmark."""
    from . import CSTMemory

    print("Running benchmark...")
    memory = CSTMemory()

    # Add test data
    for i in range(100):
        memory.write(f"/test/file_{i}.py")

    results = memory.benchmark(args.iterations)

    print("\nBenchmark Results")
    print("=" * 40)
    print(f"Morton Encode:   {results['morton_encode_ns']:.2f} ns/op")
    print(f"Token Create:    {results['token_create_ns']:.2f} ns/op")
    print(f"Query:           {results['query_ns']:.2f} ns/op")
    print(f"Native Backend:  {'Yes' if results['native_backend'] else 'No'}")

    if results['native_backend']:
        throughput = 1e9 / results['morton_encode_ns']
        print(f"Throughput:      {throughput/1e6:.1f}M tokens/sec")


def cmd_write(args):
    """Write paths to memory."""
    from . import CSTMemory

    memory = CSTMemory()

    for path in args.paths:
        token = memory.write(path)
        print(f"Wrote: {path} -> {token.hex_id} (basin={token.basin}, L{token.layer})")


def cmd_query(args):
    """Query memory."""
    from . import CSTMemory

    memory = CSTMemory()

    # Need to populate with some data first for meaningful query
    results = memory.query(args.pattern, limit=args.limit)

    print(f"Query: '{args.pattern}' ({len(results)} results)")
    if results:
        print("-" * 40)
        for i, token in enumerate(results):
            print(f"{i+1}. {token.hex_id} basin={token.basin} L{token.layer}")
            if token.path:
                print(f"   {token.path}")


def cmd_ilogic(args):
    """I-Logic operations."""
    json_output = args.json if hasattr(args, 'json') else False

    from .i_logic import ILogicState
    from .i_logic.algebra import multiply, verify_algebra
    from .i_logic.predict import predict_route, compose_path_string

    op = args.operation

    if op == "status":
        I = ILogicState
        result = {
            "algebra": "Z/4Z with absorbing element",
            "states": [{"name": I.name(s), "symbol": I.symbol(s)} for s in I.ALL_STATES],
            "complexity": {
                "multiplication": "O(1)",
                "path_composition": "O(N)",
            },
            "verified": verify_algebra()
        }
        if json_output:
            print(json.dumps(result, indent=2))
        else:
            print("I-LOGIC STATUS")
            print("=" * 40)
            print(f"Algebra: {result['algebra']}")
            print(f"States: {', '.join(s['name'] for s in result['states'])}")
            print(f"Verified: {result['verified']}")

    elif op == "multiply":
        if len(args.args) < 2:
            print("Usage: cubesquare i_logic multiply STATE_A STATE_B")
            return
        state_a = ILogicState.from_name(args.args[0])
        state_b = ILogicState.from_name(args.args[1])
        if state_a is None or state_b is None:
            print(f"Unknown state")
            return
        result = multiply(state_a, state_b)
        print(f"{ILogicState.name(state_a)} * {ILogicState.name(state_b)} = {ILogicState.name(result)}")

    elif op == "compose":
        if not args.args:
            print("Usage: cubesquare i_logic compose STATE1,STATE2,...")
            return
        result = compose_path_string(args.args[0])
        if json_output:
            print(json.dumps(result, indent=2))
        else:
            print(f"Path: {' -> '.join(result['path'])}")
            print(f"Result: {result['result']}")
            print(f"Steps: {result['steps_taken']}/{result['path_length']}")

    elif op == "predict":
        if not args.args:
            print("Usage: cubesquare i_logic predict agent:STATE,agent:STATE,...")
            return
        result = predict_route(args.args[0])
        if json_output:
            print(json.dumps(result, indent=2))
        else:
            print("ROUTING PREDICTION")
            print("=" * 40)
            for r in result.get('route', []):
                print(f"  {r['agent']} [{r['state']}]")
            print(f"\nResult: {result.get('final_state', 'ERROR')}")
            print(f"Interpretation: {result.get('interpretation', '')}")

    elif op == "test":
        passed = verify_algebra()
        print(f"I-Logic Algebra Tests: {'ALL PASS (5/5)' if passed else 'FAILED'}")


def cmd_primitives(args):
    """Show verified primitives."""
    json_output = args.json if hasattr(args, 'json') else False

    primitives = {
        "morton": {
            "operation": "3D -> Z-order",
            "complexity": "O(1), 21 ops",
            "verified": "100M entries, 100% correct"
        },
        "basin": {
            "operation": "Token -> cluster",
            "complexity": "O(1), 8 ops",
            "verified": "131 basins, 0.82 uniformity"
        },
        "srl": {
            "operation": "Distance -> path",
            "complexity": "O(1), <=25 iter",
            "verified": "0% error, d up to 10^9"
        },
        "i_logic": {
            "operation": "State composition",
            "complexity": "O(1) * N",
            "verified": "11/11 tests, 125 combos"
        }
    }

    if args.operation == "status":
        if json_output:
            print(json.dumps(primitives, indent=2))
        else:
            print("VERIFIED PRIMITIVES")
            print("=" * 50)
            for name, info in primitives.items():
                print(f"\n{name.upper()}")
                print(f"  Operation:  {info['operation']}")
                print(f"  Complexity: {info['complexity']}")
                print(f"  Verified:   {info['verified']}")
    else:
        prim = primitives.get(args.operation, {})
        if json_output:
            print(json.dumps(prim, indent=2))
        else:
            print(f"{args.operation.upper()}")
            for k, v in prim.items():
                print(f"  {k}: {v}")


if __name__ == "__main__":
    main()
