/**
 * MYP Platform Offline-First Application
 * Version: 2.0.0
 * Description: Offline-fähige PWA für die MYP Plattform
 */

class MYPApp {
    constructor() {
        this.isOffline = !navigator.onLine;
        this.registerTime = new Date().toISOString();
        this.darkMode = document.documentElement.classList.contains('dark');
        this.setupOfflineDetection();
        this.setupServiceWorker();
        this.setupLocalStorage();
        this.setupUI();
        this.setupThemeListeners();
        
        // Debug-Info für die Entwicklung
        console.log(`MYP App initialisiert um ${this.registerTime}`);
        console.log(`Initiale Netzwerkverbindung: ${navigator.onLine ? 'Online' : 'Offline'}`);
        console.log(`Aktueller Modus: ${this.darkMode ? 'Dark Mode' : 'Light Mode'}`);
    }

    /**
     * Überwacht die Netzwerkverbindung
     */
    setupOfflineDetection() {
        window.addEventListener('online', () => {
            this.isOffline = false;
            document.body.classList.remove('offline-mode');
            console.log('Netzwerkverbindung wiederhergestellt!');
            
            // Bei Wiederverbindung: Synchronisiere Daten
            this.syncOfflineData();
            
            // Event an andere Komponenten senden
            window.dispatchEvent(new CustomEvent('networkStatusChange', { 
                detail: { isOffline: false } 
            }));
        });

        window.addEventListener('offline', () => {
            this.isOffline = true;
            document.body.classList.add('offline-mode');
            console.log('Netzwerkverbindung verloren!');
            
            // Event an andere Komponenten senden
            window.dispatchEvent(new CustomEvent('networkStatusChange', { 
                detail: { isOffline: true } 
            }));
        });
        
        // Klasse setzen, wenn initial offline
        if (this.isOffline) {
            document.body.classList.add('offline-mode');
        }
    }

    /**
     * Registriert den Service Worker für Offline-Funktionalität
     */
    setupServiceWorker() {
        if ('serviceWorker' in navigator) {
            const swPath = '/sw.js';
            
            navigator.serviceWorker.register(swPath, {
                scope: '/'
            }).then(registration => {
                console.log('Service Worker erfolgreich registriert mit Scope:', registration.scope);
                
                // Status des Service Workers überprüfen
                if (registration.installing) {
                    console.log('Service Worker wird installiert');
                } else if (registration.waiting) {
                    console.log('Service Worker wartet auf Aktivierung');
                } else if (registration.active) {
                    console.log('Service Worker ist aktiv');
                }
                
                // Auf Updates überwachen
                registration.addEventListener('updatefound', () => {
                    const newWorker = registration.installing;
                    
                    newWorker.addEventListener('statechange', () => {
                        console.log(`Service Worker Status: ${newWorker.state}`);
                        
                        // Bei Aktivierung Cache aktualisieren
                        if (newWorker.state === 'activated') {
                            this.fetchAndCacheAppData();
                        }
                    });
                });
                
                // Prüfen auf Update beim App-Start
                registration.update();
                
            }).catch(error => {
                console.error('Service Worker Registrierung fehlgeschlagen:', error);
                // Fallback auf lokalen Cache wenn Service Worker fehlschlägt
                this.setupLocalCache();
            });
            
            // Kontrolltransfer abfangen
            navigator.serviceWorker.addEventListener('controllerchange', () => {
                console.log('Service Worker Controller hat gewechselt');
            });
            
        } else {
            console.warn('Service Worker werden von diesem Browser nicht unterstützt');
            // Fallback auf lokalen Cache wenn Service Worker nicht unterstützt werden
            this.setupLocalCache();
        }
    }

    /**
     * Lokaler Cache-Fallback wenn Service Worker nicht verfügbar
     */
    setupLocalCache() {
        console.log('Verwende lokalen Cache als Fallback');
        
        // Wichtige App-Daten sofort laden und cachen
        this.fetchAndCacheAppData();
        
        // Timer für regelmäßige Aktualisierung des Cache
        setInterval(() => {
            if (navigator.onLine) {
                this.fetchAndCacheAppData();
            }
        }, 15 * 60 * 1000); // Alle 15 Minuten
    }
    
