<?php
/**
 * PWA Authentication Class - PocketBooking Pro
 * 
 * Handhabt die Authentifizierung für die PWA:
 * - Login via wp_signon()
 * - Session-Validierung
 * - Token-Management
 * - Berechtigungsprüfung
 *
 * @package SimpleBookingCalendar
 * @since 1.2.0
 */

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

class Simpbook_PWA_Auth {
    
    /**
     * Singleton Instance
     */
    private static $instance = null;
    
    /**
     * Token Cookie Name
     */
    const TOKEN_COOKIE = 'simpbook_pwa_token';
    
    /**
     * Token Expiry in seconds (30 Tage)
     */
    const TOKEN_EXPIRY = 2592000;
    
    /**
     * 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() {
        // Custom Login Handler
        add_action('init', array($this, 'handle_pwa_login'));
        
        // PWA Login Page Template
        add_action('login_init', array($this, 'maybe_show_pwa_login'));
        
        // AJAX Handlers
        add_action('wp_ajax_simpbook_pwa_login', array($this, 'ajax_login'));
        add_action('wp_ajax_nopriv_simpbook_pwa_login', array($this, 'ajax_login'));
        add_action('wp_ajax_simpbook_check_pwa_session', array($this, 'ajax_check_session'));
        add_action('wp_ajax_simpbook_pwa_logout', array($this, 'ajax_logout'));
        
        // Redirect nach Standard-Login wenn PWA-Mode
        add_filter('login_redirect', array($this, 'pwa_login_redirect'), 10, 3);
    }
    
    /**
     * Handle PWA Login Form Submission
     */
    public function handle_pwa_login() {
        if (!isset($_POST['simpbook_pwa_login_nonce'])) {
            return;
        }
        
        if (!wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['simpbook_pwa_login_nonce'])), 'simpbook_pwa_login')) {
            wp_die(esc_html__('Security check failed.', 'simple-appointment-booking'));
        }
        
        $username = sanitize_user(wp_unslash($_POST['username'] ?? ''));
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Password cannot be sanitized like text
        $password = wp_unslash($_POST['password'] ?? '');
        $remember = isset($_POST['remember']);
        
        $result = $this->authenticate($username, $password, $remember);
        
        if (is_wp_error($result)) {
            // Fehler speichern für Template
            set_transient('simpbook_pwa_login_error_' . session_id(), $result->get_error_message(), 60);
            wp_safe_redirect(add_query_arg('pwa_login', '1', wp_login_url()));
            exit;
        }
        
        // Erfolgreich - zum Dashboard
        $redirect = admin_url('admin.php?page=simpbook-dashboard&pwa=1');
        wp_safe_redirect($redirect);
        exit;
    }
    
    /**
     * Authenticate User
     * 
     * @param string $username
     * @param string $password
     * @param bool $remember
     * @return WP_User|WP_Error
     */
    public function authenticate($username, $password, $remember = false) {
        // Leere Felder prüfen
        if (empty($username) || empty($password)) {
            return new WP_Error(
                'empty_fields',
                __('Bitte geben Sie Benutzername und Passwort ein.', 'simple-appointment-booking')
            );
        }
        
        // WordPress Authentication
        $credentials = array(
            'user_login'    => $username,
            'user_password' => $password,
            'remember'      => $remember
        );
        
        $user = wp_signon($credentials, is_ssl());
        
        if (is_wp_error($user)) {
            // Generische Fehlermeldung aus Sicherheitsgründen
            return new WP_Error(
                'authentication_failed',
                __('Invalid username or password.', 'simple-appointment-booking')
            );
        }
        
        // PWA-Berechtigung prüfen
        if (!$this->user_can_access_pwa($user)) {
            wp_logout();
            return new WP_Error(
                'no_pwa_access',
                __('You do not have permission for the booking app.', 'simple-appointment-booking')
            );
        }
        
        // Token generieren und speichern
        $this->create_auth_token($user->ID);
        
        // Login-Zeitpunkt speichern
        update_user_meta($user->ID, 'simpbook_last_pwa_login', current_time('mysql'));
        
        return $user;
    }
    
    /**
     * Check if User can Access PWA
     * 
     * @param WP_User $user
     * @return bool
     */
    public function user_can_access_pwa($user) {
        // Administratoren haben immer Zugang
        if (in_array('administrator', $user->roles)) {
            return true;
        }
        
        // Booking Manager Role
        if (in_array('booking_manager', $user->roles)) {
            return true;
        }
        
        // Custom Capability prüfen
        if (user_can($user, 'manage_booking_app')) {
            return true;
        }
        
        // Prüfen ob User als Mitarbeiter mit App-Zugang existiert
        return $this->mitarbeiter_has_app_access($user->ID);
    }
    
    /**
     * Check if Mitarbeiter has App Access via Database
     * 
     * @param int $wp_user_id
     * @return bool
     */
    private function mitarbeiter_has_app_access($wp_user_id) {
        global $wpdb;
        
        $table = $wpdb->prefix . 'mitarbeiter';
        
        // 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'") !== $table) {
            return false;
        }
        
        // Prüfen ob Spalte existiert
        // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $column_exists = $wpdb->get_results("SHOW COLUMNS FROM $table LIKE 'app_zugang_aktiv'");
        if (empty($column_exists)) {
            return false;
        }
        
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $result = $wpdb->get_var($wpdb->prepare(
            "SELECT app_zugang_aktiv FROM $table WHERE wp_user_id = %d AND status = 1",
            $wp_user_id
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        
        return (bool) $result;
    }
    
    /**
     * Create Authentication Token
     * 
     * @param int $user_id
     * @return string
     */
    private function create_auth_token($user_id) {
        $token = wp_generate_password(64, false);
        $token_hash = wp_hash($token);
        
        // Token in User Meta speichern
        update_user_meta($user_id, 'simpbook_pwa_token', $token_hash);
        update_user_meta($user_id, 'simpbook_pwa_token_expiry', time() + self::TOKEN_EXPIRY);
        
        // Token als Cookie setzen
        $secure = is_ssl();
        $expiry = time() + self::TOKEN_EXPIRY;
        
        setcookie(
            self::TOKEN_COOKIE,
            $token,
            $expiry,
            COOKIEPATH,
            COOKIE_DOMAIN,
            $secure,
            true // httponly
        );
        
        return $token;
    }
    
    /**
     * Validate Authentication Token
     * 
     * @return bool
     */
    public function validate_token() {
        if (!isset($_COOKIE[self::TOKEN_COOKIE])) {
            return false;
        }
        
        $token = sanitize_text_field(wp_unslash($_COOKIE[self::TOKEN_COOKIE]));
        $user = wp_get_current_user();
        
        if (!$user->ID) {
            return false;
        }
        
        $stored_hash = get_user_meta($user->ID, 'simpbook_pwa_token', true);
        $expiry = get_user_meta($user->ID, 'simpbook_pwa_token_expiry', true);
        
        // Token abgelaufen?
        if (empty($expiry) || time() > $expiry) {
            $this->invalidate_token($user->ID);
            return false;
        }
        
        // Token vergleichen
        return wp_hash($token) === $stored_hash;
    }
    
    /**
     * Invalidate Token
     * 
     * @param int $user_id
     */
    public function invalidate_token($user_id) {
        delete_user_meta($user_id, 'simpbook_pwa_token');
        delete_user_meta($user_id, 'simpbook_pwa_token_expiry');
        
        // Cookie löschen
        setcookie(self::TOKEN_COOKIE, '', time() - 3600, COOKIEPATH, COOKIE_DOMAIN);
    }
    
    /**
     * Maybe Show PWA Login Template
     */
    public function maybe_show_pwa_login() {
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Display logic only
        if (!isset($_GET['pwa_login']) && !$this->is_pwa_request()) {
            return;
        }
        
        // Custom Login Template laden
        $template = SIMPBOOK_PLUGIN_DIR . 'templates/pwa-login.php';
        
        if (file_exists($template)) {
            // Login Error Message
            $error = '';
            $session_id = session_id() ?: 'no_session';
            $transient_key = 'simpbook_pwa_login_error_' . $session_id;
            
            if ($stored_error = get_transient($transient_key)) {
                $error = $stored_error;
                delete_transient($transient_key);
            }
            
            include $template;
            exit;
        }
    }
    
    /**
     * Check if Request is from PWA
     * 
     * @return bool
     */
    private function is_pwa_request() {
        // GET Parameter
        // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Context check only
        if (isset($_GET['pwa']) || isset($_GET['pwa_login'])) {
            return true;
        }
        
        // Standalone Display Mode Header (nicht alle Browser senden das)
        if (isset($_SERVER['HTTP_SEC_FETCH_DEST']) && $_SERVER['HTTP_SEC_FETCH_DEST'] === 'document') {
            // Könnte PWA sein - zusätzlich Cookie prüfen
            if (isset($_COOKIE[self::TOKEN_COOKIE])) {
                return true;
            }
        }
        
        // Referer prüfen
        if (isset($_SERVER['HTTP_REFERER'])) {
            $referer = sanitize_text_field(wp_unslash($_SERVER['HTTP_REFERER']));
            if (strpos($referer, 'pwa=1') !== false || strpos($referer, 'pwa_login=1') !== false) {
                return true;
            }
        }
        
        return false;
    }
    
    /**
     * PWA Login Redirect
     * 
     * @param string $redirect_to
     * @param string $requested_redirect_to
     * @param WP_User|WP_Error $user
     * @return string
     */
    public function pwa_login_redirect($redirect_to, $requested_redirect_to, $user) {
        if (is_wp_error($user)) {
            return $redirect_to;
        }
        
        // Nur bei PWA-Request
        if (!$this->is_pwa_request()) {
            return $redirect_to;
        }
        
        // PWA-Berechtigung prüfen
        if (!$this->user_can_access_pwa($user)) {
            return $redirect_to;
        }
        
        // Token erstellen
        $this->create_auth_token($user->ID);
        
        // Zum PWA Dashboard
        return admin_url('admin.php?page=simpbook-dashboard&pwa=1');
    }
    
    /**
     * AJAX Login Handler
     */
    public function ajax_login() {
        // Nonce prüfen
        if (!check_ajax_referer('simpbook_pwa_login', 'nonce', false)) {
            wp_send_json_error(array(
                'message' => __('Security check failed.', 'simple-appointment-booking')
            ));
        }
        
        $username = sanitize_user(wp_unslash($_POST['username'] ?? ''));
        // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Password cannot be sanitized like text
        $password = wp_unslash($_POST['password'] ?? '');
        $remember = isset($_POST['remember']);
        
        $result = $this->authenticate($username, $password, $remember);
        
        if (is_wp_error($result)) {
            wp_send_json_error(array(
                'message' => $result->get_error_message()
            ));
        }
        
        wp_send_json_success(array(
            'redirect' => admin_url('admin.php?page=simpbook-dashboard&pwa=1'),
            'user' => array(
                'id' => $result->ID,
                'name' => $result->display_name
            )
        ));
    }
    
    /**
     * AJAX Check Session Handler
     */
    public function ajax_check_session() {
        if (!check_ajax_referer('simpbook_pwa_nonce', 'nonce', false)) {
            wp_send_json_error(array('message' => 'Invalid nonce'));
        }
        
        if (!is_user_logged_in()) {
            wp_send_json_error(array(
                'message' => __('Session abgelaufen', 'simple-appointment-booking'),
                'redirect' => wp_login_url() . '?pwa_login=1'
            ));
        }
        
        $user = wp_get_current_user();
        
        if (!$this->user_can_access_pwa($user)) {
            wp_send_json_error(array(
                'message' => __('Keine Berechtigung', 'simple-appointment-booking')
            ));
        }
        
        wp_send_json_success(array(
            'logged_in' => true,
            'user_id' => $user->ID,
            'display_name' => $user->display_name
        ));
    }
    
    /**
     * AJAX Logout Handler
     */
    public function ajax_logout() {
        if (!check_ajax_referer('simpbook_pwa_nonce', 'nonce', false)) {
            wp_send_json_error(array('message' => 'Invalid nonce'));
        }
        
        $user_id = get_current_user_id();
        
        if ($user_id) {
            $this->invalidate_token($user_id);
        }
        
        wp_logout();
        
        wp_send_json_success(array(
            'redirect' => wp_login_url() . '?pwa_login=1'
        ));
    }
    
    /**
     * Get Current Mitarbeiter for PWA User
     * 
     * @return object|null
     */
    public function get_current_mitarbeiter() {
        if (!is_user_logged_in()) {
            return null;
        }
        
        global $wpdb;
        $user_id = get_current_user_id();
        $table = $wpdb->prefix . 'mitarbeiter';
        
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        return $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $table WHERE wp_user_id = %d AND status = 1",
            $user_id
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
    }
    
    /**
     * Create WordPress User for Mitarbeiter
     * 
     * @param int $mitarbeiter_id
     * @param string $email
     * @param string $password Optional - wird generiert wenn leer
     * @return int|WP_Error User ID oder Fehler
     */
    public function create_user_for_mitarbeiter($mitarbeiter_id, $email, $password = '') {
        global $wpdb;
        
        $table = $wpdb->prefix . 'mitarbeiter';
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $mitarbeiter = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM $table WHERE id = %d",
            $mitarbeiter_id
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        
        if (!$mitarbeiter) {
            return new WP_Error('not_found', __('Mitarbeiter nicht gefunden.', 'simple-appointment-booking'));
        }
        
        // Prüfen ob User schon existiert
        if (!empty($mitarbeiter->wp_user_id)) {
            $existing_user = get_user_by('ID', $mitarbeiter->wp_user_id);
            if ($existing_user) {
                return $existing_user->ID;
            }
        }
        
        // Prüfen ob Email schon verwendet wird
        if (email_exists($email)) {
            return new WP_Error('email_exists', __('Diese E-Mail-Adresse wird bereits verwendet.', 'simple-appointment-booking'));
        }
        
        // Username generieren
        $username = sanitize_user(strtolower($mitarbeiter->name), true);
        $username = str_replace(' ', '_', $username);
        
        // Eindeutigen Username sicherstellen
        $base_username = $username;
        $counter = 1;
        while (username_exists($username)) {
            $username = $base_username . '_' . $counter;
            $counter++;
        }
        
        // Passwort generieren wenn nicht angegeben
        if (empty($password)) {
            $password = wp_generate_password(12, true, true);
        }
        
        // User erstellen
        $user_id = wp_create_user($username, $password, $email);
        
        if (is_wp_error($user_id)) {
            return $user_id;
        }
        
        // Role zuweisen
        $user = new WP_User($user_id);
        $user->set_role('booking_manager');
        
        // Display Name setzen
        wp_update_user(array(
            'ID' => $user_id,
            'display_name' => $mitarbeiter->name
        ));
        
        // Mitarbeiter mit User verknüpfen
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $wpdb->update(
            $table,
            array('wp_user_id' => $user_id),
            array('id' => $mitarbeiter_id),
            array('%d'),
            array('%d')
        );
        
        return $user_id;
    }
    
    /**
     * Send App Access Email to Mitarbeiter
     * 
     * @param int $mitarbeiter_id
     * @param string $password Optional - für neue User
     * @return bool
     */
    public function send_app_access_email($mitarbeiter_id, $password = '') {
        global $wpdb;
        
        $table = $wpdb->prefix . 'mitarbeiter';
        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        $mitarbeiter = $wpdb->get_row($wpdb->prepare(
            "SELECT m.*, u.user_email, u.user_login 
             FROM $table m 
             LEFT JOIN {$wpdb->users} u ON m.wp_user_id = u.ID 
             WHERE m.id = %d",
            $mitarbeiter_id
        ));
        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter
        
        if (!$mitarbeiter || empty($mitarbeiter->user_email)) {
            return false;
        }
        
        // App-URL generieren
        $app_url = admin_url('admin.php?page=simpbook-dashboard&pwa=1');
        $login_url = wp_login_url() . '?pwa_login=1';
        
        // E-Mail Inhalt
        $subject = sprintf(
            /* translators: %s: Blog name */
            __('[%s] Your Access to the Booking App', 'simple-appointment-booking'),
            get_bloginfo('name')
        );
        
        $message = sprintf(
            /* translators: %s: Employee name */
            __("Hallo %s,\n\nSie haben Zugang zur Buchungs-App erhalten.\n\n", 'simple-appointment-booking'),
            $mitarbeiter->name
        );
        
        if (!empty($password)) {
            $message .= sprintf(
                /* translators: 1: Username, 2: Password */
                __("Ihre Zugangsdaten:\nBenutzername: %1\$s\nPasswort: %2\$s\n\n", 'simple-appointment-booking'),
                $mitarbeiter->user_login,
                $password
            );
        }
        
        $message .= sprintf(
            /* translators: 1: Login URL, 2: Blog name */
            __("App Login: %1\$s\n\nPlease change your password after your first login.\n\nHow to install the app on your smartphone:\n1. Open the link in your mobile browser\n2. On iOS: Tap 'Share' then 'Add to Home Screen'\n3. On Android: Tap the menu (⋮) and 'Add to Home Screen'\n\nBest regards,\nYour %2\$s Team", 'simple-appointment-booking'),
            $login_url,
            get_bloginfo('name')
        );
        
        // E-Mail senden
        $headers = array('Content-Type: text/plain; charset=UTF-8');
        
        return wp_mail($mitarbeiter->user_email, $subject, $message, $headers);
    }
}

// Initialisieren
Simpbook_PWA_Auth::get_instance();
