"""
transpiler/package_manager.py — Stage 18+: RPy Package Management with Deep Stubbing.
"""

import os
import json
import shutil
import subprocess
import re
from pathlib import Path
from typing import Dict, List, Optional, Set

class PackageManager:
    def __init__(self, project_root: str = "."):
        self.project_root = Path(project_root).resolve()
        self.packages_dir = self.project_root / "rpy_packages"
        
    def load_config(self) -> dict:
        toml_path = self.project_root / "rpy.toml"
        if toml_path.exists():
            try:
                import tomllib
                return tomllib.loads(toml_path.read_text(encoding="utf-8"))
            except (ImportError, Exception):
                pass

        json_path = self.project_root / "rpy.json"
        if json_path.exists():
            try:
                with open(json_path, "r", encoding="utf-8") as f:
                    return json.load(f)
            except Exception:
                pass
        return {}

    def install(self):
        """Main entry point for 'rpy install'."""
        config = self.load_config()
        dependencies = config.get("dependencies", {})
        
        if not dependencies:
            print("[Package] No dependencies found in rpy.json.")
            return

        print(f"[*] Installing {len(dependencies)} Wally dependencies...")
        
        if not self.packages_dir.exists():
            self.packages_dir.mkdir(parents=True)

        self._sync_wally(dependencies)
        self._generate_stubs()

    def _sync_wally(self, dependencies: Dict[str, str]):
        """Generates wally.toml and runs wally install."""
        wally_path = self.project_root / "wally.toml"
        
        # Simple wally.toml generation
        content = [
            "[package]",
            'name = "rpy/project"',
            'version = "0.1.0"',
            'registry = "https://github.com/UpliftGames/wally-index"',
            'realm = "shared"',
            "",
            "[dependencies]"
        ]
        for name, version in dependencies.items():
            content.append(f'{name} = "{version}"')
            
        with open(wally_path, "w", encoding="utf-8") as f:
            f.write("\n".join(content) + "\n")
        
        print(f"[*] Generated {wally_path.name}")
        
        try:
            subprocess.run(["wally", "install"], cwd=str(self.project_root), check=True)
            print("[*] Wally dependencies installed successfully.")
        except FileNotFoundError:
            print("[!] Warning: 'wally' not found. Please Install Wally CLI.")
        except subprocess.CalledProcessError as e:
            print(f"[!] Wally install failed: {e}")

    def _generate_stubs(self):
        """Scans Packages/ and creates high-quality Python stubs."""
        packages_folder = self.project_root / "Packages"
        if not packages_folder.exists():
            print("[!] No 'Packages/' folder found. Skipping stub generation.")
            return

        print("[*] Generating Deep Stubs...")
        for entry in packages_folder.iterdir():
            if entry.is_dir() and not entry.name.startswith("_"):
                self._create_deep_stub(entry)

    def _create_deep_stub(self, package_path: Path):
        """Extracts symbols from Luau and writes a detailed .py stub."""
        package_name = package_path.name
        stub_path = self.packages_dir / f"{package_name}.py"
        
        symbols = self._extract_luau_symbols(package_path)
        
        content = [
            f'"""Auto-generated RPy stub for {package_name}"""',
            "from typing import Any, Callable, Dict, List, Optional",
            "",
            f"class {package_name}:",
        ]
        
        if not symbols:
            content.append("    def __getattr__(self, name: str) -> Any: ...")
        else:
            for sym in sorted(symbols):
                # We assume most things are functions or generic objects
                if "(" in sym: # It's a method-like string we found
                    content.append(f"    def {sym}: ...")
                else:
                    content.append(f"    {sym}: Any")

        content.append("")
        content.append(f"{package_name} = {package_name}()")
        
        with open(stub_path, "w", encoding="utf-8") as f:
            f.write("\n".join(content) + "\n")
        print(f"  [Stub] {package_name} -> {stub_path.name}")

    def _extract_luau_symbols(self, package_path: Path) -> Set[str]:
        """Simple regex-based Luau symbol extractor."""
        symbols = set()
        
        # Look for init.lua or main entry point
        init_files = ["init.lua", "init.spec.lua"] # Basic heuristic
        
        for root, _, files in os.walk(package_path):
            for file in files:
                if file.endswith(".lua"):
                    file_path = Path(root) / file
                    try:
                        text = file_path.read_text(encoding="utf-8")
                        # Match: export function Name(...) or function Module.Name(...)
                        # This is a VERY simplified extractor
                        
                        # Pattern 1: function Module.Name(...)
                        matches = re.findall(r"function\s+\w+\.([\w_]+)\s*\(", text)
                        symbols.update(matches)
                        
                        # Pattern 2: local Name = function(...)
                        matches = re.findall(r"local\s+([\w_]+)\s*=\s*function\s*\(", text)
                        # Filter out common locals
                        symbols.update(m for m in matches if not m.startswith("_"))
                        
                        # Pattern 3: Module.Name = ...
                        matches = re.findall(r"\w+\.([\w_]+)\s*=\s*", text)
                        symbols.update(m for m in matches if not m.startswith("_"))

                    except Exception as e:
                        # print(f"Error parsing {file_path}: {e}")
                        pass
        return symbols
