#!/usr/bin/env python3
"""
Direct Zexus file executor - no dependencies, just runs .zx files directly
"""
import sys
import os
import argparse

# Add src to path
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src'))

from zexus.lexer import Lexer
from zexus.parser.parser import UltimateParser
from zexus.evaluator.core import Evaluator
from zexus.object import Environment, String, List
from zexus import config
from zexus.runtime.file_flags import parse_file_flags, apply_vm_config

def run_zexus_file(filename, debug_level='none', use_vm=False):
    """Execute a Zexus file directly"""
    
    if not os.path.exists(filename):
        print(f"❌ Error: File not found: {filename}", file=sys.stderr)
        sys.exit(1)
    
    with open(filename, 'r') as f:
        code = f.read()

    # Apply inline file flags (if any)
    file_flags = parse_file_flags(code)
    vm_mode = 'auto'
    no_optimize = False
    vm_config = {}
    if file_flags:
        if 'use_vm' in file_flags:
            use_vm = bool(file_flags.get('use_vm'))
        if 'debug' in file_flags:
            dbg = file_flags.get('debug')
            if isinstance(dbg, str):
                debug_level = dbg
            else:
                debug_level = 'full' if dbg else 'none'
        if 'vm_mode' in file_flags:
            vm_mode = str(file_flags.get('vm_mode')).lower()
        if 'no_optimize' in file_flags:
            no_optimize = bool(file_flags.get('no_optimize'))
        if 'vm_config' in file_flags and isinstance(file_flags.get('vm_config'), dict):
            vm_config = dict(file_flags.get('vm_config'))

    # Set debug level (after file flags)
    config.config.debug_level = debug_level
    config.config.enable_debug_logs = (debug_level != 'none')
    
    try:
        # Tokenize
        lexer = Lexer(code)
        
        # Parse with advanced parsing enabled
        parser = UltimateParser(lexer, enable_advanced_strategies=True)
        ast = parser.parse_program()
        
        if parser.errors:
            print(f"⚠️ Parse errors: {len(parser.errors)}", file=sys.stderr)
            for error in parser.errors[:10]:  # Show first 10 errors
                print(f"  - {error}", file=sys.stderr)
        
        if use_vm:
            # VM Execution Path (High Performance - Real Implementation)
            print("🚀 Using VM execution mode with bytecode compilation", file=sys.stderr)
            
            try:
                from zexus.vm.vm import VM, VMMode
                from zexus.vm.compiler import compile_ast_to_bytecode, UnsupportedNodeError
                
                # Compile AST to bytecode
                if debug_level != 'none':
                    print("   📦 Compiling AST to bytecode...", file=sys.stderr)
                
                try:
                    bytecode = compile_ast_to_bytecode(ast, optimize=not no_optimize)
                except UnsupportedNodeError as e:
                    print(f"⚠️  VM fallback: {e}", file=sys.stderr)
                    use_vm = False
                except Exception as e:
                    print(f"⚠️  Bytecode compilation failed: {e}", file=sys.stderr)
                    if debug_level == 'full':
                        import traceback
                        traceback.print_exc(file=sys.stderr)
                    use_vm = False

                if use_vm:
                    if debug_level == 'full' and bytecode is not None:
                        print("\n" + bytecode.disassemble(), file=sys.stderr)
                    
                    if debug_level != 'none':
                        print(f"   ⚡ Executing {len(bytecode.instructions)} instructions...", file=sys.stderr)
                    
                    vm_mode_map = {
                        'auto': VMMode.AUTO,
                        'stack': VMMode.STACK,
                        'register': VMMode.REGISTER,
                        'parallel': VMMode.PARALLEL,
                    }
                    vm_mode_value = vm_mode if vm_mode in vm_mode_map else 'auto'
                    vm = VM(
                        mode=vm_mode_map[vm_mode_value],
                        use_jit=not no_optimize,
                        max_heap_mb=512,
                        debug=(debug_level == 'full')
                    )
                    apply_vm_config(vm, vm_config)

                    # Rust VM status indicator
                    if getattr(vm, '_rust_vm_available', False) and getattr(vm, '_rust_vm_enabled', False):
                        print("   ⚡ Rust VM: active — native acceleration enabled", file=sys.stderr)
                    elif getattr(vm, '_rust_vm_available', False):
                        print("   ⚡ Rust VM: available but disabled", file=sys.stderr)
                    else:
                        print("   ⚠️  Rust VM: not compiled — using Python VM", file=sys.stderr)

                    result = vm.execute(bytecode, debug=(debug_level == 'full'))
                    
                    if debug_level != 'none':
                        print(f"   ✅ VM execution complete", file=sys.stderr)
                
            except ImportError as e:
                print(f"⚠️  VM not available: {e}", file=sys.stderr)
                print("   Falling back to evaluator...", file=sys.stderr)
                use_vm = False  # Fall through to evaluator
            except Exception as e:
                print(f"⚠️  VM execution failed: {e}", file=sys.stderr)
                if debug_level == 'full':
                    import traceback
                    traceback.print_exc(file=sys.stderr)
                print("   Falling back to evaluator...", file=sys.stderr)
                use_vm = False  # Fall through to evaluator
        
        if not use_vm:
            # Standard Evaluator Path (Stable - Lower Performance)
            evaluator = Evaluator()
            env = Environment()
            # Establish module context so relative imports resolve correctly
            abs_file = os.path.abspath(filename)
            env.set("__file__", String(abs_file))
            env.set("__FILE__", String(abs_file))
            env.set("__MODULE__", String("__main__"))
            env.set("__DIR__", String(os.path.dirname(abs_file)))

            empty_args = List([])
            env.set("__ARGS__", empty_args)
            env.set("__ARGV__", empty_args)

            try:
                rel_path = os.path.relpath(abs_file)
                if os.sep in rel_path:
                    package_name = rel_path.replace(os.sep, "/").split("/")[0]
                else:
                    package_name = ""
            except (OSError, ValueError):
                package_name = ""
            env.set("__PACKAGE__", String(package_name))
            result = evaluator.eval_node(ast, env)
        
        # Check if result is an error
        from zexus.object import Null, EvaluationError
        if isinstance(result, EvaluationError):
            print(f"❌ Runtime Error: {result.message}", file=sys.stderr)
            sys.exit(1)
        
        # Print final result if not NULL
        if result and not isinstance(result, Null):
            print(f"Result: {result}")
        
    except Exception as e:
        print(f"\n❌ Error: {str(e)}", file=sys.stderr)
        import traceback
        print("\nFull traceback:", file=sys.stderr)
        traceback.print_exc(file=sys.stderr)
        sys.exit(1)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description='Zexus file executor')
    parser.add_argument('file', help='Zexus file to execute (.zx)')
    parser.add_argument('--verbose', '-v', action='store_true', 
                        help='Enable verbose debug output')
    parser.add_argument('--quiet', '-q', action='store_true',
                        help='Suppress parser debug output (default)')
    parser.add_argument('--use-vm', action='store_true',
                        help='Use VM execution mode for better performance (experimental)')
    
    args = parser.parse_args()
    
    # Determine debug level
    if args.verbose:
        debug_level = 'full'
    else:
        debug_level = 'none'
    
    run_zexus_file(args.file, debug_level, use_vm=args.use_vm)
