"""
Enhanced AbuLang Runner with fuzzy matching and AI parsing
"""

import re
import builtins
import math
import statistics

try:
    from .abu_core import AbuLang
    from .fuzzy_matcher import FuzzyMatcher
    from .ai_parser import AIParser
except ImportError:
    from abu_core import AbuLang
    from fuzzy_matcher import FuzzyMatcher
    from ai_parser import AIParser


class EnhancedAbuRunner:
    """
    Enhanced AbuLang interpreter with:
    - Fuzzy matching for typo tolerance
    - AI-assisted natural language parsing
    - Intelligent error suggestions
    """
    
    def __init__(self, enable_fuzzy=True, enable_ai=False, ai_backend="pattern", api_key=None):
        """
        Initialize enhanced runner
        
        Args:
            enable_fuzzy: Enable fuzzy matching for typos
            enable_ai: Enable AI-assisted parsing
            ai_backend: "openai", "ollama", "anthropic", or "pattern"
            api_key: API key for cloud AI services
        """
        self.lang = AbuLang()
        self.context = {
            "math": math,
            "statistics": statistics,
            "stat": statistics,
        }
        self.constants = set()
        
        # Initialize fuzzy matcher
        self.enable_fuzzy = enable_fuzzy
        if enable_fuzzy:
            self.fuzzy = FuzzyMatcher(self.lang.commands)
        
        # Initialize AI parser
        self.enable_ai = enable_ai
        if enable_ai:
            self.ai_parser = AIParser(backend=ai_backend, api_key=api_key)
        else:
            # Always have pattern-based parser as fallback
            self.ai_parser = AIParser(backend="pattern")
    
    def execute_line(self, line, auto_correct=True):
        """
        Execute a single line with fuzzy matching and AI assistance
        
        Args:
            line: Line of AbuLang code
            auto_correct: Automatically apply high-confidence corrections
        """
        line = line.strip()
        if not line:
            return
        
        # Check if this looks like natural language
        if self.enable_ai and self.ai_parser.is_natural_language(line):
            print(f"[AI] Detected natural language, translating...")
            translated = self.ai_parser.parse(line)
            print(f"[AI] Translated to: {translated}")
            line = translated
        
        # Apply fuzzy matching
        if self.enable_fuzzy:
            corrected_line, suggestions = self.fuzzy.correct_line(line, auto_correct=auto_correct)
            
            if suggestions:
                for word, info in suggestions.items():
                    if info.get("auto_corrected"):
                        print(f"[Fuzzy] Auto-corrected '{word}' → '{info['correction']}' "
                              f"(confidence: {info['confidence']:.0%})")
                        line = corrected_line
                    else:
                        print(f"[Fuzzy] Did you mean '{info['correction']}'? "
                              f"(confidence: {info['confidence']:.0%})")
                        if "alternatives" in info:
                            alts = [f"{alt} ({conf:.0%})" for alt, conf in info["alternatives"][:3]]
                            print(f"[Fuzzy] Other suggestions: {', '.join(alts)}")
        
        # Execute the line
        self._execute_core(line)
    
    def _execute_core(self, line):
        """Core execution logic (same as original runner)"""
        # === HELP ===
        if line.startswith("help"):
            self._handle_help(line)
            return
        
        # === LIBRA ===
        if line.startswith("libra"):
            self._handle_libra(line)
            return
        
        # === SHOW ===
        if line.startswith("show") or line.startswith("display") or line.startswith("print"):
            # Normalize to 'show'
            for cmd in ["show", "display", "print"]:
                if line.startswith(cmd):
                    expr = line[len(cmd):].strip()
                    break
            
            if expr.startswith("(") and expr.endswith(")"):
                expr = expr[1:-1].strip()
            
            value = self.eval_expr(expr)
            
            if isinstance(value, str) and re.search(r"[a-zA-Z_]+\(", value):
                try:
                    value = eval(value, self.context, self.context)
                except Exception as e:
                    print(f"[AbuLang Error] {e}")
            
            print(value)
            return
        
        # === ASK/INPUT ===
        if line.startswith("ask") or line.startswith("input"):
            # Extract variable and prompt
            match = re.match(r"(ask|input)\s*\(?\s*['\"]([^'\"]+)['\"]\s*\)?", line)
            if match:
                prompt_text = match.group(2)
                result = input(prompt_text)
                return result
            else:
                result = input()
                return result
        
        # === VARIABLE ASSIGNMENT ===
        if " is " in line and not line.startswith("if"):
            var, expr = map(str.strip, line.split(" is ", 1))
            
            if var in self.constants:
                print(f"[AbuLang Error] Cannot reassign constant '{var}'")
                return
            
            value = self.eval_expr(expr)
            self.context[var] = value
            return
        
        if "=" in line and not line.startswith("if"):
            var, expr = map(str.strip, line.split("=", 1))
            
            if var in self.constants:
                print(f"[AbuLang Error] Cannot reassign constant '{var}'")
                return
            
            value = self.eval_expr(expr)
            self.context[var] = value
            return
        
        # === FALLBACK RAW PYTHON ===
        try:
            exec(line, self.context, self.context)
        except Exception as e:
            print(f"[AbuLang Error] {e}")
            
            # Provide fuzzy suggestions on error
            if self.enable_fuzzy:
                words = line.split()
                if words:
                    suggestions = self.fuzzy.suggest_corrections(words[0], n=3)
                    if suggestions and suggestions[0][1] > 0.5:
                        print(f"[Fuzzy] Did you mean one of these?")
                        for suggestion, confidence in suggestions:
                            print(f"  - {suggestion} ({confidence:.0%})")
    
    def _handle_help(self, line):
        """Handle help command"""
        parts = line.split()
        if len(parts) == 1:
            sections = sorted(
                {info.get("section", "misc") for info in self.lang.commands.values()}
            )
            print("\n📘 AbuLang Help System")
            print("Available sections:\n " + ", ".join(sections))
            print("Type 'help <section>' or 'help all'")
            print("\n✨ Features:")
            print("  - Fuzzy matching: Typo tolerance enabled" if self.enable_fuzzy else "")
            print("  - AI parsing: Natural language support enabled" if self.enable_ai else "")
            return
        
        arg = parts[1].replace("(", "").replace(")", "")
        if arg.lower() == "all":
            print("\n📘 AbuLang Full Command List\n")
            for cmd, info in self.lang.commands.items():
                aliases = ", ".join(info.get("aliases", []))
                print(f"{cmd:8} | {info.get('section','misc'):10} | {info['desc']}")
                if aliases:
                    print(f"         | Aliases: {aliases}")
            return
        
        section = arg.lower()
        found = [
            (cmd, info)
            for cmd, info in self.lang.commands.items()
            if info.get("section", "") == section
        ]
        if not found:
            print(f"No commands found for section: {section}")
            return
        print(f"\nCommands in section '{section}':")
        for cmd, info in found:
            print(f"  {cmd:8} - {info['desc']}")
    
    def _handle_libra(self, line):
        """Handle library import"""
        parts = line.split()
        if len(parts) < 2:
            print("[AbuLang Error] No module specified")
            return
        
        module_name = parts[1].strip()
        alias = None
        if "as" in parts:
            idx = parts.index("as")
            if idx + 1 < len(parts):
                alias = parts[idx + 1].strip()
        
        module_aliases = {
            "stat": "statistics",
            "maths": "math",
            "osys": "os",
            "req": "requests",
            "jsons": "json",
            "path": "os.path",
            "web": "requests",
            "DISPLAY": "pygame",
            "UI": "tkinter",
            "arrow": "turtle",
        }
        
        real_module = module_aliases.get(module_name, module_name)
        
        try:
            import importlib
            imported = importlib.import_module(real_module)
            self.context[real_module] = imported
            
            if module_name != real_module:
                self.context[module_name] = imported
            
            if alias:
                self.context[alias] = imported
                print(f"[libra] imported {real_module} as {alias}")
            else:
                print(f"[libra] imported {real_module}")
            
            if real_module == "statistics":
                self.context["stat"] = imported
            elif real_module == "math":
                self.context["maths"] = imported
        
        except ImportError:
            print(f"[AbuLang Error] could not import {real_module}")
    
    def eval_expr(self, expr):
        """Evaluate an expression"""
        expr = expr.strip()
        
        # Handle string literals
        if re.match(r"^['\"].*['\"]$", expr):
            return expr.strip("\"'")
        
        # Handle variable lookup
        if expr in self.context:
            return self.context[expr]
        
        # Handle math shortcuts
        expr = expr.replace("^", "**")
        expr = re.sub(r"(\d+)%", r"(\1/100)", expr)
        
        try:
            result = eval(expr, self.context, self.context)
            return result
        except Exception:
            return expr
    
    def run(self, code: str, auto_correct=True):
        """
        Run AbuLang code with enhanced features
        
        Args:
            code: AbuLang source code
            auto_correct: Enable automatic typo correction
        """
        for line in code.splitlines():
            # Handle comments
            if "#" in line:
                line = line.split("#", 1)[0]
            if "//" in line:
                line = line.split("//", 1)[0]
            
            line = line.strip()
            if not line:
                continue
            
            self.execute_line(line, auto_correct=auto_correct)
