#!/usr/bin/env python3
"""
╔══════════════════════════════════════════════════════════════╗
║  KI-Werkstatt – Offline-Setup                               ║
║  Lädt alle Abhängigkeiten herunter, damit die App           ║
║  komplett ohne Internet vom USB-Stick läuft.                 ║
║                                                              ║
║  Voraussetzung: Python 3.7+ (einmalig zum Vorbereiten)      ║
║  Ausführen:     python setup.py                              ║
╚══════════════════════════════════════════════════════════════╝
"""

import os
import sys
import urllib.request
import ssl
import json

# ── Konfiguration ──
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
ASSETS_DIR = os.path.join(BASE_DIR, 'assets')

KATEX_VERSION = '0.16.11'
KATEX_CDN = f'https://cdn.jsdelivr.net/npm/katex@{KATEX_VERSION}/dist'

MARKED_URL = 'https://cdn.jsdelivr.net/npm/marked/marked.min.js'

# Nunito von Google Fonts (woff2, latin + latin-ext)
NUNITO_CSS_URL = 'https://fonts.googleapis.com/css2?family=Nunito:wght@400;600;700;800&display=swap'

# KaTeX-Fontdateien (die wichtigsten, referenziert aus katex.min.css)
KATEX_FONTS = [
    'KaTeX_AMS-Regular.woff2',
    'KaTeX_Caligraphic-Bold.woff2',
    'KaTeX_Caligraphic-Regular.woff2',
    'KaTeX_Fraktur-Bold.woff2',
    'KaTeX_Fraktur-Regular.woff2',
    'KaTeX_Main-Bold.woff2',
    'KaTeX_Main-BoldItalic.woff2',
    'KaTeX_Main-Italic.woff2',
    'KaTeX_Main-Regular.woff2',
    'KaTeX_Math-BoldItalic.woff2',
    'KaTeX_Math-Italic.woff2',
    'KaTeX_SansSerif-Bold.woff2',
    'KaTeX_SansSerif-Italic.woff2',
    'KaTeX_SansSerif-Regular.woff2',
    'KaTeX_Script-Regular.woff2',
    'KaTeX_Size1-Regular.woff2',
    'KaTeX_Size2-Regular.woff2',
    'KaTeX_Size3-Regular.woff2',
    'KaTeX_Size4-Regular.woff2',
    'KaTeX_Typewriter-Regular.woff2',
]

# ── Hilfsfunktionen ──

def ensure_dir(path):
    os.makedirs(path, exist_ok=True)

def download(url, dest, description=''):
    """Datei herunterladen mit Fortschrittsanzeige."""
    label = description or os.path.basename(dest)
    print(f'  📥  {label} ... ', end='', flush=True)

    try:
        # SSL-Kontext für ältere Python-Versionen
        ctx = ssl.create_default_context()
        req = urllib.request.Request(url, headers={
            'User-Agent': 'Mozilla/5.0 (KI-Werkstatt Setup)'
        })
        with urllib.request.urlopen(req, context=ctx) as response:
            data = response.read()
            with open(dest, 'wb') as f:
                f.write(data)
        size_kb = len(data) / 1024
        if size_kb > 1024:
            print(f'OK ({size_kb/1024:.1f} MB)')
        else:
            print(f'OK ({size_kb:.0f} KB)')
        return data
    except Exception as e:
        print(f'FEHLER: {e}')
        return None

def download_text(url, description=''):
    """Text-Inhalt herunterladen und zurückgeben."""
    try:
        ctx = ssl.create_default_context()
        req = urllib.request.Request(url, headers={
            'User-Agent': 'Mozilla/5.0 (KI-Werkstatt Setup)'
        })
        with urllib.request.urlopen(req, context=ctx) as response:
            return response.read().decode('utf-8')
    except Exception as e:
        print(f'  ⚠️  Fehler beim Laden von {description}: {e}')
        return None

# ── Hauptlogik ──

def setup_katex():
    """KaTeX CSS, JS und Fonts herunterladen."""
    print('\n── KaTeX (Mathe-Rendering) ──')
    katex_dir = os.path.join(ASSETS_DIR, 'katex')
    fonts_dir = os.path.join(katex_dir, 'fonts')
    ensure_dir(fonts_dir)

    # CSS
    css_data = download(f'{KATEX_CDN}/katex.min.css',
                        os.path.join(katex_dir, 'katex.min.css'),
                        'katex.min.css')

    # CSS anpassen: Font-Pfade von url(fonts/...) bleiben relativ → passt bereits
    # Aber wir müssen sicherstellen, dass die CDN-URLs durch lokale ersetzt werden
    if css_data:
        css_text = css_data.decode('utf-8')
        # Ersetze absolute CDN-URLs durch relative Pfade
        css_text = css_text.replace(
            f'url(fonts/', 'url(fonts/'
        ).replace(
            f'url(https://cdn.jsdelivr.net/npm/katex@{KATEX_VERSION}/dist/fonts/',
            'url(fonts/'
        )
        with open(os.path.join(katex_dir, 'katex.min.css'), 'w', encoding='utf-8') as f:
            f.write(css_text)

    # JS
    download(f'{KATEX_CDN}/katex.min.js',
             os.path.join(katex_dir, 'katex.min.js'),
             'katex.min.js')

    # Fonts
    print(f'  📦  {len(KATEX_FONTS)} Font-Dateien:')
    for font in KATEX_FONTS:
        download(f'{KATEX_CDN}/fonts/{font}',
                 os.path.join(fonts_dir, font),
                 f'  {font}')

