<?php
/**
 * FajaedeSEO Pro License Handler (Updated)
 * Single-use license model with strict validation and atomic redemption
 */

defined('ABSPATH') or exit;

class FajaedeSEO_Pro_License {
    
    const TABLE_NAME = 'fajaedeseo_licenses';
    const STATUS_ACTIVE = 'active';
    const STATUS_REDEEMED = 'redeemed';
    const STATUS_EXPIRED = 'expired';
    const STATUS_REVOKED = 'revoked';
    
    // Plan levels
    const PLAN_FREE = 'free';
    const PLAN_PRO = 'pro';
    const PLAN_PREMIUM = 'premium';
    const PLAN_AGENCY = 'agency';
    
    // 1. Definieer de master server URL voor je live omgeving
    const MASTER_SERVER_URL = 'https://www.fajaede.nl';

    /**
     * Create database table on plugin activation
     */
    public static function create_table() {
        global $wpdb;
        $table = $wpdb->prefix . self::TABLE_NAME;
        $charset_collate = $wpdb->get_charset_collate();
        
        $sql = "CREATE TABLE $table (
          id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
          code_hash varchar(255) NOT NULL,
          status varchar(20) NOT NULL DEFAULT 'active',
          plan_level varchar(20) NOT NULL DEFAULT 'pro',
          expires_at datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
          redeemed_at datetime DEFAULT NULL,
          user_id bigint(20) unsigned DEFAULT NULL,
          payment_id varchar(100) DEFAULT NULL,
          invoice_number varchar(100) DEFAULT NULL,
          amount decimal(10,2) DEFAULT NULL,
          currency varchar(3) DEFAULT 'EUR',
          site_url text DEFAULT NULL,
          customer_name varchar(255) DEFAULT NULL,
          country_code varchar(2) DEFAULT NULL,
          vat_rate decimal(4,2) DEFAULT NULL,
          customer_type varchar(20) DEFAULT 'particulier',
          vat_number varchar(50) DEFAULT NULL,
          created_at datetime DEFAULT CURRENT_TIMESTAMP,
          updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
          PRIMARY KEY  (id),
          UNIQUE KEY code_hash (code_hash),
          KEY idx_status_expires (status, expires_at),
          KEY status_idx (status),
          KEY expires_idx (expires_at),
          KEY redeemed_idx (redeemed_at)
        ) $charset_collate;";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql);

