<?php
/**
 * License API Integration for ExploreXR
 * 
 * Handles license activation, validation, and management for users who have purchased
 * licenses from external sources (expoxr.com or other vendors)
 */

// Exit if accessed directly
if (!defined('ABSPATH')) {
    exit;
}

/**
 * ExploreXR License API Integration Class
 * 
 * This class handles:
 * - License key activation from external purchases
 * - License validation with remote API
 * - License deactivation
 * - Addon access control based on license tier
 */
class ExploreXR_License_API_Integration {
    
    /**
     * The single instance of the class.
     */
    protected static $_instance = null;
    
    /**
     * License Manager API endpoint
     */
    private $api_url = 'https://expoxr.com/wp-json/lmfwc/v2/';

    /**
     * ExploreXR public license service endpoint.
     *
     * This endpoint should hold LMFWC credentials server-side. Customer sites
     * can still fall back to direct LMFWC requests when constants are present.
     */
    private $license_server_url = 'https://expoxr.com/wp-json/explorexr/v1/license/';
    
    /**
     * Consumer Key and Secret for API authentication
     * SECURITY: These must be defined as constants in wp-config.php
     * Never hardcode credentials in source code
     */
    private $consumer_key = ''; // Set via EXPLOREXR_LM_CONSUMER_KEY constant
    private $consumer_secret = ''; // Set via EXPLOREXR_LM_CONSUMER_SECRET constant
    
    /**
     * License tiers configuration
     * These define what each license tier includes
     */
    private $license_tiers = array(
        'FREE' => array(
            'name'            => 'ExploreXR Free',
            'max_addons'      => 0,
            'included_addons' => array(),
            'price'           => 'Free',
            'description'     => 'Basic 3D model viewer with limited features. Add-ons require a valid license.',
        ),
        'TRIAL' => array(
            'name'            => 'ExploreXR Trial',
            'max_addons'      => 4, // Same as Plus
            'included_addons' => array(), // User choice — no pre-selected addons
            'price'           => 'Free (14-day)',
            'description'     => '14-day trial with full Plus-tier features and 4 add-ons of your choice. Key prefix: EXTR-',
        ),
        'PRO' => array(
            'name'            => 'ExploreXR Pro',
            'max_addons'      => 2,
            'included_addons' => array(),
            'price'           => '$59',
            'description'     => 'Advanced 3D model viewer with premium features and 2 add-ons of your choice.',
        ),
        'PLUS' => array(
            'name'            => 'ExploreXR Plus',
            'max_addons'      => 4,
            'included_addons' => array(),
            'price'           => '$99',
            'description'     => 'Enhanced 3D model viewer with premium features and 4 add-ons of your choice.',
        ),
        'ULTRA' => array(
            'name'            => 'ExploreXR Ultra',
            'max_addons'      => -1,
            'included_addons' => array('ar', 'camera', 'annotations', 'materials', 'loading', 'woocommerce', 'animation', 'morphing', 'mouse3d', 'post-processing', 'environment', 'draggable'),
            'price'           => '$199',
            'description'     => 'Ultimate 3D model viewer with all premium features and all add-ons included.',
        ),
    );
    
