<?php
/**
 * PWA Controller Class - PocketBooking Pro
 * 
 * Zentraler Controller für die PWA-Funktionalität:
 * - Assets laden (CSS/JS)
 * - Navigation ausgeben
 * - Manifest generieren (mit kritischen id/scope Feldern!)
 * - Service Worker registrieren
 * - App Settings Tab
 *
 * @package SimpleBookingCalendar
 * @since 1.2.0
 * @updated 2.1.0 - Manifest id/scope für WebAPK-Identität hinzugefügt
 */

if (!defined('ABSPATH')) {
    exit;
}

class Simpbook_PWA_Controller {
    
    /**
     * Singleton Instance
     */
    private static $instance = null;
    
    /**
     * PWA Plugin Seiten
     */
    private $pwa_pages = array(
        'simpbook-dashboard',
        'simpbook-reservierungen',
        'simpbook-reservierungen-neu',
        'simpbook-reservierung-bearbeiten',
        'simpbook-kalender',
        'simpbook-dienstleistungen',
        'simpbook-dienstleistung-bearbeiten',
        'simpbook-mitarbeiter',
        'simpbook-mitarbeiter-bearbeiten',
        'simpbook-statistiken',
        'simpbook-reservierungen-einstellungen'
    );
    
    /**
     * Get Instance (Singleton)
     */
    public static function get_instance() {
        if (null === self::$instance) {
            self::$instance = new self();
        }
        return self::$instance;
    }
    
    /**
     * Constructor
     */
    private function __construct() {
        $this->init_hooks();
    }
    
    /**
     * Initialize Hooks
     */
    private function init_hooks() {
        // Rewrite Rules für schöne URLs
        add_action('init', array($this, 'register_rewrite_rules'));
        add_filter('query_vars', array($this, 'register_query_vars'));
        
        // Manifest & Service Worker via template_redirect (vor AJAX-Fallback)
        add_action('template_redirect', array($this, 'serve_pwa_files'), 1);
        
        // Admin Assets laden
        add_action('admin_enqueue_scripts', array($this, 'enqueue_pwa_assets'), 20);
        
        // ⭐ KRITISCH: Manifest-Link IMMER ausgeben (nicht nur im PWA-Modus!)
        // Der Browser lädt das Manifest VOR der Installation
        add_action('admin_head', array($this, 'output_pwa_manifest_link'), 1);
        
        // Body Class für PWA-Modus
        add_filter('admin_body_class', array($this, 'add_pwa_body_class'));
        
        // PWA Navigation ausgeben
        add_action('in_admin_header', array($this, 'output_pwa_navigation'), 1);
        
        // Manifest & Service Worker AJAX Handler (Fallback)
        add_action('wp_ajax_simpbook_pwa_manifest', array($this, 'ajax_output_manifest'));
        add_action('wp_ajax_nopriv_simpbook_pwa_manifest', array($this, 'ajax_output_manifest'));
        add_action('wp_ajax_simpbook_service_worker', array($this, 'ajax_output_service_worker'));
        add_action('wp_ajax_nopriv_simpbook_service_worker', array($this, 'ajax_output_service_worker'));
        
        // App Email senden
        add_action('wp_ajax_simpbook_send_app_access_email', array($this, 'ajax_send_app_access_email'));
        
        // Push-Notification AJAX Handler
        add_action('wp_ajax_simpbook_pwa_subscribe', array($this, 'ajax_subscribe_push'));
        add_action('wp_ajax_simpbook_pwa_unsubscribe', array($this, 'ajax_unsubscribe_push'));
        add_action('wp_ajax_simpbook_pwa_generate_keys', array($this, 'ajax_generate_vapid_keys'));
        add_action('wp_ajax_simpbook_pwa_test_push', array($this, 'ajax_test_push'));
        add_action('wp_ajax_simpbook_pwa_clear_subscriptions', array($this, 'ajax_clear_subscriptions'));
        
        // Settings Save Handler - MUSS VOR simpbook_einstellungen_formular_verarbeiten laufen (Priority 1)
        // Daher Priority 0, damit PWA-Settings ZUERST gespeichert werden
        add_action('admin_init', array($this, 'handle_settings_save'), 0);
        
        // App Settings Tab
        add_filter('simpbook_settings_tabs', array($this, 'add_app_settings_tab'));
        add_action('simpbook_settings_tab_content_app', array($this, 'render_app_settings_tab'));
        add_action('simpbook_settings_save', array($this, 'save_app_settings'));
    }
    
    /**
     * Register Rewrite Rules für schöne URLs
     * 
     * Ermöglicht:
     * - /simpbook-manifest.json → Manifest
     * - /simpbook-sw.js → Service Worker (mit Root-Scope!)
     */
    public function register_rewrite_rules() {
        // Manifest: /simpbook-manifest.json
        add_rewrite_rule(
            '^simpbook-manifest\.json$',
            'index.php?simpbook_manifest=1',
            'top'
        );
        
        // Service Worker: /simpbook-sw.js (muss von Root kommen für maximalen Scope!)
        add_rewrite_rule(
            '^simpbook-sw\.js$',
            'index.php?simpbook_sw=1',
            'top'
        );
    }
    
    /**
     * Register Query Variables
     */
    public function register_query_vars($vars) {
        $vars[] = 'simpbook_manifest';
        $vars[] = 'simpbook_sw';
        return $vars;
    }
    
    /**
     * Serve PWA Files (Manifest & Service Worker)
     * 
     * Wird vor WordPress-Template geladen für schnelle Auslieferung
     */
    public function serve_pwa_files() {
        global $wp_query;
        
        // Manifest oder Service Worker angefragt?
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $is_manifest = isset($wp_query->query_vars['simpbook_manifest']) || 
                       // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                       isset($_GET['simpbook_manifest']);
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $is_sw = isset($wp_query->query_vars['simpbook_sw']) || 
                 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
                 isset($_GET['simpbook_sw']);
        
        if ($is_manifest || $is_sw) {
            // Canonical redirect verhindern
            remove_action('template_redirect', 'redirect_canonical');
        }
        
        // Manifest ausliefern
        if ($is_manifest) {
            $this->output_manifest();
            exit;
        }
        
        // Service Worker ausliefern
        if ($is_sw) {
            $this->output_service_worker();
            exit;
        }
    }
    