        // Geforceerde check: Voeg site_url toe als dbDelta het niet deed (gebeurt soms op XAMPP/MySQL)
        $site_url_col = $wpdb->get_row($wpdb->prepare("SHOW COLUMNS FROM `" . esc_sql($table) . "` LIKE %s", 'site_url')); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
        if ($site_url_col === null) {
            $wpdb->query("ALTER TABLE `{$table}` ADD COLUMN site_url TEXT DEFAULT NULL AFTER currency"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        } elseif (stripos($site_url_col->Type, 'varchar') !== false) {
            $wpdb->query("ALTER TABLE `{$table}` MODIFY COLUMN site_url TEXT DEFAULT NULL"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        }

        // Geforceerde check: Voeg plan_level toe als dbDelta het niet deed
        if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM `" . esc_sql($table) . "` LIKE %s", 'plan_level')) === null) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->query("ALTER TABLE `{$table}` ADD COLUMN plan_level varchar(20) NOT NULL DEFAULT 'pro' AFTER status"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        }

        // Geforceerde check: Voeg BTW kolommen toe als dbDelta het niet deed
        if ($wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM `" . esc_sql($table) . "` LIKE %s", 'country_code')) === null) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
            $wpdb->query("ALTER TABLE `{$table}` ADD COLUMN country_code varchar(2) DEFAULT NULL"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $wpdb->query("ALTER TABLE `{$table}` ADD COLUMN vat_rate decimal(4,2) DEFAULT NULL"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $wpdb->query("ALTER TABLE `{$table}` ADD COLUMN customer_type varchar(20) DEFAULT 'particulier'"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
            $wpdb->query("ALTER TABLE `{$table}` ADD COLUMN vat_number varchar(50) DEFAULT NULL"); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        }
    }

    /**
     * Ensure the license table exists and the schema is up to date.
     */
    public static function ensure_table_schema(): void {
        global $wpdb;
        $table = $wpdb->prefix . self::TABLE_NAME;

        $cache_key = 'fajaedeseo_table_schema_' . md5($table);
        $schema_status = wp_cache_get($cache_key, 'fajaedeseo');

        if (false === $schema_status) {
            $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table)) === $table; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $has_fajaedeseo_site_url = false;
            $has_plan_level = false;
            $has_country_code = false;

            if ($table_exists) {
                $has_fajaedeseo_site_url = $wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM `" . esc_sql($table) . "` LIKE %s", 'site_url')) !== null; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
                $has_plan_level = $wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM `" . esc_sql($table) . "` LIKE %s", 'plan_level')) !== null; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
                $has_country_code = $wpdb->get_var($wpdb->prepare("SHOW COLUMNS FROM `" . esc_sql($table) . "` LIKE %s", 'country_code')) !== null; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
            }

            $schema_status = ['table_exists' => $table_exists, 'has_site_url' => $has_fajaedeseo_site_url, 'has_plan_level' => $has_plan_level, 'has_country_code' => $has_country_code];
            wp_cache_set($cache_key, $schema_status, 'fajaedeseo', 12 * HOUR_IN_SECONDS);
        }

        if (!$schema_status['table_exists'] || !$schema_status['has_site_url'] || !$schema_status['has_plan_level'] || !$schema_status['has_country_code']) {
            self::create_table();
            wp_cache_delete($cache_key, 'fajaedeseo');
        }
    }
    
    /**
     * Check if Pro license is currently active
     */
    public static function is_pro() {
        $license = self::get_current_license();
        return !empty($license) && $license['status'] === self::STATUS_REDEEMED && !self::is_expired($license);
    }
    
    /**
     * Get the current plan level (free, pro, or agency)
     */
    public static function get_plan_level() {
        $license = self::get_current_license();
        if (empty($license) || $license['status'] !== self::STATUS_REDEEMED || self::is_expired($license)) {
            return self::PLAN_FREE;
        }
        return strtolower($license['plan_level'] ?? self::PLAN_PRO);
    }
    
    /**
     * Get audit page limits based on plan level
     */
    public static function get_plan_limits() {
        $plan = self::get_plan_level();
        $limits = [
            self::PLAN_FREE   => 10,
            self::PLAN_PRO    => 500,
            self::PLAN_PREMIUM => 2500,
            self::PLAN_AGENCY => 999999 // Unlimited
        ];
        return $limits[$plan] ?? 10;
    }

    /**
     * Check if a specific plan feature is available
     */
    public static function has_feature(string $feature) {
        $plan = self::get_plan_level();
        $features = [
            self::PLAN_FREE   => ['privacy_policy'],
            self::PLAN_PRO    => ['privacy_policy', 'cookies', 'disclaimer', 'terms', 'gdpr', 'openai'],
            self::PLAN_PREMIUM => ['privacy_policy', 'cookies', 'disclaimer', 'terms', 'gdpr', 'openai', 'advanced_serp', 'bulk_actions', 'advanced_links'],
            self::PLAN_AGENCY => ['privacy_policy', 'cookies', 'disclaimer', 'terms', 'gdpr', 'accounting_export', 'openai', 'advanced_serp', 'bulk_actions', 'multi_site', 'white_label_pdf', 'advanced_links']
        ];
        return in_array($feature, $features[$plan] ?? [], true);
    }
    
    /**
     * Get current active license for this site
     */
    public static function get_current_license() {
        $status = get_option('fajaedeseo_pro_license_status');
        if ($status !== 'valid') {
            return null;
        }
        
        return [
            'status'      => self::STATUS_REDEEMED,
            'plan_level'  => strtolower(get_option('fajaedeseo_pro_license_tier', self::PLAN_PRO)),
            'expires_at'  => get_option('fajaedeseo_pro_license_expires'),
            'redeemed_at' => get_option('fajaedeseo_pro_license_redeemed_at'),
        ];
    }
    
    /**
     * Redeem a license code (atomic single-use operation)
     * 
     * Checks in one transaction:
     * - Code exists and code_hash matches
     * - Status is 'active'
     * - redeemed_at is NULL (never redeemed)
     * - expires_at > NOW()
     * 
     * If all pass: sets redeemed_at, status='redeemed', and returns success
     * Second attempt with same code fails because redeemed_at is no longer NULL
     */
    public static function redeem_license(string $license_code): array {
        $site_url = home_url();
        
        // Stuur request naar de Master Server
        $response = wp_remote_post( self::MASTER_SERVER_URL . '/wp-json/fajaedeseo/v1/verify-license', [
            'body' => wp_json_encode([
                'license_code' => sanitize_text_field($license_code),
                'site_url' => $site_url
            ]),
            'headers' => [
                'Content-Type' => 'application/json',
            ],
            'timeout' => 15,
            'sslverify' => true // Zet op true voor veilige live productie
        ]);

        if (is_wp_error($response)) {
            return [
                'success' => false,
                'message' => __('Kan niet verbinden met de licentieserver: ', 'fajaedeseo-ai') . $response->get_error_message(),
                'code' => 'CONNECTION_ERROR'
            ];
        }

        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);

        if (isset($data['success']) && $data['success'] === true) {
            wp_cache_delete( 'fajaedeseo_pro_license_status', 'options' );
            wp_cache_delete( 'fajaedeseo_pro_license_expires', 'options' );
            
            // Sla de master data lokaal op de client site op
            update_option('fajaedeseo_pro_license_status', 'valid');
            update_option('fajaedeseo_pro_license_redeemed_at', $data['redeemed_at'] ?? current_time('mysql', true));
            update_option('fajaedeseo_pro_license_expires', $data['expires_at']);
            update_option('fajaedeseo_pro_license_tier', $data['plan_level']);
            delete_option('fajaedeseo_license_debug_msg');

            return [
                'success' => true,
                'message' => $data['message'] ?? __('Licentie succesvol geactiveerd!', 'fajaedeseo-ai'),
                'expires_at' => $data['expires_at']
            ];
        }

        return [
            'success' => false,
            'message' => $data['message'] ?? __('Ongeldige of verlopen licentie.', 'fajaedeseo-ai'),
            'code' => $data['code'] ?? 'UNKNOWN_ERROR'
        ];
    }

    /**
     * Master Server Logic: Verifieert de licentie in de database
     */
    public static function master_server_redeem_license(string $license_code, string $site_url): array {
        global $wpdb;
        $license_code = sanitize_text_field((string)$license_code);
        $code_hash = self::hash_code($license_code);
        $table = $wpdb->prefix . self::TABLE_NAME;
        
        // Start transaction
        $wpdb->query('START TRANSACTION'); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        
        try {
            // Lock and fetch license (all checks in one query)
            $license = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM `" . esc_sql($table) . "` WHERE code_hash = %s AND status IN (%s, %s) AND expires_at > NOW() FOR UPDATE", $code_hash, self::STATUS_ACTIVE, self::STATUS_REDEEMED ), ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter
            
            if (!$license) {
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Transaction management.
                $wpdb->query('ROLLBACK');
                return [
                    'success' => false,
                    'message' => __('Invalid or expired license code.', 'fajaedeseo-ai'),
                    'code' => 'LICENSE_INVALID'
                ];
            }
            
            // Check multi-site restriction for non-agency plans
            if ($license['status'] === self::STATUS_REDEEMED) {
                if ($license['plan_level'] !== self::PLAN_AGENCY && $license['site_url'] !== $site_url) {
                    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Transaction management.
                    $wpdb->query('ROLLBACK');
                    return [
                        'success' => false,
                        'message' => __('This license is already in use on another website. Upgrade to Agency for unlimited sites.', 'fajaedeseo-ai'),
                        'code' => 'LICENSE_IN_USE'
                    ];
                }
            }
            
            // Atomically update: mark as redeemed
            $update_data = [
                'status'  => self::STATUS_REDEEMED
            ];
            $format = ['%s'];

            if (empty($license['user_id'])) {
                $update_data['user_id'] = get_current_user_id();
                $format[] = '%d';
            }

            if ($license['plan_level'] !== self::PLAN_AGENCY) {
                if (empty($license['site_url'])) {
                    $update_data['site_url'] = $site_url;
                    $format[] = '%s';
                }
            } else {
                $existing_sites = empty($license['site_url']) ? [] : array_map('trim', explode(',', $license['site_url']));
                if (!in_array($site_url, $existing_sites)) {
                    $existing_sites[] = $site_url;
                    $update_data['site_url'] = implode(',', $existing_sites);
                    $format[] = '%s';
                }
            }

            if (empty($license['redeemed_at'])) {
                $update_data['redeemed_at'] = current_time('mysql', true);
                $format[] = '%s';
            }
            
            $update_result = $wpdb->update( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
                $table,
                $update_data,
                ['id' => $license['id']],
                $format,
                ['%d']
            );
            
            if ($update_result === false) {
                // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Transaction management.
                $wpdb->query('ROLLBACK');
                return [
                    'success' => false,
                    'message' => __('Could not process license. Please try again.', 'fajaedeseo-ai'),
                    'code' => 'UPDATE_FAILED'
                ];
            }
            
            // Commit transaction
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Transaction management.
            $wpdb->query('COMMIT');

            $tier_name = ucfirst($license['plan_level']);
            
            return [
                'success' => true,
                /* translators: %s: Plan tier name (e.g., Pro, Premium, Agency) */
                'message' => sprintf(__('%s License Activated Successfully!', 'fajaedeseo-ai'), $tier_name),
                'expires_at' => $license['expires_at'],
                'plan_level' => $license['plan_level'],
                'redeemed_at' => $update_data['redeemed_at'] ?? $license['redeemed_at']
            ];
            
        } catch (Exception $e) {
            $wpdb->query('ROLLBACK'); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            return [
                'success' => false,
                'message' => __('Transaction error. Please try again.', 'fajaedeseo-ai'),
                'code' => 'TRANSACTION_ERROR'
            ];
        }
    }
    
    /**
     * Hash license code (never store plain text)
     */
    public static function hash_code(string $code): string {
        return hash('sha256', $code . 'fajaedeseo_license_salt');
    }
    
    /**
     * Check if license is expired
     */
    private static function is_expired(array $license): bool {
        if (empty($license['expires_at']) || strpos($license['expires_at'], '0000-00-00') !== false) {
            return false; // Treat as lifetime if not explicitly set
        }
        $timestamp = strtotime($license['expires_at']);
        if ($timestamp === false) {
            return false;
        }
        return $timestamp < current_time('timestamp');
    }
    
    /**
     * Cancel subscription (revoke license)
     * Only admin can revoke
     */
    public static function revoke_license(int $license_id, string $reason = ''): array {
        if (!current_user_can('manage_options')) {
            return ['success' => false, 'message' => __('Unauthorized.', 'fajaedeseo-ai')];
        }
        
        global $wpdb;
        $table = $wpdb->prefix . self::TABLE_NAME;
        
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- License revocation requires an immediate database update.
        $updated = $wpdb->update(
            $table,
            [
                'status'     => self::STATUS_REVOKED,
                'updated_at' => current_time('mysql', true)
            ],
            ['id' => $license_id],
            ['%s', '%s'],
            ['%d']
        );
        
        if ($updated) {
            update_option('fajaedeseo_pro_license_status', 'revoked');
            return ['success' => true, 'message' => __('License revoked.', 'fajaedeseo-ai')];
        }
        
        return ['success' => false, 'message' => __('Could not revoke license.', 'fajaedeseo-ai')];
    }
    
    /**
     * Admin: Generate new license codes
     * Returns plain codes (show to admin once, never store plain)
     */
    public static function generate_licenses(int $count = 1, int $expires_days = 365, string $plan_level = self::PLAN_PRO, bool $is_system = false) {
        if (!$is_system && !current_user_can('manage_options')) {
            return ['success' => false, 'message' => __('Unauthorized.', 'fajaedeseo-ai')];
        }
        
        global $wpdb;
        $table = $wpdb->prefix . self::TABLE_NAME;
        $generated_codes = [];
        
        $expires_at = gmdate('Y-m-d H:i:s', strtotime("+$expires_days days"));
        
        for ($i = 0; $i < $count; $i++) {
            $plain_code = self::generate_unique_code();
            $code_hash = self::hash_code($plain_code);
            
            $insert_data = [
                'code_hash'  => $code_hash,
                'status'     => self::STATUS_ACTIVE,
                'expires_at' => $expires_at,
                'plan_level' => $plan_level,
            ];
            
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $wpdb->insert($table, $insert_data, ['%s', '%s', '%s', '%s']);
            
            $generated_codes[] = $plain_code;
        }
        
        return [
            'success' => true,
            'codes' => $generated_codes,
            'message' => sprintf(
                /* translators: %d: count of generated license codes */
                __('%1$d license code(s) generated. Show these only once!', 'fajaedeseo-ai'),
                $count
            )
        ];
    }
    
    /**
     * Generate unique license code format (e.g., FSEO-XXXX-XXXX-XXXX)
     */
    public static function generate_unique_code() {
        do {
            $code = 'FSEO-' . strtoupper(
                substr(bin2hex(random_bytes(3)), 0, 4) . '-' .
                substr(bin2hex(random_bytes(3)), 0, 4) . '-' .
                substr(bin2hex(random_bytes(3)), 0, 4)
            );
            
            global $wpdb;
            $table = $wpdb->prefix . self::TABLE_NAME;
            $code_hash = self::hash_code($code);
            $fajaedeseo_exists = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM `{$table}` WHERE code_hash = %s", $code_hash ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
        } while ($fajaedeseo_exists);
        
        return $code;
    }

    /**
     * System: Generate and provision a new license after successful payment.
     * This is intended to be called by a payment gateway webhook on the master server.
     *
     * @param string $email The customer's email.
     * @param string $plan_level The plan tier (pro, premium, agency).
     * @param string $payment_id The transaction ID from the payment provider.
     * @param string $order_id The internal order ID.
     * @param float  $amount The payment amount.
     * @param string $currency The currency code.
     * @return array Result array with success status, license key, and optional password.
     */
    public static function generate_and_provision_license(string $email, string $plan_level, string $payment_id, string $order_id, float $amount, string $currency, array $vat_data = []): array {
        if (!defined('FAJAEDE_MASTER_SERVER') || !FAJAEDE_MASTER_SERVER) {
            return ['success' => false, 'message' => 'This function can only be run on the master server.'];
        }

        global $wpdb;
        $table = $wpdb->prefix . self::TABLE_NAME;

        // 1. Generate a new unique license code
        $plain_code = self::generate_unique_code();
        $code_hash = self::hash_code($plain_code);
        $expires_at = gmdate('Y-m-d H:i:s', strtotime("+366 days")); // 1 year + 1 day buffer

        // 2. Check if user exists, if not, create one
        $user = get_user_by('email', $email);
        $plain_password = '';
        if (!$user) {
            $plain_password = wp_generate_password(12, false);
            $user_id = wp_create_user($email, $plain_password, $email);
            if (is_wp_error($user_id)) {
                return ['success' => false, 'message' => 'Could not create user account: ' . $user_id->get_error_message()];
            }
            $user = get_user_by('id', $user_id);
            
            // We sturen geen standaard WordPress e-mail, omdat de FajaedeSEO licentie-email het wachtwoord al bevat.
        }

        // 3. Extract VAT data with defaults
        $country_code = sanitize_text_field($vat_data['country_code'] ?? 'BE');
        $customer_type = sanitize_text_field($vat_data['customer_type'] ?? 'particulier');
        $vat_number = sanitize_text_field($vat_data['vat_number'] ?? '');
        $vat_rate = floatval($vat_data['vat_rate'] ?? 0);

        // 4. Insert the new license into the database
        $insert_data = [
            'code_hash' => $code_hash,
            'status' => self::STATUS_ACTIVE, // It's active, but not yet redeemed on a client site
            'plan_level' => $plan_level,
            'expires_at' => $expires_at,
            'user_id' => $user->ID,
            'payment_id' => $payment_id,
            'invoice_number' => $order_id,
            'amount' => $amount,
            'currency' => $currency,
            'country_code' => $country_code,
            'vat_rate' => $vat_rate,
            'customer_type' => $customer_type,
            'vat_number' => $vat_number,
        ];
        $insert_format = ['%s', '%s', '%s', '%s', '%d', '%s', '%s', '%f', '%s', '%s', '%f', '%s', '%s'];

        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
        $inserted = $wpdb->insert($table, $insert_data, $insert_format);

        if (!$inserted) {
            return ['success' => false, 'message' => 'Database error while creating license.'];
        }

        return [
            'success' => true,
            'license_key' => $plain_code,
            'password_generated' => !empty($plain_password),
            'plain_password' => $plain_password,
            'license_id' => $wpdb->insert_id,
            'message' => 'License provisioned successfully.'
        ];
    }

    /**
     * Sends the license key email to the customer.
     *
     * @param string $email The customer's email address.
     * @param string $plan The purchased plan name.
     * @param string $license_key The generated license key.
     * @param string $password Optional plain-text password if a new account was created.
     */
    public static function send_license_email(string $email, string $plan, string $license_key, string $password = '', int $license_id = 0): void {
        $site_name = get_bloginfo('name');
        /* translators: %s: Plan name */
        $subject = sprintf(__('Your FajaedeSEO %s License Key', 'fajaedeseo-ai'), ucfirst($plan));
        
        $body = '<p>' . __('Hi there,', 'fajaedeseo-ai') . '</p>';
        /* translators: %s: Plan name */
        $body .= '<p>' . sprintf(__('Thank you for purchasing the FajaedeSEO %s plan! We are thrilled to have you on board.', 'fajaedeseo-ai'), '<strong>' . ucfirst($plan) . '</strong>') . '</p>';
        $body .= '<p>' . __('Here is your exclusive license key. Please copy it and paste it into the FajaedeSEO plugin settings on your WordPress site to activate all Pro features:', 'fajaedeseo-ai') . '</p>';
        $body .= '<p style="background: #f0f0f0; padding: 15px; border-radius: 5px; font-family: monospace; font-size: 16px; text-align: center;"><strong>' . esc_html($license_key) . '</strong></p>';

        /* translators: %s: Download URL */
        $body .= '<p>' . sprintf(__('You can download the latest version of the FajaedeSEO AI plugin here: <a href="%s" style="font-weight: bold; color: #0073aa;">Download FajaedeSEO AI</a>', 'fajaedeseo-ai'), 'https://fajaede.nl/download.php') . '</p>';

        if (!empty($password)) {
            $body .= '<p>' . __('A new account has been created for you on our website. You can use the following credentials to log in:', 'fajaedeseo-ai') . '</p>';
            $body .= '<ul>';
            $body .= '<li>' . __('Username:', 'fajaedeseo-ai') . ' ' . esc_html($email) . '</li>';
            $body .= '<li>' . __('Password:', 'fajaedeseo-ai') . ' ' . esc_html($password) . '</li>';
            $body .= '</ul>';
            $body .= '<p><a href="' . esc_url(home_url('/my-account/')) . '">' . __('Log in to your account', 'fajaedeseo-ai') . '</a></p>';
        } else {
            $body .= '<p>' . __('Since you already have an account with us, you can log in using your existing credentials to manage your new license.', 'fajaedeseo-ai') . '</p>';
            $body .= '<p><a href="' . esc_url(home_url('/my-account/')) . '">' . __('Go to My Account', 'fajaedeseo-ai') . '</a></p>';
        }

        $body .= '<p>' . __('If you have any questions, feel free to contact our support.', 'fajaedeseo-ai') . '</p>';
        $body .= '<p>' . __('Best regards,', 'fajaedeseo-ai') . '<br>' . $site_name . '</p>';

        $headers = ['Content-Type: text/html; charset=UTF-8'];
        $attachments = [];

        // Genereer en voeg de PDF factuur toe als bijlage
        if ($license_id > 0 && class_exists('\FajaedeSEO_Invoice_Generator')) {
            global $wpdb;
            $table = $wpdb->prefix . self::TABLE_NAME;
            $cache_key = 'fajaedeseo_license_' . $license_id;
            $license = wp_cache_get($cache_key, 'fajaedeseo_licenses');
            if (false === $license) {
                $license = $wpdb->get_row($wpdb->prepare("SELECT * FROM `" . esc_sql($table) . "` WHERE id = %d", $license_id)); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery
                if ($license) {
                    wp_cache_set($cache_key, $license, 'fajaedeseo_licenses', 3600);
                }
            }
            if ($license) {
                $order_data = \FajaedeSEO_Invoice_Generator::prepare_invoice_data($license);
                $upload_dir = wp_upload_dir();
                $pdf_path = wp_normalize_path(trailingslashit($upload_dir['basedir']) . 'Invoice_' . sanitize_file_name($order_data['invoice_number']) . '.pdf');
                $generated_path = \FajaedeSEO_Invoice_Generator::generate_pdf($order_data, $pdf_path);
                if ($generated_path) {
                    $attachments[] = $generated_path;
                }
            }
        }
        
        wp_mail($email, $subject, $body, $headers, $attachments);

        // Verwijder de tijdelijke PDF van de server nadat de mail is verstuurd
        foreach ($attachments as $attachment) {
            if (file_exists($attachment)) {
                wp_delete_file($attachment);
            }
        }
    }
}
