"""
Addon Builder für Pinguin Browser
Erstellt .pbcl Dateien mit eingebettetem Virtual Environment
"""

import os
import json
import zipfile
import sys
import ast
import subprocess
import tempfile
import shutil
from pathlib import Path
from PyQt5.QtWidgets import (QApplication, QMainWindow, QVBoxLayout, QHBoxLayout, 
                             QWidget, QPushButton, QLabel, QLineEdit, QTextEdit,
                             QFileDialog, QMessageBox, QProgressBar, QCheckBox)
from PyQt5.QtCore import Qt, QThread, pyqtSignal
from PyQt5.QtGui import QFont

class DependencyAnalyzer:
    """Analysiert Python-Code auf Dependencies"""
    
    STDLIB_MODULES = {
        'abc', 'aifc', 'argparse', 'array', 'ast', 'asynchat', 'asyncio', 'asyncore',
        'atexit', 'audioop', 'base64', 'bdb', 'binascii', 'binhex', 'bisect', 'builtins',
        'bz2', 'calendar', 'cgi', 'cgitb', 'chunk', 'cmath', 'cmd', 'code', 'codecs',
        'codeop', 'collections', 'colorsys', 'compileall', 'concurrent', 'configparser',
        'contextlib', 'copy', 'copyreg', 'crypt', 'csv', 'ctypes', 'curses', 'datetime',
        'dbm', 'decimal', 'difflib', 'dis', 'distutils', 'doctest', 'dummy_threading',
        'email', 'encodings', 'enum', 'errno', 'faulthandler', 'fcntl', 'filecmp',
        'fileinput', 'fnmatch', 'formatter', 'fractions', 'ftplib', 'functools',
        'gc', 'getopt', 'getpass', 'gettext', 'glob', 'grp', 'gzip', 'hashlib',
        'heapq', 'hmac', 'html', 'http', 'imaplib', 'imghdr', 'imp', 'importlib',
        'inspect', 'io', 'ipaddress', 'itertools', 'json', 'keyword', 'lib2to3',
        'linecache', 'locale', 'logging', 'lzma', 'mailbox', 'mailcap', 'marshal',
        'math', 'mimetypes', 'mmap', 'modulefinder', 'msilib', 'msvcrt', 'multiprocessing',
        'netrc', 'nis', 'nntplib', 'numbers', 'operator', 'optparse', 'os', 'ossaudiodev',
        'parser', 'pathlib', 'pdb', 'pickle', 'pickletools', 'pipes', 'pkgutil',
        'platform', 'plistlib', 'poplib', 'posix', 'posixpath', 'pprint', 'profile',
        'pstats', 'pty', 'pwd', 'py_compile', 'pyclbr', 'pydoc', 'queue', 'quopri',
        'random', 're', 'readline', 'reprlib', 'resource', 'rlcompleter', 'runpy',
        'sched', 'secrets', 'select', 'selectors', 'shelve', 'shlex', 'shutil', 'signal',
        'site', 'smtpd', 'smtplib', 'sndhdr', 'socket', 'socketserver', 'spwd', 'sqlite3',
        'ssl', 'stat', 'statistics', 'string', 'stringprep', 'struct', 'subprocess',
        'sunau', 'symbol', 'symtable', 'sys', 'sysconfig', 'syslog', 'tabnanny',
        'tarfile', 'telnetlib', 'tempfile', 'termios', 'test', 'textwrap', 'threading',
        'time', 'timeit', 'tkinter', 'token', 'tokenize', 'trace', 'traceback',
        'tracemalloc', 'tty', 'turtle', 'types', 'typing', 'unicodedata', 'unittest',
        'urllib', 'uu', 'uuid', 'venv', 'warnings', 'wave', 'weakref', 'webbrowser',
        'winreg', 'winsound', 'wsgiref', 'xdrlib', 'xml', 'xmlrpc', 'zipapp', 'zipfile',
        'zipimport', 'zlib', '_thread'
    }
    
    def __init__(self):
        self.sdk_modules = ['browser_api', 'addon_builder', '__init__']
    
    def analyze_imports(self, code):
        """Findet alle Imports im Code"""
        imports = set()
        
        try:
            tree = ast.parse(code)
            
            for node in ast.walk(tree):
                if isinstance(node, ast.Import):
                    for alias in node.names:
                        module_name = alias.name.split('.')[0]
                        imports.add(module_name)
                
                elif isinstance(node, ast.ImportFrom):
                    if node.module:
                        module_name = node.module.split('.')[0]
                        imports.add(module_name)
        except SyntaxError:
            pass
        
        return imports
    
    def filter_external_dependencies(self, imports):
        """Filtert nur externe Dependencies (pip-Pakete)"""
        external = set()
        
        for imp in imports:
            # Ignoriere SDK
            if imp == 'pinguinbrowser_sdk':
                continue
            
            # Ignoriere Standard Library
            if imp in self.STDLIB_MODULES:
                continue
            
            # PyQt5 muss speziell behandelt werden
            if imp.startswith('PyQt'):
                external.add('PyQt5')
                continue
            
            external.add(imp)
        
        return external
    
    def needs_sdk(self, imports):
        """Prüft ob SDK benötigt wird"""
        return 'pinguinbrowser_sdk' in imports
    
    def get_sdk_files(self):
        """Gibt alle SDK-Dateien zurück"""
        sdk_dir = os.path.dirname(os.path.abspath(__file__))
        sdk_files = {}
        
        for module in self.sdk_modules:
            filepath = os.path.join(sdk_dir, f"{module}.py")
            if os.path.exists(filepath):
                with open(filepath, 'r', encoding='utf-8') as f:
                    sdk_files[f"{module}.py"] = f.read()
        
        return sdk_files

