#!/usr/bin/env python3
"""
MYP Platform - Requirements Update Script
Aktualisiert die Requirements basierend auf tatsächlich verwendeten Imports
"""

import os
import sys
import subprocess
import ast
import importlib.util
from pathlib import Path
from typing import Set, List, Dict

def get_imports_from_file(file_path: Path) -> Set[str]:
    """Extrahiert alle Import-Statements aus einer Python-Datei."""
    imports = set()
    
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            content = f.read()
        
        tree = ast.parse(content)
        
        for node in ast.walk(tree):
            if isinstance(node, ast.Import):
                for alias in node.names:
                    imports.add(alias.name.split('.')[0])
            elif isinstance(node, ast.ImportFrom):
                if node.module:
                    imports.add(node.module.split('.')[0])
    
    except Exception as e:
        print(f"Fehler beim Parsen von {file_path}: {e}")
    
    return imports

def get_all_imports(project_root: Path) -> Set[str]:
    """Sammelt alle Imports aus dem Projekt."""
    all_imports = set()
    
    # Wichtige Dateien analysieren
    important_files = [
        'app.py',
        'models.py',
        'utils/rate_limiter.py',
        'utils/job_scheduler.py',
        'utils/queue_manager.py',
        'utils/ssl_manager.py',
        'utils/security.py',
        'utils/permissions.py',
        'utils/analytics.py',
        'utils/template_helpers.py',
        'utils/logging_config.py'
    ]
    
    for file_path in important_files:
        full_path = project_root / file_path
        if full_path.exists():
            imports = get_imports_from_file(full_path)
            all_imports.update(imports)
            print(f"✓ Analysiert: {file_path} ({len(imports)} Imports)")
    
    return all_imports

def get_package_mapping() -> Dict[str, str]:
    """Mapping von Import-Namen zu PyPI-Paketnamen."""
    return {
        'flask': 'Flask',
        'flask_login': 'Flask-Login',
        'flask_wtf': 'Flask-WTF',
        'sqlalchemy': 'SQLAlchemy',
        'werkzeug': 'Werkzeug',
        'bcrypt': 'bcrypt',
        'cryptography': 'cryptography',
        'PyP100': 'PyP100',
        'redis': 'redis',
        'requests': 'requests',
        'jinja2': 'Jinja2',
        'markupsafe': 'MarkupSafe',
        'itsdangerous': 'itsdangerous',
        'psutil': 'psutil',
        'click': 'click',
        'blinker': 'blinker',
        'pywin32': 'pywin32',
        'pytest': 'pytest',
        'gunicorn': 'gunicorn'
    }

def get_current_versions() -> Dict[str, str]:
    """Holt die aktuell installierten Versionen."""
    versions = {}
    
    try:
        result = subprocess.run(['pip', 'list', '--format=freeze'], 
                              capture_output=True, text=True,
                              encoding='utf-8', errors='replace')
        
        for line in result.stdout.strip().split('\n'):
            if '==' in line:
                package, version = line.split('==', 1)
                versions[package.lower()] = version
    
    except Exception as e:
        print(f"Fehler beim Abrufen der Versionen: {e}")
    
    return versions

def check_package_availability(package: str, version: str = None) -> bool:
    """Prüft, ob ein Paket in der angegebenen Version verfügbar ist."""
    try:
        if version:
            cmd = ['pip', 'index', 'versions', package]
        else:
            cmd = ['pip', 'show', package]
        
        result = subprocess.run(cmd, capture_output=True, text=True,
                              encoding='utf-8', errors='replace')
        return result.returncode == 0
    
    except Exception:
        return False

def generate_requirements(imports: Set[str], versions: Dict[str, str]) -> List[str]:
    """Generiert die Requirements-Liste."""
    package_mapping = get_package_mapping()
    requirements = []
    
    # Standard-Bibliotheken, die nicht installiert werden müssen
    stdlib_modules = {
        'os', 'sys', 'logging', 'atexit', 'datetime', 'time', 'subprocess',
        'json', 'signal', 'threading', 'functools', 'typing', 'contextlib',
        'secrets', 'hashlib', 'calendar', 'random', 'socket', 'ipaddress',
        'enum', 'dataclasses', 'concurrent', 'collections'
    }
    
    # Lokale Module ausschließen
    local_modules = {
        'models', 'utils', 'config', 'blueprints'
    }
    
    # Nur externe Pakete berücksichtigen
    external_imports = imports - stdlib_modules - local_modules
    
    for import_name in sorted(external_imports):
        package_name = package_mapping.get(import_name, import_name)
        
        # Version aus installierten Paketen holen
        version = versions.get(package_name.lower())
        
        if version and check_package_availability(package_name, version):
            if package_name == 'pywin32':
                requirements.append(f"{package_name}=={version}; sys_platform == \"win32\"")
            else:
                requirements.append(f"{package_name}=={version}")
        else:
            print(f"⚠️ Paket {package_name} nicht gefunden oder Version unbekannt")
    
    return requirements