def setup_marked():
    """marked.js herunterladen."""
    print('\n── marked.js (Markdown) ──')
    download(MARKED_URL,
             os.path.join(ASSETS_DIR, 'marked.min.js'),
             'marked.min.js')

def setup_nunito():
    """Nunito-Font herunterladen (woff2 + lokales CSS)."""
    print('\n── Nunito Font ──')
    fonts_dir = os.path.join(ASSETS_DIR, 'fonts')
    ensure_dir(fonts_dir)

    # Google Fonts CSS laden (enthält die echten woff2-URLs)
    print('  🔍  Lade Font-Metadaten von Google Fonts ...')
    # Wir brauchen einen User-Agent, der woff2 unterstützt
    try:
        ctx = ssl.create_default_context()
        req = urllib.request.Request(NUNITO_CSS_URL, headers={
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
        })
        with urllib.request.urlopen(req, context=ctx) as response:
            css_text = response.read().decode('utf-8')
    except Exception as e:
        print(f'  ⚠️  Fehler: {e}')
        print('  ⚠️  Nunito wird über System-Fallback geladen.')
        # Erstelle Fallback-CSS
        with open(os.path.join(fonts_dir, 'nunito.css'), 'w', encoding='utf-8') as f:
            f.write("/* Nunito konnte nicht geladen werden – Fallback auf System-Font */\n")
        return

    # woff2-URLs aus dem CSS extrahieren und herunterladen
    import re
    font_urls = re.findall(r'url\((https://fonts\.gstatic\.com/[^)]+\.woff2)\)', css_text)
    local_css = css_text

    for i, url in enumerate(font_urls):
        filename = f'nunito-{i}.woff2'
        download(url, os.path.join(fonts_dir, filename), filename)
        local_css = local_css.replace(url, filename)

    # Lokales CSS schreiben
    with open(os.path.join(fonts_dir, 'nunito.css'), 'w', encoding='utf-8') as f:
        f.write(local_css)
    print(f'  ✅  {len(font_urls)} Font-Varianten + CSS gespeichert')

def verify():
    """Prüfe, ob alle Dateien vorhanden sind."""
    print('\n── Überprüfung ──')
    required = [
        'assets/katex/katex.min.css',
        'assets/katex/katex.min.js',
        'assets/marked.min.js',
        'assets/fonts/nunito.css',
    ]
    all_ok = True
    for rel_path in required:
        full = os.path.join(BASE_DIR, rel_path)
        if os.path.exists(full):
            print(f'  ✅  {rel_path}')
        else:
            print(f'  ❌  {rel_path} FEHLT')
            all_ok = False

    # Prüfe ob llama-server.exe und Modell vorhanden sind
    print()
    llama = os.path.join(BASE_DIR, 'llama-server.exe')
    if os.path.exists(llama):
        print(f'  ✅  llama-server.exe gefunden')
    else:
        print(f'  ⚠️  llama-server.exe fehlt noch!')
        print(f'       → Download: https://github.com/ggerganov/llama.cpp/releases')
        print(f'       → Datei \"llama-server.exe\" hierher kopieren: {BASE_DIR}')

    gguf_files = [f for f in os.listdir(BASE_DIR) if f.endswith('.gguf')]
    if gguf_files:
        for g in gguf_files:
            size_gb = os.path.getsize(os.path.join(BASE_DIR, g)) / (1024**3)
            print(f'  ✅  Modell: {g} ({size_gb:.1f} GB)')
    else:
        print(f'  ⚠️  Keine .gguf-Modelldatei gefunden!')
        print(f'       → Empfehlung: gemma-3-4b-it-Q4_K_M.gguf')
        print(f'       → Download: https://huggingface.co/bartowski/google_gemma-3-4b-it-GGUF')

    return all_ok

# ── Main ──

def main():
    print('╔══════════════════════════════════════════════════╗')
    print('║       KI-Werkstatt – Offline-Setup               ║')
    print('╚══════════════════════════════════════════════════╝')
    print(f'\nZielverzeichnis: {BASE_DIR}')

    ensure_dir(ASSETS_DIR)

    setup_katex()
    setup_marked()
    setup_nunito()
    ok = verify()

    print('\n' + '═' * 52)
    if ok:
        print('  ✅  Alle Web-Assets sind bereit!')
    else:
        print('  ⚠️  Einige Dateien fehlen (siehe oben).')
    print()
    print('  Nächste Schritte:')
    print('  1. llama-server.exe + .gguf-Modell hierher kopieren')
    print('  2. start.bat anpassen (Modellname prüfen)')
    print('  3. Gesamten Ordner auf USB-Stick kopieren')
    print('  4. Auf dem Schulrechner: start.bat doppelklicken')
    print('═' * 52)

if __name__ == '__main__':
    main()