    /**
     * Main Instance.
     */
    public static function instance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }
    
    /**
     * Constructor. Private to enforce singleton — use instance() instead.
     */
    private function __construct() {
        $this->init_hooks();
    }
    
    /**
     * Initialize hooks
     */
    private function init_hooks() {
        // Note: explorexr_validate_license_real_time is also registered in license-handler.php;
        // the handler delegates to this class's ajax_validate_license() when available.
        // explorexr_deactivate_license_improved is registered ONLY in license-handler.php.
        // Registering it here a second time caused double-execution — do NOT re-add it.
        add_action('wp_ajax_explorexr_activate_license_api', array($this, 'ajax_activate_license'));
    }
    
    /**
     * Validate license key format.
     * Accepts PRO-, PLUS-, ULTRA-, and EXTR- (trial) prefixes.
     */
    public function validate_license_format($license_key) {
        // Format: TIER-XXXX-XXXX-XXXX-XXXX-XXXX-EXXR
        $pattern = '/^(ULTRA|PLUS|PRO|EXTR)-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-EXXR$/';

        if (!preg_match($pattern, $license_key)) {
            return array(
                'valid' => false,
                'error' => 'Invalid license key format. Expected: TIER-XXXX-XXXX-XXXX-XXXX-XXXX-EXXR'
            );
        }

        $tier       = $this->extract_tier_from_license($license_key);
        $tier_upper = strtoupper($tier);
        if (!array_key_exists($tier_upper, $this->license_tiers)) {
            return array(
                'valid' => false,
                'error' => 'Invalid license tier: ' . esc_html($tier)
            );
        }

        return array(
            'valid' => true,
            'tier'  => $tier // lowercase for internal use
        );
    }

    /**
     * Extract tier from license key.
     * EXTR- prefix maps to the 'trial' tier.
     */
    public function extract_tier_from_license($license_key) {
        if (strpos($license_key, 'ULTRA-') === 0) {
            return 'ultra';
        } elseif (strpos($license_key, 'PLUS-') === 0) {
            return 'plus';
        } elseif (strpos($license_key, 'PRO-') === 0) {
            return 'pro';
        } elseif (strpos($license_key, 'EXTR-') === 0) {
            return 'trial';
        }

        // Fallback for unexpected formats
        $parts = explode('-', $license_key);
        return isset($parts[0]) ? strtolower($parts[0]) : '';
    }

    /**
     * Debug logging helper.
     */
    private function debug_log($message) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional debug logging behind WP_DEBUG
            error_log($message);
        }
    }

    /**
     * Get the public ExploreXR license service URL.
     */
    private function get_license_server_url() {
        $server_url = defined('EXPLOREXR_LICENSE_SERVER_URL') && !empty(EXPLOREXR_LICENSE_SERVER_URL)
            ? EXPLOREXR_LICENSE_SERVER_URL
            : $this->license_server_url;

        return rtrim($server_url, '/') . '/';
    }

    /**
     * Request the public ExploreXR license service.
     *
     * Returns null when the public service is unavailable or not installed, so
     * callers can fall back to the legacy LMFWC API credentials path.
     */
    private function request_license_service($action, $license_key, $tier) {
        $endpoint = $this->get_license_server_url() . $action;

        $response = wp_remote_post($endpoint, array(
            'timeout'   => 30,
            'sslverify' => true,
            'headers'   => array(
                'Content-Type' => 'application/json',
                'Accept'       => 'application/json',
                'User-Agent'   => 'ExploreXR/' . (defined('EXPLOREXR_VERSION') ? EXPLOREXR_VERSION : '1.0.0'),
            ),
            'body'      => wp_json_encode(array(
                'license_key'    => $license_key,
                'site_url'       => home_url(),
                'plugin_version' => defined('EXPLOREXR_VERSION') ? EXPLOREXR_VERSION : '',
                'action'         => $action,
            )),
        ));

        if (is_wp_error($response)) {
            $this->debug_log('ExploreXR License Service: public endpoint unavailable - ' . $response->get_error_message());
            return null;
        }

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

        if ($response_code === 404 || !is_array($data)) {
            $this->debug_log('ExploreXR License Service: public endpoint missing or returned invalid JSON');
            return null;
        }

        if ($response_code >= 500) {
            $this->debug_log('ExploreXR License Service: public endpoint returned HTTP ' . absint($response_code) . ', falling back to LMFWC');
            return null;
        }

        if ($response_code < 200 || $response_code >= 300) {
            return $this->build_remote_error_result($action, $data, $response_code);
        }

        return $this->normalize_license_service_response($action, $data, $tier);
    }

    /**
     * Normalize an error returned by a remote license service.
     */
    private function build_remote_error_result($action, $data, $response_code) {
        $message = $this->extract_remote_error_message($data);

        if (empty($message)) {
            if ($response_code === 429) {
                $message = 'Too many license requests. Please try again later.';
            } else {
                $message = 'License service request failed (HTTP ' . absint($response_code) . ').';
            }
        }

        if ($action === 'deactivate') {
            return array(
                'success' => false,
                'error'   => $message,
            );
        }

        return array(
            'valid' => false,
            'error' => $message,
        );
    }

    /**
     * Extract a usable error message from remote API response data.
     */
    private function extract_remote_error_message($data) {
        if (isset($data['message']) && is_string($data['message'])) {
            return $data['message'];
        }

        if (isset($data['error']) && is_string($data['error'])) {
            return $data['error'];
        }

        if (isset($data['data']['message']) && is_string($data['data']['message'])) {
            return $data['data']['message'];
        }

        if (isset($data['data']['error']) && is_string($data['data']['error'])) {
            return $data['data']['error'];
        }

        return '';
    }

    /**
     * Normalize successful public license service responses.
     */
    private function normalize_license_service_response($action, $data, $tier) {
        $license_info = isset($data['data']) && is_array($data['data']) ? $data['data'] : $data;

        if ($action === 'deactivate') {
            $success = (isset($data['success']) && $data['success'] === true)
                || (isset($license_info['success']) && $license_info['success'] === true);

            if (!$success) {
                return array(
                    'success' => false,
                    'error'   => $this->extract_remote_error_message($data) ?: 'License deactivation failed',
                );
            }

            return array(
                'success' => true,
                'message' => isset($license_info['message']) ? $license_info['message'] : 'License deactivated successfully',
            );
        }

        $is_valid = (isset($data['valid']) && $data['valid'] === true)
            || (isset($data['success']) && $data['success'] === true)
            || (isset($license_info['valid']) && $license_info['valid'] === true)
            || (isset($license_info['success']) && $license_info['success'] === true);

        if (!$is_valid) {
            return array(
                'valid' => false,
                'error' => $this->extract_remote_error_message($data) ?: 'License is not valid',
            );
        }

        $license_tier = isset($license_info['tier']) ? strtolower(sanitize_key($license_info['tier'])) : strtolower($tier);
        $tier_info    = isset($this->license_tiers[strtoupper($license_tier)]) ? $this->license_tiers[strtoupper($license_tier)] : null;

        if (!$tier_info) {
            return array(
                'valid' => false,
                'error' => 'Invalid license tier: ' . esc_html($license_tier),
            );
        }

        $expires = null;
        foreach (array('expires', 'expiresAt', 'expires_at', 'date_expires') as $expires_key) {
            if (isset($license_info[$expires_key]) && !empty($license_info[$expires_key])) {
                $expires = $license_info[$expires_key];
                break;
            }
        }

        $remaining_activations = isset($license_info['remaining_activations'])
            ? intval($license_info['remaining_activations'])
            : (isset($license_info['remainingActivations']) ? intval($license_info['remainingActivations']) : 0);

        $times_activated = isset($license_info['times_activated'])
            ? intval($license_info['times_activated'])
            : (isset($license_info['timesActivated']) ? intval($license_info['timesActivated']) : 0);

        $max_activations = isset($license_info['max_activations'])
            ? intval($license_info['max_activations'])
            : (isset($license_info['timesActivatedMax']) ? intval($license_info['timesActivatedMax']) : 1);

        $activation_data = array();
        if (isset($license_info['activation_data']) && is_array($license_info['activation_data'])) {
            $activation_data = $license_info['activation_data'];
        } elseif (isset($license_info['activationData']) && is_array($license_info['activationData'])) {
            $activation_data = $license_info['activationData'];
        }

        $license_status = isset($license_info['status']) ? sanitize_key($license_info['status']) : 'active';
        if (in_array($license_status, array('sold', 'valid'), true)) {
            $license_status = 'active';
        }

        $result = array(
            'valid'                 => true,
            'tier'                  => $license_tier,
            'tier_name'             => $tier_info['name'],
            'max_addons'            => $tier_info['max_addons'],
            'status'                => $license_status,
            'expires'               => $expires,
            'remaining_activations' => $remaining_activations,
            'times_activated'       => $times_activated,
            'max_activations'       => $max_activations,
            'activation_data'       => $activation_data,
            'order_id'              => isset($license_info['order_id']) ? sanitize_text_field($license_info['order_id']) : (isset($license_info['orderId']) ? sanitize_text_field($license_info['orderId']) : ''),
            'product_id'            => isset($license_info['product_id']) ? sanitize_text_field($license_info['product_id']) : (isset($license_info['productId']) ? sanitize_text_field($license_info['productId']) : ''),
        );

        if (isset($license_info['activation_token'])) {
            $result['activation_token'] = sanitize_text_field($license_info['activation_token']);
        } elseif (isset($license_info['token'])) {
            $result['activation_token'] = sanitize_text_field($license_info['token']);
        }

        return $result;
    }

    /**
     * Customer-facing message for server configuration failures.
     */
    private function get_license_service_configuration_error() {
        return 'License service is not configured. Please contact support.';
    }
    
    /**
     * Validate license with remote API.
     * Trial (EXTR-) keys are validated locally — no API call is made.
     */
    public function validate_license_remote($license_key, $use_public_service = true) {
        // First validate format
        $format_check = $this->validate_license_format($license_key);
        if (!$format_check['valid']) {
            return $format_check;
        }

        $tier = $format_check['tier'];

        // Trial licenses are always local — skip remote API.
        if ($tier === 'trial') {
            // BUG-03 fix: verify the key being validated matches the one actually activated on
            // this site. Mismatches indicate corrupted or forged license data.
            $stored_key = get_option('explorexr_trial_key_used', '');
            if (!empty($stored_key) && !hash_equals($stored_key, $license_key)) {
                return array(
                    'valid' => false,
                    'error' => 'Trial license key does not match the key activated on this site.',
                );
            }

            $trial_started = (int) get_option('explorexr_trial_started_at', 0);
            $duration      = 14 * DAY_IN_SECONDS;

            // BUG-05 fix: if the trial has never been properly started (corrupted state),
            // refuse to compute a fresh window — require a proper activation instead.
            if (!$trial_started) {
                return array(
                    'valid' => false,
                    'error' => 'Trial has not been activated on this site. Please activate your trial key.',
                );
            }

            $trial_expiry = gmdate('Y-m-d', $trial_started + $duration);

            if (time() > $trial_started + $duration) {
                return array(
                    'valid' => false,
                    'error' => 'This 14-day trial has expired. Please purchase a full license.'
                );
            }

            return array(
                'valid'                 => true,
                'tier'                  => 'trial',
                'tier_name'             => 'ExploreXR Trial',
                'max_addons'            => 4,
                'status'                => 'active',
                'expires'               => $trial_expiry,
                'remaining_activations' => 1,
                'times_activated'       => 1,
                'max_activations'       => 1,
                'activation_data'       => array(),
                'order_id'              => '',
                'product_id'            => '',
            );
        }

        if ($use_public_service) {
            $service_result = $this->request_license_service('validate', $license_key, $tier);
            if (is_array($service_result)) {
                return $service_result;
            }
        }

        // Use GET request to validate license
        $api_endpoint = $this->api_url . 'licenses/validate/' . rawurlencode( $license_key );
        
        // Add authentication
        $consumer_key = $this->get_api_consumer_key();
        $consumer_secret = $this->get_api_consumer_secret();
        
        if (empty($consumer_key) || empty($consumer_secret)) {
            return array(
                'valid' => false,
                'error' => $this->get_license_service_configuration_error()
            );
        }
        
        $response = wp_remote_get($api_endpoint, array(
            'timeout' => 30,
            'headers' => array(
                'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
                'Content-Type' => 'application/json',
                'Accept' => 'application/json'
            ),
        ));
        
        if (is_wp_error($response)) {
            return array(
                'valid' => false,
                'error' => 'Unable to connect to license server: ' . $response->get_error_message()
            );
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        $response_code = wp_remote_retrieve_response_code($response);
        
        // Check for successful response
        if ($response_code !== 200) {
            $error_message = 'License validation failed (HTTP ' . $response_code . ')';
            if (isset($data['message'])) {
                $error_message = $data['message'];
            } elseif (isset($data['data']['message'])) {
                $error_message = $data['data']['message'];
            }
            
            return array(
                'valid' => false,
                'error' => $error_message
            );
        }
        
        // Parse the response according to your API structure
        if (!isset($data['success']) || $data['success'] !== true) {
            $error_message = isset($data['message']) ? $data['message'] : 'License is not valid';
            
            return array(
                'valid' => false,
                'error' => $error_message
            );
        }
        
        // Extract license information from the API response
        $license_info = isset($data['data']) ? $data['data'] : $data;
        
        // Check for activation data to determine if license has remaining activations
        $remaining_activations = 0;
        $times_activated = 0;
        $max_activations = 1;
        
        if (isset($license_info['remainingActivations'])) {
            $remaining_activations = intval($license_info['remainingActivations']);
        }
        
        if (isset($license_info['timesActivated'])) {
            $times_activated = intval($license_info['timesActivated']);
        }
        
        if (isset($license_info['timesActivatedMax'])) {
            $max_activations = intval($license_info['timesActivatedMax']);
        }
        
        // License is valid - extract tier and other details
        $license_tier = strtolower($tier);
        $tier_info = isset($this->license_tiers[strtoupper($tier)]) ? $this->license_tiers[strtoupper($tier)] : null;
        
        if (!$tier_info) {
            return array(
                'valid' => false,
                'error' => 'Invalid license tier: ' . $tier
            );
        }
        
        return array(
            'valid' => true,
            'tier' => $license_tier,
            'tier_name' => $tier_info['name'],
            'max_addons' => $tier_info['max_addons'],
            'status' => 'active',
            'expires' => isset($license_info['expiresAt']) ? $license_info['expiresAt'] : null,
            'remaining_activations' => $remaining_activations,
            'times_activated' => $times_activated,
            'max_activations' => $max_activations,
            'activation_data' => isset($license_info['activationData']) ? $license_info['activationData'] : array(),
            'order_id' => isset($license_info['orderId']) ? $license_info['orderId'] : '',
            'product_id' => isset($license_info['productId']) ? $license_info['productId'] : ''
        );
    }
    
    /**
     * Deactivate license with remote API
     */
    public function deactivate_license_remote($license_key, $use_public_service = true) {
        $tier = $this->extract_tier_from_license($license_key);
        if ($use_public_service) {
            $service_result = $this->request_license_service('deactivate', $license_key, $tier);
            if (is_array($service_result)) {
                return $service_result;
            }
        }

        // Use GET request to deactivate license as specified
        $api_endpoint = $this->api_url . 'licenses/deactivate/' . rawurlencode( $license_key );
        
        // Add authentication
        $consumer_key = $this->get_api_consumer_key();
        $consumer_secret = $this->get_api_consumer_secret();
        
        if (empty($consumer_key) || empty($consumer_secret)) {
            return array(
                'success' => false,
                'error' => $this->get_license_service_configuration_error()
            );
        }
        
        $response = wp_remote_get($api_endpoint, array(
            'timeout' => 30,
            'headers' => array(
                'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
                'Content-Type' => 'application/json',
                'Accept' => 'application/json'
            ),
        ));
        
        if (is_wp_error($response)) {
            return array(
                'success' => false,
                'error' => 'Unable to connect to license server: ' . $response->get_error_message()
            );
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        $response_code = wp_remote_retrieve_response_code($response);
        
        if ($response_code !== 200) {
            return array(
                'success' => false,
                'error' => isset($data['message']) ? $data['message'] : 'License deactivation failed'
            );
        }
        
        // Check if deactivation was successful
        if (!isset($data['success']) || $data['success'] !== true) {
            return array(
                'success' => false,
                'error' => isset($data['message']) ? $data['message'] : 'License deactivation failed'
            );
        }
        
        return array(
            'success' => true,
            'message' => isset($data['message']) ? $data['message'] : 'License deactivated successfully'
        );
    }
    /**
     * Activate license with remote API.
     * Trial (EXTR-) keys are activated locally — no API call is made.
     */
    public function activate_license_remote($license_key, $use_public_service = true) {
        // Trial licenses: delegate to the License Handler's activate_trial_license() so
        // trial state (explorexr_trial_started_at, explorexr_trial_key_used) is always
        // persisted regardless of which code path triggered the activation.
        if (strpos($license_key, 'EXTR-') === 0) {
            if (class_exists('ExploreXR_License_Handler')) {
                return ExploreXR_License_Handler::instance()->activate_trial_license($license_key);
            }
            return array('valid' => false, 'error' => 'License system unavailable. Please contact support.');
        }

        $format_check = $this->validate_license_format($license_key);
        if (!$format_check['valid']) {
            return $format_check;
        }

        if ($use_public_service) {
            $service_result = $this->request_license_service('activate', $license_key, $format_check['tier']);
            if (is_array($service_result)) {
                return $service_result;
            }
        }

        // First validate the license (remote)
        $validation_result = $this->validate_license_remote($license_key, false);
        if (!$validation_result['valid']) {
            return $validation_result;
        }

        // Use GET request to activate license as specified in the requirements
        $api_endpoint = $this->api_url . 'licenses/activate/' . rawurlencode( $license_key );
        
        // Add authentication
        $consumer_key = $this->get_api_consumer_key();
        $consumer_secret = $this->get_api_consumer_secret();
        
        if (empty($consumer_key) || empty($consumer_secret)) {
            return array(
                'valid' => false,
                'error' => $this->get_license_service_configuration_error()
            );
        }
        
        $response = wp_remote_get($api_endpoint, array(
            'timeout' => 30,
            'headers' => array(
                'Authorization' => 'Basic ' . base64_encode($consumer_key . ':' . $consumer_secret),
                'Content-Type' => 'application/json',
                'Accept' => 'application/json'
            ),
        ));
        
        if (is_wp_error($response)) {
            $error_msg = 'Unable to connect to license server: ' . $response->get_error_message();
            
            return array(
                'valid' => false,
                'error' => $error_msg
            );
        }
        
        $body = wp_remote_retrieve_body($response);
        $data = json_decode($body, true);
        $response_code = wp_remote_retrieve_response_code($response);
        
        // Check for successful response
        if ($response_code !== 200) {
            $error_message = 'License activation failed (HTTP ' . $response_code . ')';
            if (isset($data['message'])) {
                $error_message = $data['message'];
            } elseif (isset($data['data']['message'])) {
                $error_message = $data['data']['message'];
            }
            
            return array(
                'valid' => false,
                'error' => $error_message
            );
        }
        
        // Parse the response according to your API structure
        if (!isset($data['success']) || $data['success'] !== true) {
            return array(
                'valid' => false,
                'error' => isset($data['message']) ? $data['message'] : 'License activation failed'
            );
        }
        
        // Return the validation result with activation token if provided
        $result = $validation_result;
        if (isset($data['data']['token'])) {
            $result['activation_token'] = $data['data']['token'];
        }
        
        return $result;
    }

    /**
     * Get API Consumer Key
     * SECURITY: Must be defined in wp-config.php
     */
    private function get_api_consumer_key() {
        // Priority 1: EXPLOREXR_LM_CONSUMER_KEY constant (recommended)
        if (defined('EXPLOREXR_LM_CONSUMER_KEY') && trim((string) EXPLOREXR_LM_CONSUMER_KEY) !== '') {
            return trim((string) EXPLOREXR_LM_CONSUMER_KEY);
        }
        
        // Priority 2: Fallback to generic WooCommerce constant
        if (defined('EXPLOREXR_WC_CONSUMER_KEY') && trim((string) EXPLOREXR_WC_CONSUMER_KEY) !== '') {
            return trim((string) EXPLOREXR_WC_CONSUMER_KEY);
        }
        
        return '';
    }
    
    /**
     * Get API Consumer Secret
     * SECURITY: Must be defined in wp-config.php
     */
    private function get_api_consumer_secret() {
        // Priority 1: EXPLOREXR_LM_CONSUMER_SECRET constant (recommended)
        if (defined('EXPLOREXR_LM_CONSUMER_SECRET') && trim((string) EXPLOREXR_LM_CONSUMER_SECRET) !== '') {
            return trim((string) EXPLOREXR_LM_CONSUMER_SECRET);
        }
        
        // Priority 2: Fallback to generic WooCommerce constant
        if (defined('EXPLOREXR_WC_CONSUMER_SECRET') && trim((string) EXPLOREXR_WC_CONSUMER_SECRET) !== '') {
            return trim((string) EXPLOREXR_WC_CONSUMER_SECRET);
        }
        
        return '';
    }
    
    /**
     * Get license tiers configuration
     */
    public function get_license_tiers() {
        return $this->license_tiers;
    }
    
    /**
     * AJAX handler for license activation (API-specific endpoint).
     *
     * Previously this handler wrote license data directly to six flat wp_options
     * that are not read by any other part of the system. All license state is now
     * stored exclusively through ExploreXR_License_Handler so every subsystem reads
     * from the same authoritative explorexr_license_data option.
     */
    public function ajax_activate_license() {
        try {
            // Check nonce for security
            // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified on the next line
            $nonce_value = isset($_POST['explorexr_license_nonce'])
                ? sanitize_text_field(wp_unslash($_POST['explorexr_license_nonce']))
                : (isset($_POST['explorexr_premium_license_nonce'])
                    ? sanitize_text_field(wp_unslash($_POST['explorexr_premium_license_nonce']))
                    : (isset($_POST['nonce'])
                        ? sanitize_text_field(wp_unslash($_POST['nonce']))
                        : ''));

            $nonce_valid = $nonce_value && (wp_verify_nonce($nonce_value, 'explorexr_premium_license_nonce') || wp_verify_nonce($nonce_value, 'explorexr_license_nonce'));

            if (!$nonce_valid) {
                wp_send_json_error(array('message' => 'Security check failed. For more help, please contact support.'));
                return;
            }

            if (!current_user_can('manage_options')) {
                wp_send_json_error(array('message' => 'Insufficient permissions. For more help, please contact support.'));
                return;
            }

            // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce verified above
            $license_key = isset($_POST['license_key']) ? sanitize_text_field(wp_unslash($_POST['license_key'])) : '';

            if (empty($license_key)) {
                wp_send_json_error(array('message' => 'Please enter a license key. For more help, please contact support.'));
                return;
            }

            // Delegate entirely to the central license handler so all state is stored
            // in explorexr_license_data (the single source of truth).
            if (!class_exists('ExploreXR_License_Handler')) {
                wp_send_json_error(array('message' => 'License system unavailable. For more help, please contact support.'));
                return;
            }

            $result = ExploreXR_License_Handler::instance()->activate_license($license_key);

            if ($result['success']) {
                wp_send_json_success(array('message' => $result['message']));
            } else {
                $error_message = $result['message'];
                if (strpos($error_message, 'contact support') === false) {
                    $error_message .= ' For more help, please contact support.';
                }
                wp_send_json_error(array('message' => $error_message));
            }
        } catch (Exception $e) {
            wp_send_json_error(array(
                'message' => 'An error occurred while activating your license. For more help, please contact support.'
            ));
        } catch (Error $e) {
            wp_send_json_error(array(
                'message' => 'A system error occurred. For more help, please contact support.'
            ));
        }
    }
    
    /**
     * AJAX handler for license deactivation (kept for any direct callers).
     *
     * Previously this handler read the license key from an orphaned flat wp_option
     * (explorexr_license_key) and cleared six separate flat options on success.
     * It now delegates entirely to ExploreXR_License_Handler so state is managed
     * through the single explorexr_license_data option.
     *
     * Note: the primary AJAX action (explorexr_deactivate_license_improved) is
     * registered in license-handler.php. This method handles any calls made to
     * the integration class directly.
     */
    public function ajax_deactivate_license() {
        try {
            // Check nonce for security
            // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Nonce is verified on the next line
            $nonce_value = isset($_POST['explorexr_license_nonce'])
                ? sanitize_text_field(wp_unslash($_POST['explorexr_license_nonce']))
                : (isset($_POST['explorexr_premium_license_nonce'])
                    ? sanitize_text_field(wp_unslash($_POST['explorexr_premium_license_nonce']))
                    : (isset($_POST['nonce'])
                        ? sanitize_text_field(wp_unslash($_POST['nonce']))
                        : ''));

            $nonce_valid = $nonce_value && (wp_verify_nonce($nonce_value, 'explorexr_premium_license_nonce') || wp_verify_nonce($nonce_value, 'explorexr_license_nonce'));

            if (!$nonce_valid) {
                wp_send_json_error(array('message' => 'Security check failed. For more help, please contact support.'));
                return;
            }

            if (!current_user_can('manage_options')) {
                wp_send_json_error(array('message' => 'Insufficient permissions. For more help, please contact support.'));
                return;
            }

            if (!class_exists('ExploreXR_License_Handler')) {
                wp_send_json_error(array('message' => 'License system unavailable. For more help, please contact support.'));
                return;
            }

            $result = ExploreXR_License_Handler::instance()->deactivate_license();

            if ($result['success']) {
                wp_send_json_success(array(
                    'message' => $result['message'],
                    'type'    => 'success',
                ));
            } else {
                $error_message = $result['message'];
                if (strpos($error_message, 'contact support') === false) {
                    $error_message .= ' For more help, please contact support.';
                }
                wp_send_json_error(array(
                    'message' => $error_message,
                    'type'    => 'error',
                ));
            }
        } catch (Exception $e) {
            wp_send_json_error(array(
                'message' => 'An error occurred while deactivating your license. For more help, please contact support.',
                'type'    => 'error',
            ));
        } catch (Error $e) {
            wp_send_json_error(array(
                'message' => 'A system error occurred. For more help, please contact support.',
                'type'    => 'error',
            ));
        }
    }

    /**
     * AJAX handler for real-time license validation
     */
    public function ajax_validate_license() {
        try {
            // Check nonce for security
            $nonce_value = isset($_POST['explorexr_license_nonce'])
                ? sanitize_text_field(wp_unslash($_POST['explorexr_license_nonce']))
                : (isset($_POST['explorexr_premium_license_nonce'])
                    ? sanitize_text_field(wp_unslash($_POST['explorexr_premium_license_nonce']))
                    : (isset($_POST['nonce'])
                        ? sanitize_text_field(wp_unslash($_POST['nonce']))
                        : ''));

            $nonce_valid = $nonce_value && (wp_verify_nonce($nonce_value, 'explorexr_premium_license_nonce') || wp_verify_nonce($nonce_value, 'explorexr_license_nonce'));

            if (!$nonce_valid) {
                wp_send_json_error(array('message' => 'Security check failed. For more help, please contact support.'));
                return;
            }
            
            // Check user permissions
            if (!current_user_can('manage_options')) {
                wp_send_json_error(array('message' => 'Insufficient permissions. For more help, please contact support.'));
                return;
            }
            
            $license_key = isset($_POST['license_key']) ? sanitize_text_field(wp_unslash($_POST['license_key'])) : '';
            
            if (empty($license_key)) {
                wp_send_json_error(array(
                    'message' => 'Please enter a license key to validate. For more help, please contact support.',
                    'type' => 'warning'
                ));
                return;
            }
            
            // Validate license with remote API
            $validation_result = $this->validate_license_remote($license_key);
            
            if ($validation_result['valid']) {
                // Check if license is already activated — read from central license data.
                $central_data    = get_option('explorexr_license_data', array());
                $current_license = isset($central_data['key']) ? $central_data['key'] : '';
                if ($current_license === $license_key) {
                    $expires_message = '';
                    if (isset($validation_result['expires']) && !empty($validation_result['expires'])) {
                        $expires_date = gmdate('F j, Y', strtotime($validation_result['expires']));
                        $expires_message = " Valid until {$expires_date}";
                    }
                    
                    wp_send_json_success(array(
                        'message' => "License already activated.{$expires_message}",
                        'type' => 'success',
                        'tier' => strtolower($validation_result['tier']),
                        'status' => $validation_result['status'],
                        'expires' => isset($validation_result['expires']) ? $validation_result['expires'] : '',
                        'already_activated' => true
                    ));
                } else {
                    // License is valid but not activated
                    $expires_message = '';
                    if (isset($validation_result['expires']) && !empty($validation_result['expires'])) {
                        $expires_date = gmdate('F j, Y', strtotime($validation_result['expires']));
                        $expires_message = " Valid until {$expires_date}";
                    }
                    
                    wp_send_json_success(array(
                        'message' => "License key is valid and ready for activation.{$expires_message}",
                        'type' => 'info',
                        'tier' => strtolower($validation_result['tier']),
                        'status' => $validation_result['status'],
                        'expires' => isset($validation_result['expires']) ? $validation_result['expires'] : '',
                        'remaining_activations' => isset($validation_result['remaining_activations']) ? $validation_result['remaining_activations'] : 1,
                        'already_activated' => false
                    ));
                }
            } else {
                // Add support contact message to error
                $error_message = $validation_result['error'];
                if (strpos($error_message, 'contact support') === false) {
                    $error_message .= ' For more help, please contact support.';
                }
                wp_send_json_error(array(
                    'message' => $error_message,
                    'type' => 'error'
                ));
            }
        } catch (Exception $e) {
            wp_send_json_error(array(
                'message' => 'An error occurred while validating your license. For more help, please contact support.',
                'type' => 'error'
            ));
        } catch (Error $e) {
            wp_send_json_error(array(
                'message' => 'A system error occurred. For more help, please contact support.',
                'type' => 'error'
            ));
        }
    }

    /**
     * Secure license validation method.
     *
     * Uses the same public-service-then-LMFWC fallback path as activation so all
     * tiers share one remote validation behavior.
     *
     * @param string $license_key  The license key to validate.
     * @param bool   $force_remote Whether to force remote validation.
     * @return array Validation result.
     */
    public function validate_license_secure($license_key, $force_remote = false) {
        if (empty($license_key)) {
            return array(
                'valid'  => false,
                'error'  => 'License key is required',
                'cached' => false,
            );
        }

        if (!$force_remote && strpos($license_key, 'EXTR-') !== 0) {
            $cache_key     = 'explorexr_license_validation_' . md5($license_key);
            $cached_result = get_transient($cache_key);

            if ($cached_result !== false) {
                $cached_result['cached'] = true;
                return $cached_result;
            }
        }

        $result           = $this->validate_license_remote($license_key);
        $result['cached'] = false;

        if (strpos($license_key, 'EXTR-') !== 0) {
            set_transient(
                'explorexr_license_validation_' . md5($license_key),
                $result,
                !empty($result['valid']) ? HOUR_IN_SECONDS : 5 * MINUTE_IN_SECONDS
            );
        }

        return $result;
    }
    
    /**
     * Get product ID for license tier (for API requests)
     */
    private function get_product_id_for_tier($tier) {
        $product_ids = array(
            'PRO' => defined('EXPLOREXR_PRO_PRODUCT_ID') ? EXPLOREXR_PRO_PRODUCT_ID : 1,
            'PLUS' => defined('EXPLOREXR_PLUS_PRODUCT_ID') ? EXPLOREXR_PLUS_PRODUCT_ID : 2,
            'ULTRA' => defined('EXPLOREXR_ULTRA_PRODUCT_ID') ? EXPLOREXR_ULTRA_PRODUCT_ID : 3
        );
        
        return isset($product_ids[$tier]) ? $product_ids[$tier] : 1;
    }
}
