<?php
/**
 * Maintenance GENIUS - License Manager
 * Integration with WHMCS Licensing Addon
 * Version 2.9.124 — 1001Web Build
 */

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

class MG_License {

    /**
     * WHMCS Licensing API URL
     */
    const WHMCS_URL = 'https://client.1001web.ca/modules/servers/licensing/verify.php';

    /**
     * Local verification secret key (must match WHMCS)
     */
    const SECRET_KEY = 'mg_1001web_2026';

    /**
     * SHA-256 hash of the 1001Web master key
     */
    const MASTER_KEY_HASH = 'eaa33518ef4d4032b0ba5c1dc78dd955749da5334311ad5fe9af9b58829af361';

    /**
     * Cache duration in seconds (24 hours)
     */
    const CACHE_DURATION = 86400;

    /**
     * Check if key is the 1001Web master key
     * @param string $key
     * @return bool
     */
    public static function is_master_key($key = '') {
        if (empty($key)) {
            $key = self::get_key();
        }
        return hash('sha256', strtoupper(trim($key))) === self::MASTER_KEY_HASH;
    }

    /**
     * Check if the active license is a master key
     * @return bool
     */
    public static function is_master_active() {
        $info = self::get_info();
        return isset($info['type']) && $info['type'] === 'PRO (1001Web)';
    }

    /**
     * Check if license is valid
     * 
     * @return bool
     */
    public static function is_valid() {
        return (bool) get_option('mg_license_valid', false);
    }

    /**
     * Get the license key
     * 
     * @return string
     */
    public static function get_key() {
        return get_option('mg_license_key', '');
    }

    /**
     * Get license info
     * 
     * @return array
     */
    public static function get_info() {
        return get_option('mg_license_info', [
            'status' => 'inactive',
            'type' => '',
            'expires' => '',
            'domain' => '',
        ]);
    }

    /**
     * Activate a license
     * 
     * @param string $license_key
     * @return array ['success' => bool, 'message' => string]
     */
    public static function activate($license_key) {
        $license_key = strtoupper(trim($license_key));

        if (!self::validate_format($license_key)) {
            return [
                'success' => false,
                'message' => __('Invalid key format. Expected format: MG-XXXX-XXXX-XXXX-XXXX', 'maintenance-genius')
            ];
        }

        if (self::is_master_key($license_key)) {
            update_option('mg_license_key', $license_key);
            update_option('mg_license_valid', true);
            update_option('mg_license_activated', current_time('mysql'));
            update_option('mg_license_info', [
                'status'  => 'active',
                'type'    => 'PRO (1001Web)',
                'domain'  => 'All Domains (1001Web)',
                'expires' => 'Illimitée (Master 1001Web)',
            ]);
            update_option('mg_license_last_check', time());

            return [
                'success' => true,
                'message' => __('License activated successfully!', 'maintenance-genius')
            ];
        }

        $result = self::verify_with_whmcs($license_key, 'activate');

        if ($result['success']) {
            update_option('mg_license_key', $license_key);
            update_option('mg_license_valid', true);
            update_option('mg_license_activated', current_time('mysql'));
            update_option('mg_license_info', $result['info']);
            update_option('mg_license_last_check', time());

            return [
                'success' => true,
                'message' => __('License activated successfully!', 'maintenance-genius')
            ];
        }

        return $result;
    }

    /**
     * Deactivate the license
     * 
     * @return array
     */
    public static function deactivate() {
        $license_key = self::get_key();

        if (!empty($license_key)) {
            self::verify_with_whmcs($license_key, 'deactivate');
        }

        delete_option('mg_license_key');
        delete_option('mg_license_valid');
        delete_option('mg_license_activated');
        delete_option('mg_license_info');
        delete_option('mg_license_last_check');

        return [
            'success' => true,
            'message' => __('License deactivated', 'maintenance-genius')
        ];
    }

    /**
     * Periodic license verification (cron)
     */
    public static function periodic_check() {
        $license_key = self::get_key();
        
        if (empty($license_key)) {
            return;
        }

        if (self::is_master_key($license_key)) {
            update_option('mg_license_last_check', time());
            return;
        }

        $last_check = get_option('mg_license_last_check', 0);
        
        if (time() - $last_check < self::CACHE_DURATION) {
            return;
        }

        $result = self::verify_with_whmcs($license_key, 'check');

        if ($result['success']) {
            update_option('mg_license_valid', true);
            update_option('mg_license_info', $result['info']);
        } else {
            update_option('mg_license_valid', false);
        }

        update_option('mg_license_last_check', time());
    }

    /**
     * Validate key format
     * Accepts: MG-XXXXXXXXXXXXXXXX (16 chars after MG-)
     * or: MG-XXXX-XXXX-XXXX-XXXX (with dashes)
     * 
     * @param string $key
     * @return bool
     */
    private static function validate_format($key) {
        if (preg_match('/^MG-[A-Z0-9]{16}$/i', $key)) {
            return true;
        }
        if (preg_match('/^MG-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}-[A-Z0-9]{4}$/i', $key)) {
            return true;
        }
        return false;
    }