    /**
     * Output Manifest
     * 
     * ⚠️ KRITISCH für WebAPK-Identität (Android):
     * - "id" muss gesetzt sein (sonst nutzt Chrome start_url als ID = instabil)
     * - "scope" muss "/" sein, damit Push-URLs innerhalb der App funktionieren
     */
    public function output_manifest() {
        // PWA nicht aktiviert? 404 zurückgeben
        if (!$this->is_pwa_enabled()) {
            status_header(404);
            echo wp_json_encode(array('error' => 'PWA not enabled'));
            exit;
        }
        
        // Headers für JSON - kurzer Cache damit Icon-Änderungen schnell wirksam werden
        header('Content-Type: application/manifest+json; charset=utf-8');
        header('Cache-Control: public, max-age=3600'); // 1h Cache (war 24h)
        header('X-Content-Type-Options: nosniff');
        
        echo wp_json_encode($this->get_manifest_data(), JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
    }
    
    /**
     * AJAX Fallback für Manifest
     */
    public function ajax_output_manifest() {
        $this->output_manifest();
        exit;
    }
    
    /**
     * Output Service Worker
     * 
     * ⚠️ WICHTIG: Service Worker NIEMALS cachen!
     * Browser prüft alle 24h auf Updates - Cache = keine Updates
     */
    public function output_service_worker() {
        // Service Worker ohne Cache ausliefern
        header('Content-Type: application/javascript; charset=utf-8');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Service-Worker-Allowed: /'); // Erlaubt Scope: "/" auch wenn von /simpbook-sw.js
        header('X-Content-Type-Options: nosniff');
        
        $sw_path = SIMPBOOK_PLUGIN_DIR . 'service-worker.js';
        
        if (file_exists($sw_path)) {
            // Nutzung von WP_Filesystem statt readfile() zur Einhaltung der WP-Standards
            global $wp_filesystem;
            if (empty($wp_filesystem)) {
                require_once ABSPATH . 'wp-admin/includes/file.php';
                WP_Filesystem();
            }
            
            if ($wp_filesystem) {
                // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Das ist der Inhalt einer lokalen JavaScript-Datei, Escaping würde den Code zerstören.
                echo $wp_filesystem->get_contents($sw_path);
            }
        } else {
            // Fallback: Minimaler Service Worker
            echo "// PocketBooking Service Worker - Fallback\n";
            echo "self.addEventListener('install', () => self.skipWaiting());\n";
            echo "self.addEventListener('activate', () => self.clients.claim());\n";
        }
    }
    
    /**
     * AJAX Fallback für Service Worker
     */
    public function ajax_output_service_worker() {
        $this->output_service_worker();
        exit;
    }
    
    /**
     * Get Manifest Data
     * 
     * Generiert das vollständige Manifest mit allen kritischen Feldern
     */
    private function get_manifest_data() {
        $theme_color = get_option('simpbook_container_background', '#667eea');
        $business_name = get_option('simpbook_firmen_name', get_bloginfo('name'));
        
        // ⭐ App-Name & Kurzname aus separaten Einstellungen (Guide-konform)
        $app_name = get_option('simpbook_pwa_app_name', '');
        $app_short_name = get_option('simpbook_pwa_app_short_name', '');
        
        // Fallback auf Firmennamen wenn nicht gesetzt
        if (empty($app_name)) {
            $app_name = $business_name . ' - ' . __('Bookings', 'simple-appointment-booking');
        }
        if (empty($app_short_name)) {
            $app_short_name = mb_substr($business_name, 0, 12);
        }
        
        /* translators: %s: Business name */
        $description = sprintf(__('%s Buchungs-App', 'simple-appointment-booking'), $business_name);
        
        // Start URL mit PWA Parameter
        $start_url = admin_url('admin.php?page=simpbook-dashboard&pwa=1');
        
        $manifest = array(
            // App-Name (aus Einstellungen)
            'name' => $app_name,
            'short_name' => $app_short_name,
            'description' => $description,
            
            // ⭐ KRITISCH für WebAPK-Identität!
            // Ohne id nutzt Chrome start_url als ID → ID ändert sich bei URL-Parametern
            'id' => '/',
            
            // ⭐ KRITISCH für Push-Notifications!
            // Scope "/" = Push-URLs funktionieren überall
            // Ohne scope: Default = start_url Directory = Push-URLs außerhalb = Chrome-Logo!
            'scope' => '/',
            
            'start_url' => $start_url,
            'display' => 'standalone',
            'orientation' => 'portrait',
            'theme_color' => $theme_color,
            'background_color' => '#ffffff',
            
            // Icons (any + maskable für Android Adaptive Icons)
            'icons' => $this->get_manifest_icons(),
            
            // Zusätzliche Metadaten
            'categories' => array('business', 'productivity'),
            'lang' => get_locale(),
            'dir' => is_rtl() ? 'rtl' : 'ltr',
            
            // Shortcuts für Quick Actions (optional)
            'shortcuts' => $this->get_manifest_shortcuts()
        );
        
        return $manifest;
    }
    
    /**
     * Get Manifest Icons
     * 
     * Icon-Typen:
     * - "any" = Standard-Icon für Homescreen
     * - "maskable" = Android Adaptive Icons (mit Safe Zone)
     * - "monochrome" = Notification Badge (links, klein, transparent)
     * 
     * ⚠️ WICHTIG für maskable Icons:
     * Android Adaptive Icons schneiden die äußeren 20% ab!
     * Der wichtige Inhalt muss in den inneren 80% liegen (Safe Zone).
     * Empfehlung: Icon mit ~20% Padding/Hintergrund um das Logo herum.
     */
    private function get_manifest_icons() {
        // Absolute Plugin-URL verwenden (wie im MRTR Plugin)
        $plugin_url = plugin_dir_url(dirname(__FILE__));
        
        // Custom Icons aus Einstellungen
        $custom_icon_512 = get_option('simpbook_pwa_icon_512', '');
        $custom_icon_192 = get_option('simpbook_pwa_icon_192', ''); // Automatisch generiert
        
        // MIME-Type basierend auf Dateiendung ermitteln
        $mime_512 = $this->get_icon_mime_type($custom_icon_512);
        $mime_192 = $this->get_icon_mime_type($custom_icon_192);
        
        $icons = array();
        
        // 192x192 Icon (Homescreen) - echte 192x192 Datei für beste Kompatibilität
        if (!empty($custom_icon_192)) {
            // Echtes 192x192 Icon verwenden (automatisch generiert)
            // "any" = für alle Zwecke, Browser wählt passende Form
            $icons[] = array(
                'src' => $custom_icon_192,
                'sizes' => '192x192',
                'type' => $mime_192,
                'purpose' => 'any'
            );
            // "maskable" separat - Android schneidet äußere 20% ab!
            $icons[] = array(
                'src' => $custom_icon_192,
                'sizes' => '192x192',
                'type' => $mime_192,
                'purpose' => 'maskable'
            );
        } elseif (!empty($custom_icon_512)) {
            // Fallback: 512x512 Icon mit 192x192 Deklaration (Browser skaliert)
            $icons[] = array(
                'src' => $custom_icon_512,
                'sizes' => '192x192',
                'type' => $mime_512,
                'purpose' => 'any'
            );
            $icons[] = array(
                'src' => $custom_icon_512,
                'sizes' => '192x192',
                'type' => $mime_512,
                'purpose' => 'maskable'
            );
        } else {
            // Default Icon
            $icons[] = array(
                'src' => $plugin_url . 'assets/icon-192.png',
                'sizes' => '192x192',
                'type' => 'image/png',
                'purpose' => 'any'
            );
            $icons[] = array(
                'src' => $plugin_url . 'assets/icon-192.png',
                'sizes' => '192x192',
                'type' => 'image/png',
                'purpose' => 'maskable'
            );
        }
        
        // 512x512 Icon (Splash Screen)
        if (!empty($custom_icon_512)) {
            $icons[] = array(
                'src' => $custom_icon_512,
                'sizes' => '512x512',
                'type' => $mime_512,
                'purpose' => 'any'
            );
            $icons[] = array(
                'src' => $custom_icon_512,
                'sizes' => '512x512',
                'type' => $mime_512,
                'purpose' => 'maskable'
            );
        } else {
            $icons[] = array(
                'src' => $plugin_url . 'assets/icon-512.png',
                'sizes' => '512x512',
                'type' => 'image/png',
                'purpose' => 'any'
            );
            $icons[] = array(
                'src' => $plugin_url . 'assets/icon-512.png',
                'sizes' => '512x512',
                'type' => 'image/png',
                'purpose' => 'maskable'
            );
        }
        
        // Monochrome Badge für Notifications (96x96)
        // ⚠️ Für Android Statusbar: MUSS weiß auf transparent sein!
        $icons[] = array(
            'src' => $plugin_url . 'templates/notification-badge-test.png',
            'sizes' => '96x96',
            'type' => 'image/png',
            'purpose' => 'monochrome'
        );
        
        return $icons;
    }
    
    /**
     * Get MIME Type from Icon URL
     * 
     * Ermittelt den korrekten MIME-Type basierend auf der Dateiendung.
     * Unterstützt: PNG, WEBP, JPG/JPEG, SVG
     * 
     * @param string $url Icon URL
     * @return string MIME-Type (default: image/png)
     */
    private function get_icon_mime_type($url) {
        if (empty($url)) {
            return 'image/png';
        }
        
        $extension = strtolower(pathinfo(wp_parse_url($url, PHP_URL_PATH), PATHINFO_EXTENSION));
        
        $mime_types = array(
            'png'  => 'image/png',
            'webp' => 'image/webp',
            'jpg'  => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'svg'  => 'image/svg+xml',
            'gif'  => 'image/gif',
        );
        
        return isset($mime_types[$extension]) ? $mime_types[$extension] : 'image/png';
    }
    
    /**
     * Get Manifest Shortcuts
     * 
     * Quick Actions für den App-Launcher
     */
    private function get_manifest_shortcuts() {
        return array(
            array(
                'name' => __('New Booking', 'simple-appointment-booking'),
                'short_name' => __('Neu', 'simple-appointment-booking'),
                'description' => __('Neue Reservierung erstellen', 'simple-appointment-booking'),
                'url' => admin_url('admin.php?page=simpbook-reservierungen-neu&pwa=1'),
                'icons' => array(
                    array(
                        'src' => SIMPBOOK_PLUGIN_URL . 'assets/shortcut-new.png',
                        'sizes' => '96x96',
                        'type' => 'image/png'
                    )
                )
            ),
            array(
                'name' => __('Calendar', 'simple-appointment-booking'),
                'short_name' => __('Calendar', 'simple-appointment-booking'),
                'description' => __('Open booking calendar', 'simple-appointment-booking'),
                'url' => admin_url('admin.php?page=simpbook-kalender&pwa=1'),
                'icons' => array(
                    array(
                        'src' => SIMPBOOK_PLUGIN_URL . 'assets/shortcut-calendar.png',
                        'sizes' => '96x96',
                        'type' => 'image/png'
                    )
                )
            )
        );
    }
    
    /**
     * Generate Scaled Icon (192x192 from 512x512)
     * 
     * Erstellt automatisch eine 192x192 Version des hochgeladenen 512x512 Icons.
     * Verwendet WordPress Image Editor (GD oder Imagick).
     * 
     * @param string $icon_512_url URL des 512x512 Icons
     * @return string|false URL des generierten 192x192 Icons oder false bei Fehler
     */
    private function generate_scaled_icon($icon_512_url) {
        if (empty($icon_512_url)) {
            return false;
        }
        
        // Attachment ID aus URL ermitteln
        $attachment_id = attachment_url_to_postid($icon_512_url);
        
        if (!$attachment_id) {
            // error_log('[Simpbook PWA] Icon-Skalierung: Attachment ID nicht gefunden für URL: ' . $icon_512_url);
            return false;
        }
        
        // Dateipfad ermitteln
        $file_path = get_attached_file($attachment_id);
        
        if (!$file_path || !file_exists($file_path)) {
            // error_log('[Simpbook PWA] Icon-Skalierung: Datei nicht gefunden: ' . $file_path);
            return false;
        }
        
        // Prüfen ob bereits eine 192x192 Version existiert
        $upload_dir = wp_upload_dir();
        $path_info = pathinfo($file_path);
        $icon_192_filename = $path_info['filename'] . '-192x192.' . $path_info['extension'];
        $icon_192_path = $path_info['dirname'] . '/' . $icon_192_filename;
        
        // Wenn 192x192 bereits existiert, URL zurückgeben
        if (file_exists($icon_192_path)) {
            // URL aus Pfad generieren
            $icon_192_url = str_replace(
                wp_normalize_path($upload_dir['basedir']),
                $upload_dir['baseurl'],
                wp_normalize_path($icon_192_path)
            );
            // error_log('[Simpbook PWA] Icon 192x192 bereits vorhanden: ' . $icon_192_url);
            return $icon_192_url;
        }
        
        // WordPress Image Editor verwenden
        $image_editor = wp_get_image_editor($file_path);
        
        if (is_wp_error($image_editor)) {
            // error_log('[Simpbook PWA] Icon-Skalierung: Image Editor Fehler: ' . $image_editor->get_error_message());
            return false;
        }
        
        // Auf 192x192 skalieren (crop = true für exakte Größe)
        $resized = $image_editor->resize(192, 192, true);
        
        if (is_wp_error($resized)) {
            // error_log('[Simpbook PWA] Icon-Skalierung: Resize Fehler: ' . $resized->get_error_message());
            return false;
        }
        
        // Qualität setzen (PNG = verlustfrei, aber kleinere Dateigröße)
        $image_editor->set_quality(90);
        
        // Speichern
        $saved = $image_editor->save($icon_192_path);
        
        if (is_wp_error($saved)) {
            // error_log('[Simpbook PWA] Icon-Skalierung: Speichern Fehler: ' . $saved->get_error_message());
            return false;
        }
        
        // URL aus Pfad generieren
        $icon_192_url = str_replace(
            wp_normalize_path($upload_dir['basedir']),
            $upload_dir['baseurl'],
            wp_normalize_path($saved['path'])
        );
        
        // Option speichern für spätere Verwendung
        update_option('simpbook_pwa_icon_192', $icon_192_url);
        
        // error_log('[Simpbook PWA] ✓ Icon 192x192 erfolgreich generiert: ' . $icon_192_url);
        
        return $icon_192_url;
    }
    
    /**
     * Enqueue PWA Assets
     */
    public function enqueue_pwa_assets($hook) {
        // Nur im PWA-Modus laden
        if (!simpbook_is_pwa_mode()) {
            return;
        }
        
        // Prüfe ob wir auf einer Plugin-Seite sind
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
        
        if (!in_array($page, $this->pwa_pages, true)) {
            return;
        }
        
        // PWA Mobile CSS
        wp_enqueue_style(
            'simpbook-pwa-mobile',
            SIMPBOOK_PLUGIN_URL . 'css/pwa-mobile.css',
            array('dashicons'),
            SIMPBOOK_VERSION
        );
        
        // Theme-Farbe als CSS-Variable
        $theme_color = get_option('simpbook_container_background', '#667eea');
        $custom_css = ":root { --simpbook-container-bg: {$theme_color}; }";
        wp_add_inline_style('simpbook-pwa-mobile', $custom_css);
        
        // PWA Navigation JS
        wp_enqueue_script(
            'simpbook-pwa-navigation',
            SIMPBOOK_PLUGIN_URL . 'js/pwa-navigation.js',
            array('jquery'),
            SIMPBOOK_VERSION,
            false // Im Header für sofortige Verfügbarkeit
        );
        
        // PWA Install & Push Handler
        wp_enqueue_script(
            'simpbook-pwa-install',
            SIMPBOOK_PLUGIN_URL . 'js/pwa-install.js',
            array('jquery'),
            SIMPBOOK_VERSION,
            true // Im Footer
        );
        
        // JS Config
        wp_localize_script('simpbook-pwa-navigation', 'simpbookPWAConfig', array(
            'ajaxUrl' => admin_url('admin-ajax.php'),
            'adminUrl' => admin_url('admin.php'),
            'nonce' => wp_create_nonce('simpbook_pwa_nonce'),
            'loginUrl' => wp_login_url() . '?pwa_login=1',
            'serviceWorkerUrl' => home_url('/simpbook-sw.js'),
            'vapidPublicKey' => get_option('simpbook_pwa_vapid_public_key', ''),
            'isEnabled' => $this->is_pwa_enabled(),
            'isPushEnabled' => get_option('simpbook_pwa_push_enabled', '0') === '1',
            'currentLanguage' => simpbook_get_current_language(), // ⭐ Für mehrsprachige Push-Notifications
            'i18n' => array(
                'sessionExpired' => __('Ihre Sitzung ist abgelaufen. Bitte melden Sie sich erneut an.', 'simple-appointment-booking'),
                'confirmLogout' => __('Do you really want to log out?', 'simple-appointment-booking'),
                'networkError' => __('Netzwerkfehler. Bitte versuchen Sie es erneut.', 'simple-appointment-booking')
            )
        ));
        
        // Zusätzliche Meta-Tags nur im PWA-Modus (Manifest-Link wird in init_hooks() registriert)
        add_action('admin_head', array($this, 'output_pwa_meta_tags'), 2);
    }
    
    /**
     * Output Manifest Link
     * 
     * ⚠️ KRITISCH: Muss IMMER ausgegeben werden (nicht nur im PWA-Modus!)
     * Der Browser lädt das Manifest VOR der Installation - zu diesem Zeitpunkt
     * ist ?pwa=1 noch nicht in der URL!
     */
    public function output_pwa_manifest_link() {
        // Nur auf Plugin-Seiten
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
        if (!in_array($page, $this->pwa_pages, true)) {
            return;
        }
        
        $manifest_url = home_url('/simpbook-manifest.json');
        ?>
        <!-- PWA Manifest Link - PocketBooking Pro -->
        <link rel="manifest" href="<?php echo esc_url($manifest_url); ?>">
        <?php
    }
    
    /**
     * Output PWA Meta Tags (nur im PWA-Modus)
     */
    public function output_pwa_meta_tags() {
        if (!simpbook_is_pwa_mode()) {
            return;
        }
        
        $theme_color = get_option('simpbook_container_background', '#667eea');
        $business_name = get_option('simpbook_firmen_name', get_bloginfo('name'));
        $icon_512 = get_option('simpbook_pwa_icon_512', SIMPBOOK_PLUGIN_URL . 'assets/icon-512.png');
        
        // Service Worker URL - muss von Root kommen für maximalen Scope
        $sw_url = home_url('/simpbook-sw.js');
        
        ?>
        <!-- PWA Meta Tags - PocketBooking Pro -->
        <!-- ⭐ viewport-fit=cover für iPhone Safe Area (Notch) -->
        <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover, maximum-scale=1.0, user-scalable=no">
        <meta name="theme-color" content="<?php echo esc_attr($theme_color); ?>">
        <meta name="mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-capable" content="yes">
        <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
        <meta name="apple-mobile-web-app-title" content="<?php echo esc_attr($business_name); ?>">
        <link rel="apple-touch-icon" href="<?php echo esc_url($icon_512); ?>">
        
        <!-- Service Worker Registration -->
        <script>
        (function() {
            if ('serviceWorker' in navigator) {
                window.addEventListener('load', function() {
                    navigator.serviceWorker.register('<?php echo esc_js($sw_url); ?>', {
                        scope: '/'
                    })
                    .then(function(registration) {
                        console.log('[Simpbook PWA] Service Worker registered with scope:', registration.scope);
                        
                        // Update-Check
                        registration.addEventListener('updatefound', function() {
                            console.log('[Simpbook PWA] Service Worker update found');
                        });
                    })
                    .catch(function(error) {
                        console.error('[Simpbook PWA] Service Worker registration failed:', error);
                    });
                });
            }
        })();
        </script>
        <?php
    }
    
    /**
     * Add PWA Body Class
     */
    public function add_pwa_body_class($classes) {
        if (simpbook_is_pwa_mode()) {
            $classes .= ' simpbook-pwa-mode';
        }
        return $classes;
    }
    
    /**
     * Output PWA Navigation
     */
    public function output_pwa_navigation() {
        if (!simpbook_is_pwa_mode()) {
            return;
        }
        
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $page = isset($_GET['page']) ? sanitize_text_field(wp_unslash($_GET['page'])) : '';
        
        if (!in_array($page, $this->pwa_pages, true)) {
            return;
        }
        
        // Navigation Template laden
        $template = SIMPBOOK_PLUGIN_DIR . 'templates/pwa-navigation.php';
        
        if (file_exists($template)) {
            include $template;
        }
    }
    
    /**
     * AJAX: Send App Access Email
     */
    public function ajax_send_app_access_email() {
        check_ajax_referer('simpbook_app_email_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error(array(
                'message' => __('Keine Berechtigung.', 'simple-appointment-booking')
            ));
        }
        