    /**
     * Laden und Cachen wichtiger API-Endpunkte
     */
    fetchAndCacheAppData() {
        if (!navigator.onLine) return;
        
        const endpoints = [
            '/api/printers',
            '/api/jobs',
            '/api/schedule',
            '/api/status'
        ];
        
        for (const endpoint of endpoints) {
            fetch(endpoint)
                .then(response => response.json())
                .then(data => {
                    localStorage.setItem(`cache_${endpoint}`, JSON.stringify({
                        timestamp: new Date().getTime(),
                        data: data
                    }));
                    console.log(`Daten für ${endpoint} gecached`);
                })
                .catch(error => {
                    console.error(`Fehler beim Cachen von ${endpoint}:`, error);
                });
        }
    }

    /**
     * Lokaler Speicher für Offline-Daten
     */
    setupLocalStorage() {
        // Speicher für Offline-Bearbeitung einrichten
        if (!localStorage.getItem('offlineChanges')) {
            localStorage.setItem('offlineChanges', JSON.stringify([]));
        }
        
        // Speicher für App-Konfiguration einrichten
        if (!localStorage.getItem('appConfig')) {
            const defaultConfig = {
                theme: 'system',
                notifications: true,
                dataSync: true,
                lastSync: null
            };
            localStorage.setItem('appConfig', JSON.stringify(defaultConfig));
        }
        
        // Aufräumen alter Cache-Einträge (älter als 7 Tage)
        this.cleanupOldCache(7);
    }
    