    /**
     * Verify the license with WHMCS
     * 
     * @param string $license_key
     * @param string $action (activate, check, deactivate)
     * @return array
     */
    private static function verify_with_whmcs($license_key, $action = 'check') {
        $domain = self::get_domain();
        $ip = self::get_server_ip();
        $dir = ABSPATH;

        $response = wp_remote_post(self::WHMCS_URL, [
            'timeout' => 30,
            'body' => [
                'licensekey' => $license_key,
                'domain' => $domain,
                'ip' => $ip,
                'dir' => $dir,
            ],
            'sslverify' => true,
        ]);

        if (is_wp_error($response)) {
            if (get_option('mg_license_valid', false)) {
                return [
                    'success' => true,
                    'message' => __('Cached verification', 'maintenance-genius'),
                    'info' => self::get_info()
                ];
            }

            return [
                'success' => false,
                'message' => __('License server connection error:', 'maintenance-genius') . ' ' . $response->get_error_message()
            ];
        }

        $body = wp_remote_retrieve_body($response);

        // unserialize() sur input externe = vulnérabilité PHP Object Injection (RCE potentiel).
        // Le serveur WHMCS retourne idéalement du JSON, mais on garde un fallback
        // parser whitelist pour les anciennes installations qui retournent du serialized.
        $data = self::parse_license_response($body);

        if ( ! is_array( $data ) || empty( $data ) ) {
            if (strpos($body, 'Active') !== false || strpos($body, 'Valid') !== false) {
                return [
                    'success' => true,
                    'message' => __('Valid license', 'maintenance-genius'),
                    'info' => [
                        'status' => 'active',
                        'type' => 'standard',
                        'domain' => $domain,
                        'expires' => '',
                    ]
                ];
            }

            return [
                'success' => false,
                'message' => __('Invalid response from license server', 'maintenance-genius')
            ];
        }

        $status = isset($data['status']) ? strtolower($data['status']) : '';

        if ($status === 'active' || $status === 'valid') {
            return [
                'success' => true,
                'message' => __('Valid license', 'maintenance-genius'),
                'info' => [
                    'status' => 'active',
                    'type' => isset($data['productname']) ? $data['productname'] : 'PRO',
                    'domain' => $domain,
                    'expires' => isset($data['nextduedate']) ? $data['nextduedate'] : '',
                    'registered' => isset($data['regdate']) ? $data['regdate'] : '',
                    'client' => isset($data['name']) ? $data['name'] : '',
                ]
            ];
        }

        $error_messages = [
            'expired' => __('License expired. Please renew.', 'maintenance-genius'),
            'suspended' => __('License suspended. Contact support.', 'maintenance-genius'),
            'invalid' => __('Invalid license key.', 'maintenance-genius'),
            'cancelled' => __('License cancelled.', 'maintenance-genius'),
            'pending' => __('License pending activation.', 'maintenance-genius'),
            'fraud' => __('License blocked for fraud.', 'maintenance-genius'),
        ];

        $message = isset($error_messages[$status]) 
            ? $error_messages[$status] 
            : (isset($data['message']) ? $data['message'] : __('Invalid or expired license', 'maintenance-genius'));

        return [
            'success' => false,
            'message' => $message
        ];
    }

    /**
     * Get the site domain
     * 
     * @return string
     */
    private static function get_domain() {
        $url = home_url();
        $parsed = wp_parse_url( $url );
        $domain = isset($parsed['host']) ? $parsed['host'] : '';
        
        $domain = preg_replace('/^www\./', '', $domain);
        
        return $domain;
    }

    /**
     * Get the server IP
     * 
     * @return string
     */
    private static function get_server_ip() {
        if (!empty($_SERVER['SERVER_ADDR'])) {
            return sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ?? '' ) );
        }
        
        if (!empty($_SERVER['LOCAL_ADDR'])) {
            return sanitize_text_field( wp_unslash( $_SERVER['LOCAL_ADDR'] ?? '' ) );
        }

        return gethostbyname(gethostname());
    }

    /**
     * v2.9.52 SECURITY (B1) — Parser sécurisé pour les réponses du serveur de licences.
     *
     * Remplace unserialize() qui est vulnérable à PHP Object Injection.
     * Tente d'abord JSON (format moderne recommandé).
     * Fallback : extraction whitelist des champs WHMCS connus depuis le serialized PHP,
     * sans appeler unserialize() (regex sur clés/valeurs string scalaires uniquement).
     *
     * @param string $body Réponse brute du serveur de licences.
     * @return array|null  Tableau associatif parsé, ou null si invalide.
     */
    private static function parse_license_response($body) {
        if ( empty( $body ) || ! is_string( $body ) ) {
            return null;
        }

        // 1. Format JSON (préféré, sécurisé nativement)
        $json = json_decode( $body, true );
        if ( is_array( $json ) ) {
            return $json;
        }

        // 2. Fallback : parser whitelist pour serialized PHP legacy
        // Champs autorisés du retour WHMCS Licensing Addon (string scalaires uniquement)
        $allowed_fields = [
            'status', 'productname', 'productid', 'regdate', 'nextduedate',
            'name', 'company', 'email', 'message', 'description',
        ];

        $result = [];
        foreach ( $allowed_fields as $field ) {
            // Pattern : s:LEN:"FIELD";s:LEN:"VALUE";
            $pattern = '/s:\d+:"' . preg_quote( $field, '/' ) . '";s:(\d+):"((?:[^"\\\\]|\\\\.)*)"/';
            if ( preg_match( $pattern, $body, $matches ) ) {
                $value = stripslashes( $matches[2] );
                $result[ $field ] = sanitize_text_field( $value );
            }
        }

        return ! empty( $result ) ? $result : null;
    }
}