class VenvBuilder(QThread):
    """Thread für Virtual Environment Erstellung"""
    
    progress = pyqtSignal(int, str)
    finished = pyqtSignal(bool, str)
    
    def __init__(self, temp_dir, dependencies):
        super().__init__()
        self.temp_dir = temp_dir
        self.dependencies = dependencies
        self.venv_path = os.path.join(temp_dir, 'venv')
    
    def run(self):
        """Erstellt venv und installiert Packages"""
        try:
            # Virtual Environment erstellen
            self.progress.emit(10, "Erstelle Virtual Environment...")
            subprocess.run(
                [sys.executable, '-m', 'venv', self.venv_path],
                check=True,
                capture_output=True
            )
            
            # Pfad zu pip im venv
            if os.name == 'nt':  # Windows
                pip_path = os.path.join(self.venv_path, 'Scripts', 'pip.exe')
                python_path = os.path.join(self.venv_path, 'Scripts', 'python.exe')
            else:  # Linux/Mac
                pip_path = os.path.join(self.venv_path, 'bin', 'pip')
                python_path = os.path.join(self.venv_path, 'bin', 'python')
            
            self.progress.emit(30, f"Installiere {len(self.dependencies)} Pakete...")
            
            # Pakete installieren
            if self.dependencies:
                for i, dep in enumerate(self.dependencies):
                    progress_val = 30 + int((i / len(self.dependencies)) * 50)
                    self.progress.emit(progress_val, f"Installiere {dep}...")
                    
                    result = subprocess.run(
                        [pip_path, 'install', dep, '--no-warn-script-location'],
                        capture_output=True,
                        text=True
                    )
                    
                    if result.returncode != 0:
                        self.finished.emit(False, f"Fehler beim Installieren von {dep}:\n{result.stderr}")
                        return
            
            self.progress.emit(80, "Virtual Environment bereit!")
            self.finished.emit(True, self.venv_path)
            
        except Exception as e:
            self.finished.emit(False, f"Fehler beim Erstellen des venv:\n{str(e)}")