        $mitarbeiter_id = isset($_POST['mitarbeiter_id']) ? intval($_POST['mitarbeiter_id']) : 0;
        
        if (!$mitarbeiter_id) {
            wp_send_json_error(array(
                'message' => __('Invalid staff member ID.', 'simple-appointment-booking')
            ));
        }
        
        // PWA Auth Class verwenden
        if (class_exists('Simpbook_PWA_Auth')) {
            $auth = Simpbook_PWA_Auth::get_instance();
            $result = $auth->send_app_access_email($mitarbeiter_id);
            
            if ($result) {
                wp_send_json_success(array(
                    'message' => __('E-Mail wurde erfolgreich gesendet.', 'simple-appointment-booking')
                ));
            } else {
                wp_send_json_error(array(
                    'message' => __('E-Mail konnte nicht gesendet werden.', 'simple-appointment-booking')
                ));
            }
        } else {
            wp_send_json_error(array(
                'message' => __('PWA Auth class not available.', 'simple-appointment-booking')
            ));
        }
    }
    
    /**
     * Add App Settings Tab
     */
    public function add_app_settings_tab($tabs) {
        $tabs['app'] = array(
            'title' => __('App', 'simple-appointment-booking'),
            'icon' => 'dashicons-smartphone'
        );
        return $tabs;
    }
    
    /**
     * Render App Settings Tab Content
     */
    public function render_app_settings_tab() {
        $pwa_enabled = get_option('simpbook_pwa_enabled', '1'); // Default: aktiviert
        
        // Default App Icon aus Assets
        $default_icon_url = SIMPBOOK_PLUGIN_URL . 'assets/App-Icon.png';
        $icon_512 = get_option('simpbook_pwa_icon_512', $default_icon_url);
        
        if (empty($icon_512)) {
            $icon_512 = $default_icon_url;
        }

        $business_name = get_option('simpbook_firmen_name', get_bloginfo('name'));
        
        // App-Name und Kurzname (Guide-konform)
        $app_name = get_option('simpbook_pwa_app_name', $business_name);
        $app_short_name = get_option('simpbook_pwa_app_short_name', mb_substr($business_name, 0, 12));
        
        // PWA Install URL
        $pwa_url = admin_url('admin.php?page=simpbook-dashboard&pwa=1');
        $login_url = wp_login_url() . '?pwa_login=1';
        
        // QR-Code URL
        $qr_url = 'https://api.qrserver.com/v1/create-qr-code/?size=200x200&data=' . urlencode($login_url);
        
        // Media Library laden
        wp_enqueue_media();
        
        ?>
        <div class="simpbook-settings-section">
            <h2 class="simpbook-section-title">
                <span class="dashicons dashicons-smartphone"></span>
                <?php esc_html_e('Booking App (PWA)', 'simple-appointment-booking'); ?>
            </h2>
            
            <!-- PWA Aktivierung -->
            <table class="form-table">
                <tr>
                    <th scope="row"><?php esc_html_e('Enable PWA', 'simple-appointment-booking'); ?></th>
                    <td>
                        <label>
                            <input type="checkbox" 
                                   name="simpbook_pwa_enabled" 
                                   value="1" 
                                   <?php checked($pwa_enabled, '1'); ?>>
                            <?php esc_html_e('Enable Progressive Web App', 'simple-appointment-booking'); ?>
                            <p class="description">                      <?php esc_html_e('Allows installation as an app on smartphones.', 'simple-appointment-booking'); ?>
                        </p>
                        </label>

                    </td>
                </tr>
            </table>
            
            <h3><?php esc_html_e('App Settings', 'simple-appointment-booking'); ?></h3>
            
            <table class="form-table">
                <tr>
                    <th scope="row">
                        <label for="simpbook_pwa_app_name"><?php esc_html_e('App Name', 'simple-appointment-booking'); ?></label>
                    </th>
                    <td>
                        <input type="text" 
                               name="simpbook_pwa_app_name" 
                               id="simpbook_pwa_app_name" 
                               value="<?php echo esc_attr($app_name); ?>" 
                               class="regular-text"
                               placeholder="<?php echo esc_attr($business_name); ?>">
                        <p class="description">
                            <?php esc_html_e('Full name of the app (e.g. "My Salon Bookings")', 'simple-appointment-booking'); ?>
                        </p>
                    </td>
                </tr>
                <tr>
                    <th scope="row">
                        <label for="simpbook_pwa_app_short_name"><?php esc_html_e('App Short Name', 'simple-appointment-booking'); ?></label>
                    </th>
                    <td>
                        <input type="text" 
                               name="simpbook_pwa_app_short_name" 
                               id="simpbook_pwa_app_short_name" 
                               value="<?php echo esc_attr($app_short_name); ?>" 
                               class="regular-text"
                               maxlength="12"
                               placeholder="<?php echo esc_attr(mb_substr($business_name, 0, 12)); ?>">
                        <p class="description">
                            <?php esc_html_e('Short name for home screen (max. 12 characters)', 'simple-appointment-booking'); ?>
                            <span id="short-name-counter" style="color: #666;"></span>
                        </p>
                    </td>
                </tr>
                <tr>
                    <th scope="row">
                        <label for="simpbook_pwa_icon_512"><?php esc_html_e('App Icon (512x512)', 'simple-appointment-booking'); ?></label>
                    </th>
                    <td>
                        <input type="text" 
                               name="simpbook_pwa_icon_512" 
                               id="simpbook_pwa_icon_512" 
                               value="<?php echo esc_url($icon_512); ?>" 
                               class="regular-text">
                        <button type="button" class="button simpbook-upload-icon" data-target="simpbook_pwa_icon_512">
                            <?php esc_html_e('Select image', 'simple-appointment-booking'); ?>
                        </button>
                        <?php if ($icon_512) : ?>
                            <div style="margin-top: 10px;">
                                <img src="<?php echo esc_url($icon_512); ?>" style="max-width: 128px; border-radius: 16px;">
                            </div>
                        <?php endif; ?>
                        <p class="description">
                            <?php esc_html_e('PNG image, 512x512 pixels. Automatically used for all icon sizes (splash screen, home screen, dashboard).', 'simple-appointment-booking'); ?>
                        </p>
                    </td>
                </tr>
                <?php
                // Push-Settings laden
                $push_enabled = get_option('simpbook_pwa_push_enabled', '0');
                $vapid_public = get_option('simpbook_pwa_vapid_public_key', '');
                $vapid_private = get_option('simpbook_pwa_vapid_private_key', '');
                ?>
                <tr>
                   
                            
                    <td>
                        <label>
                            <input type="checkbox" 
                                   name="simpbook_pwa_push_enabled" 
                                   id="simpbook_pwa_push_enabled" 
                                   value="1" 
                                   <?php checked($push_enabled, '1'); ?>>
                            <?php esc_html_e('Enable push notifications', 'simple-appointment-booking'); ?>
                            <p class="description">
                                <?php esc_html_e('When enabled, the app will request permission to send notifications on first launch.', 'simple-appointment-booking'); ?>
                            </p>
                        </label>
                        
                        <button type="button" id="simpbook_pwa_test_push_btn" class="button button-secondary" <?php disabled($push_enabled, '0'); ?> style="margin-top: 15px; margin-right: 5px;">
                            <span class="dashicons dashicons-megaphone" style="vertical-align: middle; margin-right: 5px;"></span>
                            <?php esc_html_e('Send test push', 'simple-appointment-booking'); ?>
                        </button>
                        
                        <button type="button" id="simpbook_pwa_clear_subscriptions_btn" class="button button-secondary" style="background: #dc3232 !important; color: white; border-color: #dc3232 !important; margin-top: 15px;">
                            <span class="dashicons dashicons-trash" style="vertical-align: middle; margin-right: 5px;"></span>
                            <?php esc_html_e('Delete old subscriptions', 'simple-appointment-booking'); ?>
                        </button>
                        
                        <!-- VAPID Erweiterte Einstellungen (versteckt für Endkunden) -->
                        <div id="simpbook-pwa-advanced-push" style="display: none; background: #f9f9f9; padding: 20px; border-radius: 8px; border: 1px solid #ddd; margin-top: 20px;">
                            <h4 style="margin-top: 0;"><?php esc_html_e('VAPID Security Keys', 'simple-appointment-booking'); ?></h4>
                            <p class="description" style="margin-bottom: 20px;">
                                <?php esc_html_e('These keys are required for communication with Google and Apple push services.', 'simple-appointment-booking'); ?>
                            </p>
                            
                            <?php if (!empty($vapid_public) && !empty($vapid_private)) : ?>
                                <div style="padding: 12px; background: #d4edda; border: 1px solid #c3e6cb; border-radius: 4px; margin-bottom: 15px; color: #155724;">
                                    <span class="dashicons dashicons-yes-alt" style="color: #28a745; vertical-align: middle;"></span>
                                    <strong><?php esc_html_e('Keys available', 'simple-appointment-booking'); ?></strong>
                                    <?php esc_html_e('- VAPID keys have been successfully generated.', 'simple-appointment-booking'); ?>
                                </div>
                            <?php else : ?>
                                <div style="padding: 12px; background: #fff3cd; border: 1px solid #ffc107; border-radius: 4px; margin-bottom: 15px; color: #856404;">
                                    <span class="dashicons dashicons-warning" style="color: #ffc107; vertical-align: middle;"></span>
                                    <strong><?php esc_html_e('No keys', 'simple-appointment-booking'); ?></strong>
                                    <?php esc_html_e('- Click on "Generate Keys" below.', 'simple-appointment-booking'); ?>
                                </div>
                            <?php endif; ?>
                            
                            <table class="form-table" style="margin: 0;">
                                <tr>
                                    <th scope="row">
                                        <label for="simpbook_pwa_vapid_public_key"><?php esc_html_e('VAPID Public Key', 'simple-appointment-booking'); ?></label>
                                    </th>
                                    <td>
                                        <input type="text" 
                                               name="simpbook_pwa_vapid_public_key" 
                                               id="simpbook_pwa_vapid_public_key" 
                                               value="<?php echo esc_attr($vapid_public); ?>" 
                                               class="large-text"
                                               placeholder="<?php echo empty($vapid_public) ? esc_attr__('Will be generated when saving...', 'simple-appointment-booking') : ''; ?>">
                                    </td>
                                </tr>
                                <tr>
                                    <th scope="row">
                                        <label for="simpbook_pwa_vapid_private_key"><?php esc_html_e('VAPID Private Key', 'simple-appointment-booking'); ?></label>
                                    </th>
                                    <td>
                                        <input type="password" 
                                               name="simpbook_pwa_vapid_private_key" 
                                               id="simpbook_pwa_vapid_private_key" 
                                               value="<?php echo esc_attr($vapid_private); ?>" 
                                               class="large-text"
                                               placeholder="<?php echo empty($vapid_private) ? esc_attr__('Will be generated when saving...', 'simple-appointment-booking') : ''; ?>">
                                    </td>
                                </tr>
                            </table>
                            
                            <div style="margin-top: 20px; display: flex; gap: 10px; flex-wrap: wrap;">
                                <button type="button" id="simpbook_pwa_generate_keys_btn" class="button button-primary">
                                    <span class="dashicons dashicons-update" style="vertical-align: middle; margin-right: 5px;"></span>
                                    <?php esc_html_e('Generate Keys', 'simple-appointment-booking'); ?>
                                </button>
                                <a href="https://vapidkeys.com/" target="_blank" class="button button-secondary">
                                    <?php esc_html_e('Externer Generator (Fallback)', 'simple-appointment-booking'); ?>
                                </a>
                            </div>
                            <div id="simpbook_vapid_error_box" style="display: none; margin-top: 15px; padding: 12px; background: #f8d7da; border: 1px solid #f5c6cb; border-radius: 4px; color: #721c24;">
                                <strong><?php esc_html_e('Error:', 'simple-appointment-booking'); ?></strong>
                                <span id="simpbook_vapid_error_msg"></span>
                            </div>
                        </div>
                    </td>
                </tr>
            </table>
            
            <?php if ($pwa_enabled === '1') : ?>
            <!-- App Install Box -->
            <div class="simpbook-app-install-box" style="background: linear-gradient(135deg, <?php echo esc_attr($theme_color); ?> 0%, #764ba2 100%); color: white; padding: 40px 20px; border-radius: 12px; margin-bottom: 30px; margin-top: 30px; text-align: center;">
                <div style="display: flex; flex-direction: column; gap: 30px; align-items: center; justify-content: center; min-height: 300px;">
                    <!-- App Name & Beschreibung -->
                    <div style="max-width: 600px; text-align: center;">
                        <h3 style="margin: 0 0 15px; font-size: 28px; color: white; font-weight: 700; line-height: 1.2;"><?php echo esc_html($app_name); ?></h3>
                        <p style="margin: 0 0 25px; opacity: 0.9; font-size: 16px; line-height: 1.5;">
                            <?php esc_html_e('Install the app on your smartphone to manage bookings on the go.', 'simple-appointment-booking'); ?>
                        </p>
                        
                        <!-- Buttons nur mobil sichtbar -->
                        <div class="simpbook-mobile-only" style="gap: 12px; flex-wrap: wrap; justify-content: center; margin-bottom: 10px;">
                            <a href="<?php echo esc_url($pwa_url); ?>" target="_blank" class="button button-secondary" style="background: white; color: <?php echo esc_attr($theme_color); ?>; border: none; padding: 5px 20px; height: auto; font-weight: 600;">
                                <span class="dashicons dashicons-external" style="margin-top: 6px;"></span>
                                <?php esc_html_e('Open app in browser', 'simple-appointment-booking'); ?>
                            </a>
                            <button type="button" class="button button-secondary simpbook-copy-url" data-url="<?php echo esc_url($login_url); ?>" style="background: rgba(255,255,255,0.2); color: white; border: 1px solid rgba(255,255,255,0.5); padding: 5px 20px; height: auto;">
                                <span class="dashicons dashicons-admin-links" style="margin-top: 6px;"></span>
                                <?php esc_html_e('Copy link', 'simple-appointment-booking'); ?>
                            </button>
                        </div>
                    </div>
                    
                    <!-- QR Code zentriert -->
                    <div style="text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; background: rgba(255,255,255,0.1); padding: 25px; border-radius: 15px; backdrop-filter: blur(5px);">
                        <div style="background: white; padding: 15px; border-radius: 12px; display: inline-block; line-height: 0; box-shadow: 0 10px 25px rgba(0,0,0,0.2);">
                            <img src="<?php echo esc_url($qr_url); ?>" alt="QR Code" style="display: block; width: 180px; height: 180px;">
                        </div>
                        <p style="margin: 15px 0 0; font-size: 14px; font-weight: 600; color: white;"><?php esc_html_e('Scan QR code', 'simple-appointment-booking'); ?></p>
                    </div>
                </div>
                
                <!-- Installationsanleitung innerhalb der Install Box -->
                <div style="margin-top: 30px; padding-top: 25px; border-top: 1px solid rgba(255,255,255,0.2);">
                    <h4 style="margin: 0 0 15px; font-size: 16px; color: white; font-weight: 600;"><?php esc_html_e('📱 How to install the app', 'simple-appointment-booking'); ?></h4>
                    <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px;">
                        <div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 8px;">
                            <h5 style="margin: 0 0 12px; color: white; font-size: 14px; font-weight: 600;">🍎 iOS (iPhone/iPad):</h5>
                            <ol style="margin: 0; padding-left: 20px; color: rgba(255,255,255,0.9); font-size: 13px; line-height: 1.8;">
                                <li><?php esc_html_e('Open the link in Safari', 'simple-appointment-booking'); ?></li>
                                <li><?php esc_html_e('Tap the share icon (square with arrow)', 'simple-appointment-booking'); ?></li>
                                <li><?php esc_html_e('Select "Add to Home Screen"', 'simple-appointment-booking'); ?></li>
                            </ol>
                        </div>
                        <div style="background: rgba(255,255,255,0.1); padding: 20px; border-radius: 8px;">
                            <h5 style="margin: 0 0 12px; color: white; font-size: 14px; font-weight: 600;">🤖 Android:</h5>
                            <ol style="margin: 0; padding-left: 20px; color: rgba(255,255,255,0.9); font-size: 13px; line-height: 1.8;">
                                <li><?php esc_html_e('Open the link in Chrome', 'simple-appointment-booking'); ?></li>
                                <li><?php esc_html_e('Tap the menu (⋮)', 'simple-appointment-booking'); ?></li>
                                <li><?php esc_html_e('Select "Add to home screen"', 'simple-appointment-booking'); ?></li>
                            </ol>
                        </div>
                    </div>
                </div>
            </div>
            <?php endif; ?>
        </div>
        
        <script>
        jQuery(document).ready(function($) {
            // Copy URL Button
            $('.simpbook-copy-url').on('click', function() {
                var url = $(this).data('url');
                navigator.clipboard.writeText(url).then(function() {
                    alert('<?php echo esc_js(__('Link copied!', 'simple-appointment-booking')); ?>');
                });
            });
            
            // Push-Benachrichtigungen Buttons
            $('#simpbook_pwa_test_push_btn').on('click', function() {
                if (!confirm('<?php echo esc_js(__('Should a test notification be sent?', 'simple-appointment-booking')); ?>')) return;
                
                var $btn = $(this);
                $btn.prop('disabled', true).text('<?php echo esc_js(__('Sending...', 'simple-appointment-booking')); ?>');
                
                $.post(ajaxurl, {
                    action: 'simpbook_pwa_test_push',
                    nonce: '<?php echo esc_js(wp_create_nonce('simpbook_pwa_nonce')); ?>'
                })
                .done(function(response) {
                    console.log('Test Push Response:', response);
                    if (response.success) {
                        alert('✓ ' + response.data);
                    } else {
                        alert('✗ Fehler: ' + (response.data || 'Unbekannter Fehler'));
                    }
                })
                .fail(function(xhr, status, error) {
                    console.error('Test Push AJAX Error:', xhr, status, error);
                    alert('✗ AJAX-Fehler: ' + error);
                })
                .always(function() {
                    $btn.prop('disabled', false).html('<span class="dashicons dashicons-megaphone" style="vertical-align: middle; margin-right: 5px;"></span><?php echo esc_js(__('Send test push', 'simple-appointment-booking')); ?>');
                });
            });
            
            $('#simpbook_pwa_clear_subscriptions_btn').on('click', function() {
                if (!confirm('<?php echo esc_js(__('Are you sure you want to delete ALL subscriptions? Users will have to allow push notifications again!', 'simple-appointment-booking')); ?>')) return;
                
                var $btn = $(this);
                $btn.prop('disabled', true).text('<?php echo esc_js(__('Deleting...', 'simple-appointment-booking')); ?>');
                
                $.post(ajaxurl, {
                    action: 'simpbook_pwa_clear_subscriptions',
                    nonce: '<?php echo esc_js(wp_create_nonce('simpbook_pwa_nonce')); ?>'
                })
                .done(function(response) {
                    console.log('Clear Subscriptions Response:', response);
                    if (response.success) {
                        alert('✓ ' + response.data);
                    } else {
                        alert('✗ Fehler: ' + (response.data || 'Unbekannter Fehler'));
                    }
                })
                .fail(function(xhr, status, error) {
                    console.error('Clear Subscriptions AJAX Error:', xhr, status, error);
                    alert('✗ AJAX-Fehler: ' + error);
                })
                .always(function() {
                    $btn.prop('disabled', false).html('<span class="dashicons dashicons-trash" style="vertical-align: middle; margin-right: 5px;"></span><?php echo esc_js(__('Delete old subscriptions', 'simple-appointment-booking')); ?>');
                });
            });
            
            $('#simpbook_pwa_generate_keys_btn').on('click', function() {
                if (!confirm('<?php echo esc_js(__('Generate new VAPID keys? IMPORTANT: After that, all old subscriptions must be deleted!', 'simple-appointment-booking')); ?>')) return;
                
                var $btn = $(this);
                var $errorBox = $('#simpbook_vapid_error_box');
                var $errorMsg = $('#simpbook_vapid_error_msg');
                
                $btn.prop('disabled', true).html('<span class="dashicons dashicons-update spin" style="vertical-align: middle; margin-right: 5px;"></span><?php echo esc_js(__('Generiere...', 'simple-appointment-booking')); ?>');
                $errorBox.hide();
                
                $.post(ajaxurl, {
                    action: 'simpbook_pwa_generate_keys',
                    nonce: '<?php echo esc_js(wp_create_nonce('simpbook_pwa_nonce')); ?>'
                })
                .done(function(response) {
                    if (response.success) {
                        $('#simpbook_pwa_vapid_public_key').val(response.data.public);
                        $('#simpbook_pwa_vapid_private_key').val(response.data.private);
                        $errorBox.hide();
                        alert('<?php echo esc_js(__('VAPID keys generated successfully! Please save the settings and then delete all old subscriptions.', 'simple-appointment-booking')); ?>');
                        location.reload();
                    } else {
                        $errorMsg.text(response.data);
                        $errorBox.show();
                    }
                })
                .fail(function(xhr, status, error) {
                    $errorMsg.text('AJAX-Fehler: ' + error);
                    $errorBox.show();
                })
                .always(function() {
                    $btn.prop('disabled', false).html('<span class="dashicons dashicons-update" style="vertical-align: middle; margin-right: 5px;"></span><?php echo esc_js(__('Generate Keys', 'simple-appointment-booking')); ?>');
                });
            });
            
            // App-Kurzname Zeichenzähler
            var $shortNameInput = $('#simpbook_pwa_app_short_name');
            var $counter = $('#short-name-counter');
            
            function updateCounter() {
                var len = $shortNameInput.val().length;
                $counter.text('(' + len + '/12)');
                $counter.css('color', len > 12 ? '#dc3232' : '#666');
            }
            
            $shortNameInput.on('input', updateCounter);
            updateCounter(); // Initial
            
            // Icon Upload
            $('.simpbook-upload-icon').on('click', function(e) {
                e.preventDefault();
                var targetId = $(this).data('target');
                var $input = $('#' + targetId);
                
                var frame = wp.media({
                    title: '<?php echo esc_js(__('Select icon', 'simple-appointment-booking')); ?>',
                    button: { text: '<?php echo esc_js(__('Select', 'simple-appointment-booking')); ?>' },
                    multiple: false
                });
                
                frame.on('select', function() {
                    var attachment = frame.state().get('selection').first().toJSON();
                    $input.val(attachment.url);
                });
                
                frame.open();
            });
        });
        </script>
        <?php
    }
    
    /**
     * Save App Settings
     */
    public function save_app_settings($post_data) {
        // PWA aktiviert/deaktiviert
        $pwa_enabled = isset($post_data['simpbook_pwa_enabled']) ? '1' : '0';
        update_option('simpbook_pwa_enabled', $pwa_enabled);
        
        // App-Name (Guide-konform)
        if (isset($post_data['simpbook_pwa_app_name'])) {
            update_option('simpbook_pwa_app_name', sanitize_text_field($post_data['simpbook_pwa_app_name']));
        }
        
        // App-Kurzname (max 12 Zeichen, Guide-konform)
        if (isset($post_data['simpbook_pwa_app_short_name'])) {
            $short_name = sanitize_text_field($post_data['simpbook_pwa_app_short_name']);
            $short_name = mb_substr($short_name, 0, 12); // Max 12 Zeichen
            update_option('simpbook_pwa_app_short_name', $short_name);
        }
        
        if (isset($post_data['simpbook_pwa_theme_color'])) {
            update_option('simpbook_pwa_theme_color', sanitize_hex_color($post_data['simpbook_pwa_theme_color']));
        }
        
        if (isset($post_data['simpbook_pwa_icon_512'])) {
            $icon_512_url = esc_url_raw($post_data['simpbook_pwa_icon_512']);
            $old_icon_512 = get_option('simpbook_pwa_icon_512', '');
            
            update_option('simpbook_pwa_icon_512', $icon_512_url);
            
            // Automatisch 192x192 Version generieren wenn Icon geändert wurde
            if (!empty($icon_512_url) && $icon_512_url !== $old_icon_512) {
                $icon_192_url = $this->generate_scaled_icon($icon_512_url);
                
                if ($icon_192_url) {
                    update_option('simpbook_pwa_icon_192', $icon_192_url);
                } else {
                    // Bei Fehler: 192x192 Option löschen (Fallback auf Browser-Skalierung)
                    delete_option('simpbook_pwa_icon_192');
                }
            } elseif (empty($icon_512_url)) {
                // Wenn 512er Icon entfernt wurde, auch 192er löschen
                delete_option('simpbook_pwa_icon_192');
            }
        }
        
        // Push-Benachrichtigungen aktiviert/deaktiviert
        $push_enabled = isset($post_data['simpbook_pwa_push_enabled']) ? '1' : '0';
        update_option('simpbook_pwa_push_enabled', $push_enabled);
        
        // VAPID Keys - Nur speichern wenn im Formular gesetzt (manuell oder bereits vorhanden)
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $manual_public = isset($post_data['simpbook_pwa_vapid_public_key']) ? sanitize_text_field($post_data['simpbook_pwa_vapid_public_key']) : null;
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        $manual_private = isset($post_data['simpbook_pwa_vapid_private_key']) ? sanitize_text_field($post_data['simpbook_pwa_vapid_private_key']) : null;
        
        // Werte speichern (können leer sein wenn gelöscht, oder gefüllt wenn vorhanden/manuell)
        if ($manual_public !== null) {
            update_option('simpbook_pwa_vapid_public_key', $manual_public);
        }
        if ($manual_private !== null) {
            update_option('simpbook_pwa_vapid_private_key', $manual_private);
        }
        
        // ⚠️ Rewrite-Rules nach Änderungen flushen
        flush_rewrite_rules();
    }
    
    /**
     * Handle Settings Save (via admin_init)
     * 
     * Direkt-Handler für POST-Requests vom Einstellungen-Formular
     */
    public function handle_settings_save() {
        // Prüfe ob Submit-Button geklickt wurde
        if (!isset($_POST['simpbook_einstellungen_submit'])) {
            return;
        }
        
        // Prüfe Nonce
        if (!isset($_POST['_wpnonce'])) {
            return;
        }
        
        // Verify nonce
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        $nonce_check = wp_verify_nonce(wp_unslash($_POST['_wpnonce']), 'simpbook_einstellungen');
        if (!$nonce_check) {
            return;
        }
        
        // Prüfe Berechtigung
        if (!current_user_can('manage_options')) {
            return;
        }
        
        // Speichere PWA-Settings
        $this->save_app_settings(wp_unslash($_POST));
    }
    
    /**
     * Prüft ob PWA aktiviert ist
     * 
     * @return bool
     */
    public function is_pwa_enabled() {
        return get_option('simpbook_pwa_enabled', '1') === '1';
    }
    
    /**
     * Prüft ob im PWA-Modus
     * 
     * @return bool
     */
    public function is_pwa_mode() {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended
        return isset($_GET['pwa']) && $_GET['pwa'] === '1' && $this->is_pwa_enabled();
    }
    
    // ========================================
    // PUSH-BENACHRICHTIGUNGEN
    // ========================================
    
    /**
     * AJAX: Test Push-Benachrichtigung
     */
    public function ajax_test_push() {
        check_ajax_referer('simpbook_pwa_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Keine Berechtigung.');
        }

        // Prüfe ob Push aktiviert ist
        $push_enabled = get_option('simpbook_pwa_push_enabled', '0');
        if ($push_enabled !== '1') {
            wp_send_json_error('Push-Benachrichtigungen sind deaktiviert. Bitte aktiviere sie in den Einstellungen.');
        }

        // Prüfe VAPID Keys
        $public_key = get_option('simpbook_pwa_vapid_public_key');
        $private_key = get_option('simpbook_pwa_vapid_private_key');
        if (empty($public_key) || empty($private_key)) {
            wp_send_json_error('VAPID-Schlüssel fehlen. Bitte generiere sie in den Einstellungen.');
        }

        // Hole aktuelle Plugin-Sprache
        $language = simpbook_get_current_language();
        
        // Übersetze Titel und Body
        $title = simpbook_get_push_translation('push_test_title', $language);
        $body = simpbook_get_push_translation('push_test_body', $language);
        
        $this->send_push_notification(
            $title,
            $body,
            admin_url('admin.php?page=simpbook-dashboard&pwa=1')
        );

        wp_send_json_success(__('Test push sent. Check your device (may take 1-2 seconds).', 'simple-appointment-booking'));
    }
    
    /**
     * AJAX: Alle Push-Subscriptions löschen
     */
    public function ajax_clear_subscriptions() {
        check_ajax_referer('simpbook_pwa_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Keine Berechtigung.');
        }

        global $wpdb;
        $table_name = $wpdb->prefix . 'simpbook_pwa_subscriptions';
        
        // Prüfe ob Tabelle existiert
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
            $this->create_subscriptions_table();
            wp_send_json_success('Subscriptions-Tabelle wurde erstellt. Es gibt noch keine Subscriptions zum Löschen.');
        }
        
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $count = $wpdb->get_var("SELECT COUNT(*) FROM $table_name");
        
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $result = $wpdb->query("TRUNCATE TABLE $table_name");
        
        if ($result === false) {
            wp_send_json_error('Fehler beim Löschen der Subscriptions.');
        }
        
        wp_send_json_success($count . ' Subscriptions wurden gelöscht. Benutzer müssen die App neu öffnen und Push-Benachrichtigungen erneut erlauben.');
    }
    
    /**
     * AJAX: VAPID Schlüssel generieren
     */
    public function ajax_generate_vapid_keys() {
        check_ajax_referer('simpbook_pwa_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Unauthorized');
        }

        // Detaillierte Fehlerprüfung
        if (!extension_loaded('openssl')) {
            wp_send_json_error('OpenSSL Extension ist nicht geladen.');
        }
        
        if (!defined('OPENSSL_KEYTYPE_EC')) {
            wp_send_json_error('OpenSSL EC Key-Typ ist nicht definiert.');
        }
        
        // Prüfe ob prime256v1 Kurve verfügbar ist
        if (function_exists('openssl_get_curve_names')) {
            $curves = openssl_get_curve_names();
            if (!in_array('prime256v1', $curves)) {
                wp_send_json_error('EC-Kurve prime256v1 ist nicht verfügbar. Verfügbare Kurven: ' . implode(', ', array_slice($curves, 0, 5)));
            }
        }

        $keys = $this->generate_vapid_keys();
        
        if ($keys) {
            update_option('simpbook_pwa_vapid_public_key', $keys['public']);
            update_option('simpbook_pwa_vapid_private_key', $keys['private']);
            wp_send_json_success($keys);
        } else {
            // Hole OpenSSL Fehler
            $errors = [];
            while ($error = openssl_error_string()) {
                $errors[] = $error;
            }
            $error_msg = 'VAPID-Generierung fehlgeschlagen.';
            if (!empty($errors)) {
                $error_msg .= ' OpenSSL-Fehler: ' . implode(' | ', $errors);
            }
            wp_send_json_error($error_msg);
        }
    }

    /**
     * Generiert VAPID Schlüssel via OpenSSL
     * 
     * @return array|false Array mit 'public' und 'private' Keys oder false bei Fehler
     */
    public function generate_vapid_keys() {
        // Prüfe OpenSSL Extension
        if (!extension_loaded('openssl')) {
            error_log('VAPID Key Generation: OpenSSL extension not loaded');
            return false;
        }

        // Prüfe ob EC-Kurven verfügbar sind
        if (!defined('OPENSSL_KEYTYPE_EC')) {
            error_log('VAPID Key Generation: OpenSSL EC type not supported');
            return false;
        }

        // OpenSSL Config-Pfad für Windows finden
        $openssl_config = null;
        $possible_paths = [
            getenv('OPENSSL_CONF'),
            // XAMPP
            'C:/xampp/apache/conf/openssl.cnf',
            'C:/xampp/php/extras/openssl/openssl.cnf',
            // Local by Flywheel / WP Local
            'C:/Program Files/Local/resources/extraResources/lightning-services/php-8.2.10+1/bin/win64/extras/ssl/openssl.cnf',
            'C:/Program Files/Local/resources/extraResources/lightning-services/php-8.1.23+1/bin/win64/extras/ssl/openssl.cnf',
            'C:/Program Files/Local/resources/extraResources/lightning-services/php-8.0.30+1/bin/win64/extras/ssl/openssl.cnf',
            // WAMP
            'C:/wamp64/bin/apache/apache2.4.54.2/conf/openssl.cnf',
            // Laragon
            'C:/laragon/bin/apache/httpd-2.4.54-win64-VS16/conf/openssl.cnf',
            // Standard PHP
            dirname(PHP_BINARY) . '/extras/ssl/openssl.cnf',
            dirname(PHP_BINARY) . '/../extras/ssl/openssl.cnf',
        ];
        
        foreach ($possible_paths as $path) {
            if ($path && file_exists($path)) {
                $openssl_config = $path;
                break;
            }
        }

        // Basis-Konfiguration
        $config = [
            "private_key_type" => OPENSSL_KEYTYPE_EC,
            "curve_name" => "prime256v1"
        ];
        
        // Config-Pfad hinzufügen wenn gefunden
        if ($openssl_config) {
            $config['config'] = $openssl_config;
        }

        // Schlüssel generieren
        $res = @openssl_pkey_new($config);
        
        // Fallback: Ohne config versuchen
        if (!$res && $openssl_config) {
            unset($config['config']);
            $res = @openssl_pkey_new($config);
        }
        
        if (!$res) {
            $error = openssl_error_string();
            error_log('VAPID Key Generation: openssl_pkey_new failed - ' . ($error ? $error : 'unknown error'));
            return false;
        }

        // Private Key exportieren (mit config wenn verfügbar)
        $export_config = $openssl_config ? ['config' => $openssl_config] : [];
        $export_success = @openssl_pkey_export($res, $priv_key, null, $export_config);
        
        // Fallback ohne config
        if (!$export_success) {
            $export_success = @openssl_pkey_export($res, $priv_key);
        }
        
        if (!$export_success) {
            error_log('VAPID Key Generation: openssl_pkey_export failed');
            return false;
        }
        
        // Public Key Details holen
        $pub_key_details = @openssl_pkey_get_details($res);
        
        if (!$pub_key_details || !isset($pub_key_details['ec'])) {
            error_log('VAPID Key Generation: Failed to get key details or EC key missing');
            return false;
        }
        
        if (!isset($pub_key_details['ec']['x']) || !isset($pub_key_details['ec']['y'])) {
            error_log('VAPID Key Generation: EC coordinates (x,y) missing');
            return false;
        }

        // VAPID benötigt den Public Key im Uncompressed Point Format (65 bytes)
        // 1 Byte (0x04) + 32 Bytes X + 32 Bytes Y = 65 Bytes
        $x = $pub_key_details['ec']['x'];
        $y = $pub_key_details['ec']['y'];
        
        // Stelle sicher, dass x und y genau 32 bytes sind
        $x = str_pad($x, 32, "\0", STR_PAD_LEFT);
        $y = str_pad($y, 32, "\0", STR_PAD_LEFT);
        
        // Uncompressed Point Format: 0x04 || X || Y
        $public_key_bin = "\x04" . $x . $y;
        
        // Base64 URL Safe encoding (ohne padding)
        $public_key_base64 = rtrim(strtr(base64_encode($public_key_bin), '+/', '-_'), '=');
        
        // Private Key (d parameter) - muss auch 32 bytes sein
        if (!isset($pub_key_details['ec']['d'])) {
            error_log('VAPID Key Generation: Private key parameter (d) missing');
            return false;
        }
        
        $private_key_bin = str_pad($pub_key_details['ec']['d'], 32, "\0", STR_PAD_LEFT);
        $private_key_base64 = rtrim(strtr(base64_encode($private_key_bin), '+/', '-_'), '=');

        error_log('VAPID Key Generation: Successfully generated keys');
        
        return [
            'public' => $public_key_base64,
            'private' => $private_key_base64
        ];
    }

    /**
     * AJAX: Push-Subscription speichern
     */
    public function ajax_subscribe_push() {
        check_ajax_referer('simpbook_pwa_nonce', 'nonce');
        
        if (!current_user_can('manage_options')) {
            wp_send_json_error('Keine Berechtigung.');
        }

        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
        $subscription = isset($_POST['subscription']) ? wp_unslash($_POST['subscription']) : '';
        if (empty($subscription)) {
            wp_send_json_error('Keine Subscription-Daten erhalten.');
        }

        global $wpdb;
        $table_name = $wpdb->prefix . 'simpbook_pwa_subscriptions';
        
        // Prüfen ob Tabelle existiert
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
            $this->create_subscriptions_table();
        }

        $user_id = get_current_user_id();
        
        // Wir speichern die Subscription. 
        // Ein User kann mehrere Subscriptions haben (verschiedene Geräte).
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- JSON data
        $result = $wpdb->insert(
            $table_name,
            [
                'user_id' => $user_id,
                'subscription_data' => $subscription,
                'created_at' => current_time('mysql')
            ]
        );

        if ($result === false) {
            wp_send_json_error('Fehler beim Speichern der Subscription: ' . $wpdb->last_error);
        }

        wp_send_json_success('Push-Benachrichtigungen aktiviert!');
    }

    /**
     * AJAX: Push-Subscription entfernen
     */
    public function ajax_unsubscribe_push() {
        check_ajax_referer('simpbook_pwa_nonce', 'nonce');
        
        $endpoint = isset($_POST['endpoint']) ? sanitize_text_field(wp_unslash($_POST['endpoint'])) : '';
        if (empty($endpoint)) {
            wp_send_json_error('No endpoint');
        }

        global $wpdb;
        $table_name = $wpdb->prefix . 'simpbook_pwa_subscriptions';
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->delete($table_name, ['subscription_data' => $endpoint]);

        wp_send_json_success('Unsubscribed');
    }
    
    /**
     * Erstellt die Push-Subscriptions Tabelle
     * 
     * Public damit bei Plugin-Aktivierung aufrufbar
     */
    public function create_subscriptions_table() {
        global $wpdb;
        $table_name = $wpdb->prefix . 'simpbook_pwa_subscriptions';
        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE $table_name (
            id bigint(20) NOT NULL AUTO_INCREMENT,
            user_id bigint(20) NOT NULL,
            subscription_data text NOT NULL,
            created_at datetime NOT NULL,
            PRIMARY KEY  (id),
            KEY user_id (user_id)
        ) $charset_collate;";

        require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
        dbDelta($sql);
    }
    
    /**
     * Sendet Push-Benachrichtigung an alle Subscriptions
     * 
     * @param string $title Notification Titel
     * @param string $body Notification Text
     * @param string $url Ziel-URL
     */
    public function send_push_notification($title, $body, $url = '') {
        $push_enabled = get_option('simpbook_pwa_push_enabled', '0');
        if ($push_enabled !== '1') {
            return;
        }

        $public_key = get_option('simpbook_pwa_vapid_public_key');
        $private_key = get_option('simpbook_pwa_vapid_private_key');

        if (empty($public_key) || empty($private_key)) {
            return;
        }

        global $wpdb;
        $table_name = $wpdb->prefix . 'simpbook_pwa_subscriptions';
        
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        if ($wpdb->get_var("SHOW TABLES LIKE '$table_name'") !== $table_name) {
            return;
        }

        $subscriptions = $wpdb->get_results("SELECT * FROM $table_name", ARRAY_A);
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter

        if (empty($subscriptions)) {
            return;
        }

        require_once SIMPBOOK_PLUGIN_DIR . 'includes/class-simpbook-webpush-sender.php';
        $sender = new Simpbook_WebPush_Sender($public_key, $private_key);

        $payload = [
            'title' => $title,
            'body' => $body,
            'url' => $url ?: admin_url('admin.php?page=simpbook-dashboard&pwa=1')
        ];

        $expired_ids = [];

        foreach ($subscriptions as $sub) {
            $result = $sender->send($sub['subscription_data'], $payload);
            
            if (!$result['success'] && $result['expired']) {
                $expired_ids[] = $sub['id'];
            }
        }

        // Expired subscriptions löschen
        if (!empty($expired_ids)) {
            $ids_string = implode(',', array_map('intval', $expired_ids));
            // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- Safe usage with intval and placeholders not possible in IN
            $wpdb->query("DELETE FROM $table_name WHERE id IN ($ids_string)");
        }
    }
}

// Initialisieren
Simpbook_PWA_Controller::get_instance();
