<?php
/**
 * ExploreXR License Expiration Handler
 *
 * Handles license expiration checking, grace period management,
 * and warning flag storage for the cron-based daily check.
 *
 * Admin notices are displayed by ExploreXR_License_Handler
 * ::maybe_show_license_expiry_notice() which reads live license
 * data. This class manages the stored flags and cron schedule only.
 *
 * @package ExploreXR Premium
 */

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

/**
 * License Expiration Handler Class
 */
class ExploreXR_License_Expiration_Handler {
    /**
     * The single instance of the class.
     */
    protected static $_instance = null;

    /**
     * Grace period in days before addons are deactivated.
     * NOTE: Must match grace period in license-handler.php (90 days).
     */
    const GRACE_PERIOD_DAYS = 90;

    /**
     * Cron hook name
     */
    const CRON_HOOK = 'explorexr_daily_license_check';

    /**
     * Main Instance
     */
    public static function instance() {
        if (is_null(self::$_instance)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    /**
     * Constructor
     */
    public function __construct() {
        // Schedule daily license check
        add_action('init', array($this, 'schedule_license_check'));

        // Hook into daily cron
        add_action(self::CRON_HOOK, array($this, 'check_license_expiration'));

        // NOTE: admin_notices for expiry are displayed by ExploreXR_License_Handler
        // ::maybe_show_license_expiry_notice() which reads live license data.
        // Registering display_expiration_notices() here caused duplicate banners
        // and was broken because it relied on stored flags that were incorrectly
        // set by the missing $days_until_expiration calculation. Do NOT re-add.

        // Hook into license activation to clear warnings
        add_action('explorexr_license_activated', array($this, 'clear_expiration_warnings'));

        // Deactivation cleanup
        register_deactivation_hook(EXPLOREXR_PREMIUM_PLUGIN_FILE, array($this, 'unschedule_license_check'));
    }

    /**
     * Schedule daily license check
     */
    public function schedule_license_check() {
        if (!wp_next_scheduled(self::CRON_HOOK)) {
            wp_schedule_event(time(), 'daily', self::CRON_HOOK);
        }
    }

    /**
     * Unschedule license check on plugin deactivation
     */
    public function unschedule_license_check() {
        $timestamp = wp_next_scheduled(self::CRON_HOOK);
        if ($timestamp) {
            wp_unschedule_event($timestamp, self::CRON_HOOK);
        }
    }

    /**
     * Check license expiration and handle grace period.
     *
     * Reads expiry from the central license data option and computes
     * the number of days until (or since) expiration so that stored
     * flags are set correctly for downstream consumers.
     */
    public function check_license_expiration() {
        // Read expiry from the central license data (explorexr_license_data['expires']).
        $license_data = get_option('explorexr_license_data', array());
        $expires      = isset($license_data['expires']) ? $license_data['expires'] : '';

        if (empty($expires)) {
            return; // No expiration date set (e.g., free tier or not yet activated).
        }

        $expiration_timestamp = strtotime($expires);
        if (!$expiration_timestamp) {
            return; // Un-parseable date string — bail cleanly.
        }

        $current_timestamp = time();

        // Compute signed days: positive = days remaining, negative = days past expiry.
        $days_until_expiration = (int) ceil(($expiration_timestamp - $current_timestamp) / DAY_IN_SECONDS);

        // Persist so that other UI components can read the pre-computed value.
        update_option('explorexr_license_days_until_expiration', $days_until_expiration);

        // Check if license has expired
        if ($days_until_expiration <= 0) {
            $this->handle_expired_license($days_until_expiration);
        } else {
            // Show warnings at specific intervals before expiration
            $this->set_expiration_warning_level($days_until_expiration);
        }

        // Log the check for debugging
        if (defined('WP_DEBUG') && WP_DEBUG) {
            // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional debug logging behind WP_DEBUG
            error_log(sprintf(
                'ExploreXR License Check: %d days until expiration',
                $days_until_expiration
            ));
        }
    }

    /**
     * Handle expired license (with grace period)
     */
    private function handle_expired_license($days_until_expiration) {
        $days_expired = abs($days_until_expiration);

        // Set expired flag
        update_option('explorexr_license_expired', true);
        update_option('explorexr_license_expired_days', $days_expired);

        // Check if grace period has passed
        if ($days_expired >= self::GRACE_PERIOD_DAYS) {
            $this->deactivate_addons();
            update_option('explorexr_license_grace_period_expired', true);
        } else {
            update_option('explorexr_license_grace_period_expired', false);
        }
    }

    /**
     * Set warning level based on days until expiration
     */
    private function set_expiration_warning_level($days_until_expiration) {
        // Clear expired flags if license is still valid (handles renewal scenario)
        delete_option('explorexr_license_expired');
        delete_option('explorexr_license_expired_days');
        delete_option('explorexr_license_grace_period_expired');

        // Set warning level for display
        if ($days_until_expiration <= 1) {
            update_option('explorexr_license_warning_level', 'critical');
        } elseif ($days_until_expiration <= 7) {
            update_option('explorexr_license_warning_level', 'high');
        } elseif ($days_until_expiration <= 14) {
            update_option('explorexr_license_warning_level', 'medium');
        } elseif ($days_until_expiration <= 30) {
            update_option('explorexr_license_warning_level', 'low');
        } else {
            delete_option('explorexr_license_warning_level');
        }
    }

    /**
     * Deactivate all licensed ExploreXR add-ons (debug is excluded — it needs no license).
     */
    private function deactivate_addons() {
        if (!function_exists('deactivate_plugins')) {
            require_once ABSPATH . 'wp-admin/includes/plugin.php';
        }

        // Only licensed add-ons are deactivated; debug add-on is license-free.
        $addon_paths = array(
            'explorexr-animation-addon/explorexr-animation-addon.php',
            'explorexr-annotations-addon/explorexr-annotations-addon.php',
            'explorexr-ar-addon/explorexr-ar-addon.php',
            'explorexr-camera-addon/explorexr-camera-addon.php',
            'explorexr-draggable-addon/explorexr-draggable-addon.php',
            'explorexr-loading-addon/explorexr-loading-addon.php',
            'explorexr-materials-addon/explorexr-materials-addon.php',
            'explorexr-morphing-addon/explorexr-morphing-addon.php',
            'explorexr-mouse3d-addon/explorexr-mouse3d-addon.php',
            'explorexr-environment-addon/explorexr-environment-addon.php',
            'explorexr-post-processing-addon/explorexr-post-processing-addon.php',
            'explorexr-woocommerce-addon/explorexr-woocommerce-addon.php',
        );

        // Filter to only active addons
        $active_addons = array_filter($addon_paths, 'is_plugin_active');

        if (!empty($active_addons)) {
            deactivate_plugins($active_addons, true); // Silent deactivation

            if (defined('WP_DEBUG') && WP_DEBUG) {
                // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Intentional debug logging behind WP_DEBUG
                error_log('ExploreXR: Deactivated addons due to expired license after grace period');
            }

            update_option('explorexr_deactivated_addons', $active_addons);
        }
    }

    /**
     * Clear expiration warnings when license is activated/renewed
     */
    public function clear_expiration_warnings() {
        delete_option('explorexr_license_warning_level');
        delete_option('explorexr_license_expired');
        delete_option('explorexr_license_expired_days');
        delete_option('explorexr_license_grace_period_expired');
        delete_option('explorexr_license_days_until_expiration');
        delete_option('explorexr_deactivated_addons');
    }

    /**
     * Get days until expiration (live calculation from central license data).
     *
     * @return int Positive = days remaining; negative = days past expiry; 999 = no expiry set.
     */
    public function get_days_until_expiration() {
        $license_data = get_option('explorexr_license_data', array());
        $expires      = isset($license_data['expires']) ? $license_data['expires'] : '';

        if (empty($expires)) {
            return 999; // Free tier or no expiry set.
        }

        $expiration_timestamp = strtotime($expires);
        if (!$expiration_timestamp) {
            return 999;
        }

        return (int) ceil(($expiration_timestamp - time()) / DAY_IN_SECONDS);
    }

    /**
     * Check if license is expired (reads stored flag set by cron check)
     */
    public function is_license_expired() {
        return (bool) get_option('explorexr_license_expired', false);
    }

    /**
     * Check if grace period has expired (reads stored flag set by cron check)
     */
    public function is_grace_period_expired() {
        return (bool) get_option('explorexr_license_grace_period_expired', false);
    }
}

// Initialize the handler
function explorexr_premium_license_expiration_handler() {
    return ExploreXR_License_Expiration_Handler::instance();
}

// Initialize on plugins_loaded
add_action('plugins_loaded', 'explorexr_premium_license_expiration_handler', 20);