class AddonBuilderWindow(QMainWindow):
    """GUI für den Addon Builder"""
    
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Pinguin Browser Addon Builder")
        self.setGeometry(100, 100, 800, 700)
        self.analyzer = DependencyAnalyzer()
        self.venv_builder = None
        self.setup_ui()
    
    def setup_ui(self):
        """Richtet die UI ein"""
        central = QWidget()
        self.setCentralWidget(central)
        layout = QVBoxLayout(central)
        layout.setSpacing(20)
        
        # Titel
        title = QLabel("🐧 Pinguin Browser Addon Builder")
        title_font = QFont()
        title_font.setPointSize(18)
        title_font.setBold(True)
        title.setFont(title_font)
        title.setStyleSheet("color: rgba(0,255,240,1); padding: 20px;")
        
        # FIXED: Qt.AlignCenter statt Qt.Alignment.AlignCenter
        title.setAlignment(Qt.AlignCenter)
        layout.addWidget(title)
        
        # Python-Datei auswählen
        file_row = QWidget()
        file_layout = QHBoxLayout(file_row)
        
        file_label = QLabel("Python-Datei:")
        file_label.setStyleSheet("font-weight: bold; min-width: 120px;")
        file_layout.addWidget(file_label)
        
        self.file_path = QLineEdit()
        self.file_path.setPlaceholderText("addon.py")
        file_layout.addWidget(self.file_path)
        
        browse_btn = QPushButton("Durchsuchen")
        browse_btn.clicked.connect(self.browse_file)
        file_layout.addWidget(browse_btn)
        
        layout.addWidget(file_row)
        
        # Addon-Name
        name_row = QWidget()
        name_layout = QHBoxLayout(name_row)
        
        name_label = QLabel("Addon-Name:")
        name_label.setStyleSheet("font-weight: bold; min-width: 120px;")
        name_layout.addWidget(name_label)
        
        self.addon_name = QLineEdit()
        self.addon_name.setPlaceholderText("Mein Addon")
        name_layout.addWidget(self.addon_name)
        
        layout.addWidget(name_row)
        
        # Autor
        author_row = QWidget()
        author_layout = QHBoxLayout(author_row)
        
        author_label = QLabel("Autor:")
        author_label.setStyleSheet("font-weight: bold; min-width: 120px;")
        author_layout.addWidget(author_label)
        
        self.addon_author = QLineEdit()
        self.addon_author.setPlaceholderText("Dein Name")
        author_layout.addWidget(self.addon_author)
        
        layout.addWidget(author_row)
        
        # Version
        version_row = QWidget()
        version_layout = QHBoxLayout(version_row)
        
        version_label = QLabel("Version:")
        version_label.setStyleSheet("font-weight: bold; min-width: 120px;")
        version_layout.addWidget(version_label)
        
        self.addon_version = QLineEdit()
        self.addon_version.setText("1.0.0")
        version_layout.addWidget(self.addon_version)
        
        layout.addWidget(version_row)
        
        # Beschreibung
        desc_label = QLabel("Beschreibung:")
        desc_label.setStyleSheet("font-weight: bold; margin-top: 10px;")
        layout.addWidget(desc_label)
        
        self.addon_description = QTextEdit()
        self.addon_description.setPlaceholderText("Beschreibe dein Addon...")
        self.addon_description.setMaximumHeight(100)
        layout.addWidget(self.addon_description)
        
        # Dependencies Info
        self.deps_info = QLabel("")
        self.deps_info.setStyleSheet("color: rgba(0,200,255,1); padding: 5px; font-size: 11px;")
        self.deps_info.setWordWrap(True)
        layout.addWidget(self.deps_info)
        
        # Virtual Environment Option
        self.include_venv = QCheckBox("Virtual Environment mit Dependencies erstellen (empfohlen)")
        self.include_venv.setChecked(True)
        self.include_venv.setStyleSheet("font-weight: bold; color: rgba(0,255,240,1);")
        layout.addWidget(self.include_venv)
        
        # Progress Bar
        self.progress = QProgressBar()
        self.progress.setVisible(False)
        layout.addWidget(self.progress)
        
        # Status Label
        self.status_label = QLabel("")
        self.status_label.setStyleSheet("color: rgba(0,255,240,1); padding: 10px;")
        
        # FIXED: Qt.AlignCenter statt Qt.Alignment.AlignCenter
        self.status_label.setAlignment(Qt.AlignCenter)
        self.status_label.setWordWrap(True)
        layout.addWidget(self.status_label)
        
        # Build Button
        build_btn = QPushButton("🔨 Addon erstellen (.pbcl)")
        build_btn.setStyleSheet("""
            QPushButton {
                background: rgba(0,255,240,1);
                color: #1a1c24;
                border: none;
                padding: 15px;
                border-radius: 8px;
                font-weight: bold;
                font-size: 14px;
            }
            QPushButton:hover {
                background: rgba(0,255,240,0.8);
            }
        """)
        build_btn.clicked.connect(self.build_addon)
        layout.addWidget(build_btn)
        
        layout.addStretch()
    
    def browse_file(self):
        """Öffnet Datei-Dialog"""
        filename, _ = QFileDialog.getOpenFileName(
            self,
            "Python-Datei auswählen",
            "",
            "Python Files (*.py);;All Files (*)"
        )
        if filename:
            self.file_path.setText(filename)
            
            # Auto-fill Name wenn leer
            if not self.addon_name.text():
                basename = os.path.splitext(os.path.basename(filename))[0]
                self.addon_name.setText(basename.replace('_', ' ').title())
            
            # Analysiere Dependencies
            self.analyze_file_dependencies()
    
    def analyze_file_dependencies(self):
        """Analysiert die Dependencies der ausgewählten Datei"""
        try:
            with open(self.file_path.text(), 'r', encoding='utf-8') as f:
                code = f.read()
            
            imports = self.analyzer.analyze_imports(code)
            external_deps = self.analyzer.filter_external_dependencies(imports)
            
            if external_deps:
                deps_text = f"📦 Erkannte Dependencies: {', '.join(sorted(external_deps))}"
            else:
                deps_text = "✓ Keine externen Dependencies gefunden"
            
            self.deps_info.setText(deps_text)
            
        except Exception as e:
            self.deps_info.setText(f"⚠️ Fehler beim Analysieren: {str(e)}")
    
    def build_addon(self):
        """Erstellt die .pbcl Datei"""
        # Validierung
        if not self.file_path.text():
            QMessageBox.warning(self, "Fehler", "Bitte wähle eine Python-Datei aus!")
            return
        
        if not os.path.exists(self.file_path.text()):
            QMessageBox.warning(self, "Fehler", "Datei existiert nicht!")
            return
        
        if not self.addon_name.text():
            QMessageBox.warning(self, "Fehler", "Bitte gib einen Addon-Namen ein!")
            return
        
        # Progress anzeigen
        self.progress.setVisible(True)
        self.progress.setValue(0)
        self.status_label.setText("Analysiere Code...")
        
        try:
            # Code laden
            with open(self.file_path.text(), 'r', encoding='utf-8') as f:
                code = f.read()
            
            # Dependencies analysieren
            imports = self.analyzer.analyze_imports(code)
            needs_sdk = self.analyzer.needs_sdk(imports)
            external_deps = self.analyzer.filter_external_dependencies(imports)
            
            self.progress.setValue(5)
            
            # Output-Pfad wählen
            output_file, _ = QFileDialog.getSaveFileName(
                self,
                "Addon speichern",
                f"{self.addon_name.text().replace(' ', '_')}.pbcl",
                "Pinguin Browser Addon (*.pbcl)"
            )
            
            if not output_file:
                self.progress.setVisible(False)
                self.status_label.setText("")
                return
            
            # Wenn venv erstellt werden soll
            if self.include_venv.isChecked() and external_deps:
                self.create_addon_with_venv(output_file, code, needs_sdk, external_deps)
            else:
                self.create_addon_simple(output_file, code, needs_sdk, external_deps)
                
        except Exception as e:
            self.progress.setVisible(False)
            self.status_label.setText(f"❌ Fehler: {str(e)}")
            QMessageBox.critical(self, "Fehler", f"Fehler beim Erstellen des Addons:\n{str(e)}")
    
    def create_addon_with_venv(self, output_file, code, needs_sdk, external_deps):
        """Erstellt Addon mit Virtual Environment"""
        temp_dir = tempfile.mkdtemp()
        
        try:
            self.status_label.setText(f"Erstelle Virtual Environment mit {len(external_deps)} Paketen...")
            
            # Venv Builder Thread starten
            self.venv_builder = VenvBuilder(temp_dir, external_deps)
            self.venv_builder.progress.connect(self.update_venv_progress)
            self.venv_builder.finished.connect(
                lambda success, msg: self.finish_addon_with_venv(
                    success, msg, output_file, code, needs_sdk, external_deps, temp_dir
                )
            )
            self.venv_builder.start()
            
        except Exception as e:
            shutil.rmtree(temp_dir, ignore_errors=True)
            raise e
    
    def update_venv_progress(self, value, message):
        """Aktualisiert Progress während venv-Erstellung"""
        self.progress.setValue(value)
        self.status_label.setText(message)
    
    def create_addon_simple(self, output_file, code, needs_sdk, external_deps):
        """Erstellt einfaches Addon ohne venv - Struktur optimiert"""
        self.progress.setValue(50)
        self.status_label.setText("Erstelle .pbcl Datei...")
        
        metadata = {
            "name": self.addon_name.text(),
            "author": self.addon_author.text(),
            "version": self.addon_version.text(),
            "description": self.addon_description.toPlainText(),
            "type": "addon",
            "requires_sdk": needs_sdk,
            "has_venv": False,
            "dependencies": list(external_deps)
        }
        
        with zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
            # WICHTIG: Root-Level Dateien
            zipf.writestr('metadata.json', json.dumps(metadata, indent=2))
            zipf.writestr('addon.py', code)
            
            # SDK nur hinzufügen, wenn wirklich benötigt
            if needs_sdk:
                # Hier Mock-SDK Dateien erzeugen, falls nicht vorhanden
                zipf.writestr('pinguinbrowser_sdk/__init__.py', '')
                zipf.writestr('pinguinbrowser_sdk/browser_api.py', '')
            
        self.progress.setValue(100)
        self.status_label.setText(f"✅ Addon erfolgreich erstellt!")
        QMessageBox.information(self, "Erfolg", f"Addon gespeichert: {output_file}")

    def finish_addon_with_venv(self, success, msg, output_file, code, needs_sdk, external_deps, temp_dir):
        """Beendet Addon-Erstellung mit venv"""
        if not success:
            self.progress.setVisible(False)
            self.status_label.setText(f"❌ {msg}")
            QMessageBox.critical(self, "Fehler", msg)
            shutil.rmtree(temp_dir, ignore_errors=True)
            return
        
        venv_path = msg
        
        try:
            self.progress.setValue(85)
            self.status_label.setText("Erstelle .pbcl Datei...")
            
            metadata = {
                "name": self.addon_name.text(),
                "author": self.addon_author.text(),
                "version": self.addon_version.text(),
                "description": self.addon_description.toPlainText(),
                "type": "addon",
                "requires_sdk": needs_sdk,
                "has_venv": True,
                "dependencies": list(external_deps)
            }
            
            with zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED) as zipf:
                zipf.writestr('metadata.json', json.dumps(metadata, indent=2))
                zipf.writestr('addon.py', code)
                
                if needs_sdk:
                    zipf.writestr('pinguinbrowser_sdk/__init__.py', '')
                    zipf.writestr('pinguinbrowser_sdk/browser_api.py', '')
                
                self.progress.setValue(90)
                self.status_label.setText("Packe Virtual Environment...")
                
                # Venv rekursiv packen
                venv_path_obj = Path(venv_path)
                for file_path in venv_path_obj.rglob('*'):
                    if file_path.is_file():
                        # Relativen Pfad im ZIP bewahren (venv/...)
                        arcname = os.path.join('venv', file_path.relative_to(venv_path_obj))
                        zipf.write(file_path, arcname)
            
            self.progress.setValue(100)
            self.status_label.setText(f"✅ Addon erfolgreich erstellt!")
            QMessageBox.information(self, "Erfolg", f"Addon mit Venv gespeichert: {output_file}")
            
        except Exception as e:
            self.progress.setVisible(False)
            self.status_label.setText(f"❌ Fehler: {str(e)}")
            QMessageBox.critical(self, "Fehler", f"Fehler beim Packen:\n{str(e)}")
        finally:
            shutil.rmtree(temp_dir, ignore_errors=True)

def build_addon():
    """Startet den Addon Builder"""
    app = QApplication(sys.argv)
    app.setStyle("Fusion")
    
    window = AddonBuilderWindow()
    window.show()
    
    sys.exit(app.exec_())

if __name__ == "__main__":
    build_addon()