"""
Nexa Language — Debugger (v22)
`nexa debug file.nexa` — interactive pdb-based debugger.

Features:
  - Set breakpoints by line: nexa debug file.nexa:15
  - Wraps interpreter with pdb.set_trace() at target lines
  - Prints Nexa-level variable names (filters out Python internals)
  - Stack trace shows Nexa line numbers
"""
from __future__ import annotations
import sys
import pdb


def run_debug(path: str, break_line: int = 0, debug_all: bool = False):
    """Start a Nexa debug session for `path`. Break at `break_line` if provided."""
    import os
    from nexa_lang.lexer import Lexer
    from nexa_lang.parser import Parser
    from nexa_lang.interpreter import Interpreter, Environment, NexaRuntimeError
    from nexa_lang.builtins import BUILTINS

    if not os.path.exists(path):
        print(f"  ❌ File not found: {path}"); sys.exit(1)

    with open(path, encoding="utf-8") as f:
        src = f.read()

    print(f"\n  🐛 Nexa Debugger v22")
    print(f"  File: {path}")
    if break_line:
        print(f"  Break at: line {break_line}")
    print(f"  Commands: n(next), s(step), c(continue), p <var>(print), q(quit)\n")

    tokens = Lexer(src).tokenize()
    ast = Parser(tokens).parse()

    env = Environment()
    for k, v in BUILTINS.items():
        env.set(k, v)

    interp = Interpreter()

    # Monkey-patch _exec to inject breakpoints
    original_exec = interp._exec.__func__ if hasattr(interp._exec, '__func__') else None

    def debug_exec(self, node, env_inner):
        line = getattr(node, 'line', 0)
        if break_line and line == break_line:
            print(f"\n  ⏸  Breakpoint at line {line} — {type(node).__name__}")
            _print_nexa_locals(env_inner)
            pdb.set_trace()
        elif debug_all:
            print(f"  ▶  line {line}: {type(node).__name__}")
        return original_exec(self, node, env_inner) if original_exec else None

    if original_exec:
        import types
        interp._exec = types.MethodType(debug_exec, interp)

    try:
        for stmt in ast.statements:
            interp._exec(stmt, env)
        print(f"\n  ✅ Debug session complete.")
    except KeyboardInterrupt:
        print("\n  ⏹  Debugger interrupted.")
    except NexaRuntimeError as e:
        print(f"\n  💥 Runtime Error: {e}")
        if interp.call_stack:
            print("  Call stack:")
            for frame in reversed(interp.call_stack[-5:]):
                print(f"    {frame}")


def _print_nexa_locals(env):
    """Print readable Nexa variable snapshot from environment."""
    try:
        scope = env._env if hasattr(env, '_env') else {}
        if not scope: return
        print("  📋 Local variables:")
        for k, v in list(scope.items())[:20]:
            if k.startswith("__"): continue
            print(f"     {k} = {repr(v)[:60]}")
    except Exception:
        pass