    /**
     * Entfernt alte Cache-Einträge
     * @param {number} daysOld - Alter in Tagen
     */
    cleanupOldCache(daysOld) {
        const now = new Date().getTime();
        const maxAge = daysOld * 24 * 60 * 60 * 1000;
        
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            
            // Nur Cache-Einträge prüfen
            if (key.startsWith('cache_')) {
                try {
                    const item = JSON.parse(localStorage.getItem(key));
                    if (item && item.timestamp && (now - item.timestamp > maxAge)) {
                        localStorage.removeItem(key);
                        console.log(`Alter Cache-Eintrag entfernt: ${key}`);
                    }
                } catch (e) {
                    console.error(`Fehler beim Verarbeiten von Cache-Eintrag ${key}:`, e);
                }
            }
        }
    }

    /**
     * Synchronisiert offline getätigte Änderungen
     */
    syncOfflineData() {
        if (!navigator.onLine) return;
        
        const offlineChanges = JSON.parse(localStorage.getItem('offlineChanges') || '[]');
        
        if (offlineChanges.length === 0) {
            console.log('Keine Offline-Änderungen zu synchronisieren');
            return;
        }
        
        console.log(`${offlineChanges.length} Offline-Änderungen werden synchronisiert...`);
        
        // Status-Indikator für Synchronisierung anzeigen
        document.body.classList.add('syncing');
        
        const syncPromises = offlineChanges.map(change => {
            return fetch(change.url, {
                method: change.method,
                headers: {
                    'Content-Type': 'application/json',
                    'X-Offline-Change': 'true'
                },
                body: JSON.stringify(change.data)
            })
            .then(response => {
                if (!response.ok) {
                    throw new Error(`Fehler ${response.status}: ${response.statusText}`);
                }
                return response.json();
            })
            .then(data => {
                console.log(`Änderung erfolgreich synchronisiert: ${change.url}`);
                return { success: true, change };
            })
            .catch(error => {
                console.error(`Synchronisierung fehlgeschlagen für ${change.url}:`, error);
                return { success: false, change, error };
            });
        });
        
        Promise.all(syncPromises)
            .then(results => {
                // Fehlgeschlagene Änderungen behalten
                const failedChanges = results
                    .filter(result => !result.success)
                    .map(result => result.change);
                
                localStorage.setItem('offlineChanges', JSON.stringify(failedChanges));
                
                // App-Konfiguration aktualisieren
                const appConfig = JSON.parse(localStorage.getItem('appConfig') || '{}');
                appConfig.lastSync = new Date().toISOString();
                localStorage.setItem('appConfig', JSON.stringify(appConfig));
                
                // Status-Indikator entfernen
                document.body.classList.remove('syncing');
                
                // Event-Benachrichtigung
                const syncEvent = new CustomEvent('offlineDataSynced', {
                    detail: {
                        total: offlineChanges.length,
                        succeeded: offlineChanges.length - failedChanges.length,
                        failed: failedChanges.length
                    }
                });
                window.dispatchEvent(syncEvent);
                
                console.log(`Synchronisierung abgeschlossen: ${offlineChanges.length - failedChanges.length} erfolgreich, ${failedChanges.length} fehlgeschlagen`);
            });
    }
    
    /**
     * Fügt Offline-Änderung zum Synchronisierungsstapel hinzu
     * @param {string} url - API-Endpunkt
     * @param {string} method - HTTP-Methode (POST, PUT, DELETE)
     * @param {object} data - Zu sendende Daten
     */
    addOfflineChange(url, method, data) {
        const offlineChanges = JSON.parse(localStorage.getItem('offlineChanges') || '[]');
        
        offlineChanges.push({
            id: Date.now().toString(36) + Math.random().toString(36).substr(2, 5),
            url,
            method,
            data,
            timestamp: new Date().toISOString()
        });
        
        localStorage.setItem('offlineChanges', JSON.stringify(offlineChanges));
        console.log(`Offline-Änderung gespeichert: ${method} ${url}`);
    }

    /**
     * Theme-Wechsel überwachen und reagieren
     */
    setupThemeListeners() {
        // Auf Dark Mode Änderungen reagieren
        window.addEventListener('darkModeChanged', (e) => {
            this.darkMode = e.detail.isDark;
            this.updateAppTheme();
            
            // App-Konfiguration aktualisieren
            const appConfig = JSON.parse(localStorage.getItem('appConfig') || '{}');
            appConfig.theme = this.darkMode ? 'dark' : 'light';
            localStorage.setItem('appConfig', JSON.stringify(appConfig));
            
            console.log(`Theme geändert: ${this.darkMode ? 'Dark Mode' : 'Light Mode'}`);
        });
        
        // Bei Systemthemen-Änderung prüfen, ob wir automatisch wechseln sollen
        window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => {
            const appConfig = JSON.parse(localStorage.getItem('appConfig') || '{}');
            
            // Nur reagieren, wenn der Nutzer "system" als Theme gewählt hat
            if (appConfig.theme === 'system') {
                this.darkMode = e.matches;
                this.updateAppTheme();
                console.log(`Systemthema geändert: ${this.darkMode ? 'Dark Mode' : 'Light Mode'}`);
            }
        });
    }
    
    /**
     * Theme im UI aktualisieren
     */
    updateAppTheme() {
        // Theme-color Meta-Tag aktualisieren für Mobile Browser
        const metaThemeColor = document.getElementById('metaThemeColor') || 
                              document.querySelector('meta[name="theme-color"]');
        if (metaThemeColor) {
            metaThemeColor.setAttribute('content', this.darkMode ? '#0f172a' : '#ffffff');
        }
        
        // Dynamische UI-Elemente anpassen
        this.updateUIForTheme();
    }
    
    /**
     * UI-Elemente für das aktuelle Theme anpassen
     */
    updateUIForTheme() {
        // Offline-Banner und Sync-Indikator anpassen
        const offlineBanner = document.getElementById('offline-banner');
        const syncIndicator = document.getElementById('sync-indicator');
        
        if (offlineBanner) {
            if (this.darkMode) {
                offlineBanner.classList.add('dark-theme');
                offlineBanner.classList.remove('light-theme');
            } else {
                offlineBanner.classList.add('light-theme');
                offlineBanner.classList.remove('dark-theme');
            }
        }
        
        if (syncIndicator) {
            if (this.darkMode) {
                syncIndicator.classList.add('dark-theme');
                syncIndicator.classList.remove('light-theme');
            } else {
                syncIndicator.classList.add('light-theme');
                syncIndicator.classList.remove('dark-theme');
            }
        }
        
        // Andere dynamische UI-Elemente hier anpassen
    }

    /**
     * UI-Komponenten initialisieren
     */
    setupUI() {
        // Offline-Modus Banner einfügen wenn nicht vorhanden
        if (!document.getElementById('offline-banner')) {
            const banner = document.createElement('div');
            banner.id = 'offline-banner';
            banner.className = `hidden fixed top-0 left-0 right-0 bg-amber-500 dark:bg-amber-600 text-white text-center py-2 px-4 z-50 ${this.darkMode ? 'dark-theme' : 'light-theme'}`;
            banner.textContent = 'Sie sind offline. Einige Funktionen sind eingeschränkt.';
            document.body.prepend(banner);
            
            // Anzeigen wenn offline
            if (this.isOffline) {
                banner.classList.remove('hidden');
            }
            
            // Event-Listener für Online/Offline-Status
            window.addEventListener('online', () => banner.classList.add('hidden'));
            window.addEventListener('offline', () => banner.classList.remove('hidden'));
        }
        
        // Synchronisierungs-Indikator einfügen wenn nicht vorhanden
        if (!document.getElementById('sync-indicator')) {
            const indicator = document.createElement('div');
            indicator.id = 'sync-indicator';
            indicator.className = `hidden fixed bottom-4 right-4 bg-indigo-600 dark:bg-indigo-700 text-white text-sm rounded-full py-1 px-3 z-50 flex items-center ${this.darkMode ? 'dark-theme' : 'light-theme'}`;
            
            const spinnerSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
            spinnerSvg.setAttribute('class', 'animate-spin -ml-1 mr-2 h-4 w-4 text-white');
            spinnerSvg.setAttribute('fill', 'none');
            spinnerSvg.setAttribute('viewBox', '0 0 24 24');
            
            const circle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
            circle.setAttribute('class', 'opacity-25');
            circle.setAttribute('cx', '12');
            circle.setAttribute('cy', '12');
            circle.setAttribute('r', '10');
            circle.setAttribute('stroke', 'currentColor');
            circle.setAttribute('stroke-width', '4');
            
            const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
            path.setAttribute('class', 'opacity-75');
            path.setAttribute('fill', 'currentColor');
            path.setAttribute('d', 'M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z');
            
            spinnerSvg.appendChild(circle);
            spinnerSvg.appendChild(path);
            
            const text = document.createElement('span');
            text.textContent = 'Synchronisiere...';
            
            indicator.appendChild(spinnerSvg);
            indicator.appendChild(text);
            document.body.appendChild(indicator);
            
            // Anzeigen wenn synchronisiert wird
            const observer = new MutationObserver((mutations) => {
                mutations.forEach((mutation) => {
                    if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
                        if (document.body.classList.contains('syncing')) {
                            indicator.classList.remove('hidden');
                        } else {
                            indicator.classList.add('hidden');
                        }
                    }
                });
            });
            
            observer.observe(document.body, { attributes: true });
        }
        
        // Mobile Optimierungen
        this.setupMobileOptimizations();
    }
    
    /**
     * Mobile Optimierungen
     */
    setupMobileOptimizations() {
        // Service Worker-Status auf mobilen Geräten überwachen und UI entsprechend anpassen
        if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
            // Verbessert Touch-Handhabung auf Mobilgeräten
            this.setupTouchFeedback();
            
            // Viewport-Höhe für mobile Browser anpassen (Adressleisten-Problem)
            this.fixMobileViewportHeight();
            
            // Scroll-Wiederherstellung deaktivieren für eine bessere UX auf Mobilgeräten
            if ('scrollRestoration' in history) {
                history.scrollRestoration = 'manual';
            }
        }
    }
    
    /**
     * Touch-Feedback für mobile Geräte
     */
    setupTouchFeedback() {
        // Aktive Klasse für Touch-Feedback hinzufügen
        document.addEventListener('touchstart', function(e) {
            if (e.target.tagName === 'BUTTON' || e.target.tagName === 'A' || 
                e.target.closest('button') || e.target.closest('a')) {
                const element = e.target.tagName === 'BUTTON' || e.target.tagName === 'A' ? 
                                e.target : (e.target.closest('button') || e.target.closest('a'));
                element.classList.add('touch-active');
            }
        }, { passive: true });
        
        document.addEventListener('touchend', function() {
            const activeElements = document.querySelectorAll('.touch-active');
            activeElements.forEach(el => el.classList.remove('touch-active'));
        }, { passive: true });
    }
    
    /**
     * Viewport-Höhe für mobile Browser fixieren
     */
    fixMobileViewportHeight() {
        // Mobile Viewport-Höhe berechnen und als CSS-Variable setzen
        const setViewportHeight = () => {
            const vh = window.innerHeight * 0.01;
            document.documentElement.style.setProperty('--vh', `${vh}px`);
        };
        
        // Initial setzen und bei Größenänderung aktualisieren
        setViewportHeight();
        window.addEventListener('resize', setViewportHeight);
        
        // Auch bei Orientierungsänderung aktualisieren
        window.addEventListener('orientationchange', () => {
            setTimeout(setViewportHeight, 100);
        });
    }
}

// App initialisieren wenn DOM geladen ist
document.addEventListener('DOMContentLoaded', () => {
    window.myp = new MYPApp();
});