def write_requirements_file(requirements: List[str], output_file: Path):
    """Schreibt die Requirements in eine Datei."""
    header = """# MYP Platform - Python Dependencies
# Basierend auf tatsächlich verwendeten Imports in app.py
# Automatisch generiert am: {date}
# Installiere mit: pip install -r requirements.txt

# ===== CORE FLASK FRAMEWORK =====
# Direkt in app.py verwendet
{flask_requirements}

# ===== DATENBANK =====
# SQLAlchemy für Datenbankoperationen (models.py, app.py)
{db_requirements}

# ===== SICHERHEIT UND AUTHENTIFIZIERUNG =====
# Werkzeug für Passwort-Hashing und Utilities (app.py)
{security_requirements}

# ===== SMART PLUG STEUERUNG =====
# PyP100 für TP-Link Tapo Smart Plugs (utils/job_scheduler.py)
{smartplug_requirements}

# ===== RATE LIMITING UND CACHING =====
# Redis für Rate Limiting (utils/rate_limiter.py) - optional
{cache_requirements}

# ===== HTTP REQUESTS =====
# Requests für HTTP-Anfragen (utils/queue_manager.py, utils/debug_drucker_erkennung.py)
{http_requirements}

# ===== TEMPLATE ENGINE =====
# Jinja2 und MarkupSafe (automatisch mit Flask installiert, aber explizit für utils/template_helpers.py)
{template_requirements}

# ===== SYSTEM MONITORING =====
# psutil für System-Monitoring (utils/debug_utils.py, utils/debug_cli.py)
{monitoring_requirements}

# ===== ZUSÄTZLICHE CORE ABHÄNGIGKEITEN =====
# Click für CLI-Kommandos (automatisch mit Flask)
{core_requirements}

# ===== WINDOWS-SPEZIFISCHE ABHÄNGIGKEITEN =====
# Nur für Windows-Systeme erforderlich
{windows_requirements}

# ===== OPTIONAL: ENTWICKLUNG UND TESTING =====
# Nur für Entwicklungsumgebung
{dev_requirements}

# ===== OPTIONAL: PRODUKTIONS-SERVER =====
# Gunicorn für Produktionsumgebung
{prod_requirements}
"""
    
    # Requirements kategorisieren
    flask_reqs = [r for r in requirements if any(x in r.lower() for x in ['flask'])]
    db_reqs = [r for r in requirements if 'SQLAlchemy' in r]
    security_reqs = [r for r in requirements if any(x in r for x in ['Werkzeug', 'bcrypt', 'cryptography'])]
    smartplug_reqs = [r for r in requirements if 'PyP100' in r]
    cache_reqs = [r for r in requirements if 'redis' in r]
    http_reqs = [r for r in requirements if 'requests' in r]
    template_reqs = [r for r in requirements if any(x in r for x in ['Jinja2', 'MarkupSafe', 'itsdangerous'])]
    monitoring_reqs = [r for r in requirements if 'psutil' in r]
    core_reqs = [r for r in requirements if any(x in r for x in ['click', 'blinker'])]
    windows_reqs = [r for r in requirements if 'sys_platform' in r]
    
    from datetime import datetime
    
    content = header.format(
        date=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
        flask_requirements='\n'.join(flask_reqs) or '# Keine Flask-spezifischen Requirements',
        db_requirements='\n'.join(db_reqs) or '# Keine Datenbank-Requirements',
        security_requirements='\n'.join(security_reqs) or '# Keine Sicherheits-Requirements',
        smartplug_requirements='\n'.join(smartplug_reqs) or '# Keine Smart Plug Requirements',
        cache_requirements='\n'.join(cache_reqs) or '# Keine Cache-Requirements',
        http_requirements='\n'.join(http_reqs) or '# Keine HTTP-Requirements',
        template_requirements='\n'.join(template_reqs) or '# Keine Template-Requirements',
        monitoring_requirements='\n'.join(monitoring_reqs) or '# Keine Monitoring-Requirements',
        core_requirements='\n'.join(core_reqs) or '# Keine Core-Requirements',
        windows_requirements='\n'.join(windows_reqs) or '# Keine Windows-Requirements',
        dev_requirements='pytest==8.3.4; extra == "dev"\npytest-cov==6.0.0; extra == "dev"',
        prod_requirements='gunicorn==23.0.0; extra == "prod"'
    )
    
    with open(output_file, 'w', encoding='utf-8') as f:
        f.write(content)

def main():
    """Hauptfunktion."""
    print("🔄 MYP Platform Requirements Update")
    print("=" * 50)
    
    # Projekt-Root ermitteln
    project_root = Path(__file__).parent
    
    print(f"📁 Projekt-Verzeichnis: {project_root}")
    
    # Imports sammeln
    print("\n📋 Sammle Imports aus wichtigen Dateien...")
    imports = get_all_imports(project_root)
    
    print(f"\n📦 Gefundene externe Imports: {len(imports)}")
    for imp in sorted(imports):
        print(f"  - {imp}")
    
    # Aktuelle Versionen abrufen
    print("\n🔍 Prüfe installierte Versionen...")
    versions = get_current_versions()
    
    # Requirements generieren
    print("\n⚙️ Generiere Requirements...")
    requirements = generate_requirements(imports, versions)
    
    # Requirements-Datei schreiben
    output_file = project_root / 'requirements.txt'
    write_requirements_file(requirements, output_file)
    
    print(f"\n✅ Requirements aktualisiert: {output_file}")
    print(f"📊 {len(requirements)} Pakete in requirements.txt")
    
    # Zusammenfassung
    print("\n📋 Generierte Requirements:")
    for req in requirements:
        print(f"  - {req}")
    
    print("\n🎉 Requirements-Update abgeschlossen!")
    print("\nNächste Schritte:")
    print("1. pip install -r requirements.txt")
    print("2. Anwendung testen")
    print("3. requirements-dev.txt und requirements-prod.txt bei Bedarf anpassen")

if __name__ == "__main__":
    main() 