<?php
namespace Aegisify\Utils;

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

class License {

    const OPTION_KEY              = 'aegisify_license_key';
    const OPTION_EMAIL            = 'aegisify_license_email';
    const TRANSIENT_STATUS        = 'aegisify_license_status';
    const OPTION_FREE_OPTIN       = 'aegisify_free_reg_optin';
    const OPTION_FREE_STATUS      = 'aegisify_free_reg_status'; 
    const OPTION_LAST_DAILY_CHECK = 'aegisify_clm_last_daily_check';
    const OPTION_LAST_STATUS_CHECK = 'aegisify_clm_last_status_check';
    const OPTION_LAST_STATUS_ROW   = 'aegisify_clm_last_status_row';
    const OPTION_TRIAL_TOKEN        = 'aegisify_clm_trial_token';

    private function get_expiration_timestamp(string $expires) : int {
        $expires = trim($expires);
        if ($expires === '') {
            return 0;
        }

        $timestamp = strtotime($expires);
        return ($timestamp !== false) ? (int) $timestamp : 0;
    }

    private function is_status_expired(array $status_row) : bool {
        $expires_ts = $this->get_expiration_timestamp((string) ($status_row['expires'] ?? ''));
        if ($expires_ts <= 0) {
            return false;
        }

        return $expires_ts < time();
    }

    private function normalize_status_row(array $status_row) : array {
        if (empty($status_row) || !$this->is_status_expired($status_row)) {
            return $status_row;
        }

        $status_row['status'] = 'expired';
        $status_row['is_pro'] = 0;
        $status_row['expired'] = 1;

        return $status_row;
    }

    private function is_status_active(array $status_row) : bool {
        $status_row = $this->normalize_status_row($status_row);
        $lic_state = strtolower((string) ($status_row['status'] ?? ''));
        return !empty($status_row['is_pro']) || in_array($lic_state, array('active', 'valid', 'licensed'), true);
    }

    private function is_explicit_remote_deactivation(array $data) : bool {
        $status_values = array(
            $data['license_status'] ?? '',
            $data['status'] ?? '',
        );

        if (!empty($data['data']) && is_array($data['data'])) {
            $status_values[] = $data['data']['license_status'] ?? '';
            $status_values[] = $data['data']['status'] ?? '';
        }

        foreach ($status_values as $value) {
            $value = strtolower((string) $value);
            if (in_array($value, array('inactive', 'deactivated', 'deleted', 'not_found', 'unlinked', 'revoked', 'removed'), true)) {
                return true;
            }
        }

        return false;
    }

    private function should_preserve_active_status(array $old_status, array $data) : bool {
        if (!$this->is_status_active($old_status)) {
            return false;
        }

        if ($this->is_explicit_remote_deactivation($data)) {
            return false;
        }

        $success = !empty($data['success']);
        $status  = strtolower((string) ($data['license_status'] ?? $data['status'] ?? ''));

        // A failed or incomplete CLM refresh must not erase a previously active
        // license. Only an explicit server-side inactive/deactivated/revoked/etc.
        // status may switch PRO off.
        if (!$success) {
            return true;
        }

        if ($status === '' || $status === 'active' || $status === 'valid' || $status === 'licensed') {
            return false;
        }

        return true;
    }

    public function get_key() : string {
        return (string) get_option(self::OPTION_KEY, '');
    }

    public function set_key(string $key) : void {
        $key         = trim($key);
        $previous_key = $this->get_key();

        update_option(self::OPTION_KEY, $key, false);
        delete_transient(self::TRANSIENT_STATUS);

        // A durable last-known status belongs to the key that produced it.
        // If the key changes, clear that row so a failed/new activation cannot
        // accidentally display or reuse the old key's active license state.
        if ($previous_key !== $key) {
            delete_option(self::OPTION_LAST_STATUS_CHECK);
            delete_option(self::OPTION_LAST_STATUS_ROW);
        }
    }

    public function get_cached_status() : array {
        $s = get_transient(self::TRANSIENT_STATUS);

        // The transient is only the short-lived hot cache. The last verified row
        // is the durable local status snapshot used when that transient expires.
        // Without this fallback, the admin screen and suite consumers read an
        // empty status after six hours and falsely show the license as inactive.
        if (!is_array($s) || empty($s)) {
            $last_row = get_option(self::OPTION_LAST_STATUS_ROW, array());
            $s = is_array($last_row) ? $last_row : array();
        }

        $s = is_array($s) ? $this->normalize_status_row($s) : array();

        if (!empty($s) && !empty($s['expired'])) {
            set_transient(self::TRANSIENT_STATUS, $s, 6 * HOUR_IN_SECONDS);

            $last_row = get_option(self::OPTION_LAST_STATUS_ROW, array());
            if (is_array($last_row) && !empty($last_row)) {
                $last_row = $this->normalize_status_row($last_row);
                update_option(self::OPTION_LAST_STATUS_ROW, $last_row, false);
            }
        }

        return $s;
    }

    public function get_status() : array {
        return $this->get_cached_status();
    }

    public function status_refresh_due() : bool {
        $last_opt = (int) get_option(self::OPTION_LAST_STATUS_CHECK, 0);
        $last_row = get_option(self::OPTION_LAST_STATUS_ROW, array());
        $last_row_checked_at = (is_array($last_row) && !empty($last_row['checked_at']))
            ? (int) $last_row['checked_at']
            : 0;

        $last_check_at = max($last_opt, $last_row_checked_at);

        return $last_check_at <= 0 || (time() - $last_check_at) >= (4 * HOUR_IN_SECONDS);
    }

    public function is_pro_active(bool $auto_check = true, string $current_version = ''): bool {
        $st = $this->get_status();
        if ($auto_check && $current_version !== '' && (empty($st) || $this->status_refresh_due())) {
            $st = $this->normalize_status_row($this->check_now($current_version));
        }

        return $this->is_status_active($st);
    }

	private function is_manual_force_request(): bool {
		if ( ! is_admin() ) { return false; }
		if ( ! function_exists( 'current_user_can' ) || ! current_user_can( 'manage_options' ) ) { return false; }

		$has_force = false;

		if ( ! empty( $_POST['aegisify_activate_license'] ) ) { $has_force = true; }
		if ( ! empty( $_POST['aegisify_deactivate_license'] ) ) { $has_force = true; }

		$action = isset( $_REQUEST['action'] ) ? sanitize_key( (string) wp_unslash( $_REQUEST['action'] ) ) : '';

		$allowed_actions = array(
			'aegisify_license_activate',
			'aegisify_license_deactivate',
			'aegisify_activate_license',
			'aegisify_deactivate_license',
		);

		if ( $action && in_array( $action, $allowed_actions, true ) ) {
			$has_force = true;
		}

		if ( ! $has_force ) {
			return false;
		}

		$nonce = isset( $_REQUEST['_wpnonce'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['_wpnonce'] ) ) : '';
		if ( '' === $nonce ) {
			return false;
		}

		$expected_actions = array();

		if ( $action && in_array( $action, $allowed_actions, true ) ) {
			$expected_actions[] = $action;
		}

		if ( ! empty( $_POST['aegisify_activate_license'] ) ) {
			$expected_actions[] = 'aegisify_activate_license';
			$expected_actions[] = 'aegisify_license_activate';
		}
		if ( ! empty( $_POST['aegisify_deactivate_license'] ) ) {
			$expected_actions[] = 'aegisify_deactivate_license';
			$expected_actions[] = 'aegisify_license_deactivate';
		}

		$expected_actions[] = 'aegisify_license';
		$expected_actions[] = 'aegisify_license_action';

		foreach ( array_unique( $expected_actions ) as $expected_action ) {
			if ( wp_verify_nonce( $nonce, $expected_action ) ) {
				return true;
			}
		}

		return false;
	}


    private function clm_post(string $endpoint, array $payload, int $timeout = 20) : array {
        if (!$endpoint) {
            return array('success'=>false,'status'=>'no_endpoint','message'=>'CLM endpoint is not configured.');
        }

        $args = array(
            'timeout' => $timeout,
            'headers' => array('Content-Type' => 'application/json'),
            'body'    => wp_json_encode($payload),
        );

        $resp = wp_remote_post($endpoint, $args);
        if (is_wp_error($resp)) {
            return array('success'=>false,'status'=>'wp_error','message'=>$resp->get_error_message());
        }

        $code = (int) wp_remote_retrieve_response_code($resp);
        $raw  = (string) wp_remote_retrieve_body($resp);

        if ($code < 200 || $code >= 300) {
            return array('success'=>false,'status'=>'http','message'=>'CLM HTTP '.$code,'http_code'=>$code,'raw'=>$raw);
        }

        $data = json_decode($raw, true);
        if (!is_array($data)) {
            return array('success'=>false,'status'=>'bad_json','message'=>'Invalid JSON from CLM','http_code'=>$code,'raw'=>$raw);
        }

        if (!isset($data['success'])) {
            $data['success'] = true;
        }

        $data['http_code'] = $code;
        return $data;
    }

	public function check_now(string $current_version, bool $force = false) : array {
		static $request_cache = null;
		static $request_cache_at = 0;
		if (!$force && is_array($request_cache) && $request_cache_at > 0 && (time() - $request_cache_at) < 15) {
			return $request_cache;
		}

		$min_interval = 4 * HOUR_IN_SECONDS;

		$cached    = $this->get_cached_status();
		$last_opt  = (int) get_option(self::OPTION_LAST_STATUS_CHECK, 0);
		$last_row  = get_option(self::OPTION_LAST_STATUS_ROW, array());
		$old_status = (is_array($cached) && !empty($cached)) ? $cached : (is_array($last_row) ? $last_row : array());
		$last_cached_at = (is_array($cached) && !empty($cached['checked_at'])) ? (int) $cached['checked_at'] : 0;
		$last_check_at = max($last_opt, $last_cached_at);
		$force_allowed = ($force && $this->is_manual_force_request());

		if (!$force_allowed && $last_check_at > 0 && (time() - $last_check_at) < $min_interval) {

			if (is_array($cached) && !empty($cached)) {
				$request_cache = $cached;
				$request_cache_at = time();
				return $cached;
			}
			if (is_array($last_row) && !empty($last_row)) {
				$request_cache = $last_row;
				$request_cache_at = time();
				return $last_row;
			}

			$throttled = array(
				'checked_at' => $last_check_at,
				'success'    => false,
				'status'     => 'throttled',
				'plan'       => '',
				'expires'    => '',
				'is_pro'     => 0,
				'raw'        => array('message' => 'CLM status check throttled (4-hour interval).'),
			);

			$request_cache = $throttled;
			$request_cache_at = time();
			return $throttled;
		}

		$site_url = home_url();
		$domain   = wp_parse_url($site_url, PHP_URL_HOST);


        $payload = array(
            'slug'           => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'product'        => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'version'        => (string) $current_version,
            'domain'         => (string) $domain,
            'site_url'       => (string) $site_url,
            'license_key'    => (string) $this->get_key(),
            'email'          => (string) get_option(self::OPTION_EMAIL, get_option('admin_email', '')),
            'wp_version'     => (string) get_bloginfo('version'),
            'php_version'    => (string) PHP_VERSION,
            'plugin_basename'=> defined('AEGISIFY_BASENAME') ? (string) AEGISIFY_BASENAME : '',
            'client_trial_token' => (string) get_option(self::OPTION_TRIAL_TOKEN, ''),
            'client_expires_at'  => (string) (is_array($last_row) && !empty($last_row['expires']) ? $last_row['expires'] : (is_array($cached) && !empty($cached['expires']) ? $cached['expires'] : '')),

        );

        $endpoint = defined('AEGISIFY_CLM_STATUS_ENDPOINT') ? AEGISIFY_CLM_STATUS_ENDPOINT : '';
        if (!$endpoint && defined('AEGISIFY_CLM_UPDATE_ENDPOINT')) {
            $endpoint = AEGISIFY_CLM_UPDATE_ENDPOINT;
        }

        $data = $this->clm_post($endpoint, $payload, 20);

        if (is_array($data) && isset($data['status']) && is_array($data['status'])) {
            $nested = $data['status'];
            $data['_status_raw'] = $nested;

            foreach ($nested as $k => $v) {
                if (!array_key_exists($k, $data)) {
                    $data[$k] = $v;
                } else {
                    if (in_array($k, array('status','plan','expires','expires_at','is_pro','success','license_status','max_sites','domains','this_domain','bound','is_active','is_paid'), true)) {
                        $data[$k] = $v;
                    }
                }
            }
        }

        $is_pro = false;
        if (is_array($data)) {
            $candidates_true = array(
                $data['is_pro'] ?? null,
                $data['pro'] ?? null,
                $data['license_active'] ?? null,
                $data['active'] ?? null,
            );
            foreach ($candidates_true as $v) {
                if ($v === true || $v === 1 || $v === '1' || $v === 'true') { $is_pro = true; break; }
            }

            if (!$is_pro) {
                $status = strtolower((string)($data['license_status'] ?? $data['status'] ?? ''));
                $plan   = strtolower((string)($data['plan'] ?? $data['tier'] ?? $data['license_type'] ?? ''));
                if (in_array($status, array('active','valid','licensed'), true) && in_array($plan, array('pro','premium','paid','bundle','suite'), true)) {
                    $is_pro = true;
                }
                if (in_array($plan, array('pro','premium','paid','bundle','suite'), true) && $status === '') {
                    $is_pro = true;
                }
            }
        }

        $returned_domain = '';
        if (is_array($data)) {
            $returned_domain = (string)($data['domain'] ?? $data['licensed_domain'] ?? $data['site_domain'] ?? '');
            if ($returned_domain === '' && !empty($data['data']) && is_array($data['data'])) {
                $returned_domain = (string)($data['data']['domain'] ?? $data['data']['licensed_domain'] ?? $data['data']['site_domain'] ?? '');
            }
        }

        $current_domain = (string) $domain;
        if ($returned_domain !== '' && $current_domain !== '' && strcasecmp($returned_domain, $current_domain) !== 0) {
            $is_pro = false;
            if (is_array($data)) {
                $data['success'] = false;
                $data['license_status'] = 'domain_mismatch';
            }
        }
		
        $status_row = array(
            'checked_at' => time(),
            'success'    => !empty($data['success']),
            'status'     => (string)($data['license_status'] ?? $data['status'] ?? ''),
            'plan'       => (string)($data['plan'] ?? $data['tier'] ?? ''),
            'expires'    => (string)($data['expires'] ?? $data['expires_at'] ?? $data['expiration'] ?? ''),
            'is_pro'     => $is_pro ? 1 : 0,
            'raw'        => $data,
        );

        if ($this->should_preserve_active_status($old_status, is_array($data) ? $data : array())) {
            $status_row['success'] = !empty($old_status['success']);
            $status_row['status']  = (string) ($old_status['status'] ?? 'active');
            $status_row['plan']    = (string) ($old_status['plan'] ?? $status_row['plan']);
            $status_row['expires'] = (string) ($old_status['expires'] ?? $status_row['expires']);
            $status_row['is_pro']  = !empty($old_status['is_pro']) ? 1 : 0;
            $status_row['preserved_active'] = 1;
            $status_row['refresh_preserved_reason'] = empty($data['success'])
                ? 'remote_refresh_failed'
                : 'non_authoritative_remote_status';
        }

        $status_row = $this->normalize_status_row($status_row);

        set_transient(self::TRANSIENT_STATUS, $status_row, 6 * HOUR_IN_SECONDS);

        // Notify other Aegisify products that the suite license status changed.
        // This allows products to clear stale caches immediately after activate/deactivate.
        if (function_exists('do_action')) {
            do_action('aegisify_license_changed', $status_row, $old_status);
        }


        update_option(self::OPTION_LAST_STATUS_CHECK, (int) ($status_row['checked_at'] ?? time()), false);
        update_option(self::OPTION_LAST_STATUS_ROW, $status_row, false);
        update_option(self::OPTION_LAST_DAILY_CHECK, time(), false);

        if (function_exists('aegisify_update_log')) {
            aegisify_update_log('CLM status checked.', array(
                'http_code' => $data['http_code'] ?? null,
                'success'   => !empty($data['success']),
                'status'    => $status_row,
            ), !empty($data['success']) ? 'INFO' : 'ERROR');
        }
		
		$request_cache = $status_row;
		$request_cache_at = time();
        return $status_row;
    }

    public function activate_now(string $current_version) : array {
        $site_url = home_url();
        $domain   = wp_parse_url($site_url, PHP_URL_HOST);

        $payload = array(
            'slug'        => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'product'     => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'version'     => (string) $current_version,
            'domain'      => (string) $domain,
            'site_url'    => (string) $site_url,
            'license_key' => (string) $this->get_key(),
            'email'       => (string) get_option(self::OPTION_EMAIL, get_option('admin_email', '')),
        );

        $email = (string) ($payload['email'] ?? '');
        $key   = (string) ($payload['license_key'] ?? '');
        if ($key === '' || $email === '' || !is_email($email)) {
            return array('success'=>false,'status'=>'invalid_input','message'=>'License key and a valid email are required.');
        }

        $data = $this->clm_post(defined('AEGISIFY_CLM_ACTIVATE_ENDPOINT') ? AEGISIFY_CLM_ACTIVATE_ENDPOINT : '', $payload, 20);
        if (!empty($data['success'])) {
            $active_status = '';
            $active_plan   = '';
            $active_exp    = '';

            if (!empty($data['data']) && is_array($data['data'])) {
                $active_status = (string) ($data['data']['status'] ?? '');
                $active_plan   = (string) ($data['data']['plan'] ?? '');
                $active_exp    = (string) ($data['data']['expires_at'] ?? '');
                $active_is_pro = !empty($data['data']['is_pro']) || (!empty($data['data']['is_pro']) && (int)$data['data']['is_pro'] === 1);
            } else {
                $active_status = (string) ($data['status'] ?? '');
                $active_plan   = (string) ($data['plan'] ?? '');
                $active_exp    = (string) ($data['expires_at'] ?? '');
                $active_is_pro = !empty($data['is_pro']);
            }

            $row = array(
                'checked_at' => time(),
                'success'    => true,
                'status'     => $active_status !== '' ? $active_status : 'active',
                'plan'       => $active_plan,
                'expires'    => $active_exp,
                'is_pro'     => !empty($active_is_pro) ? 1 : 1, // activation implies pro for suite
                'raw'        => $data,
            );

            $row = $this->normalize_status_row($row);

            set_transient(self::TRANSIENT_STATUS, $row, 6 * HOUR_IN_SECONDS);
            update_option(self::OPTION_LAST_STATUS_CHECK, (int) $row['checked_at'], false);
            update_option(self::OPTION_LAST_STATUS_ROW, $row, false);

            // A successful manual activation replaces any prior trial context.
            // Keeping the old signed trial token would make later status checks present
            // stale trial evidence against a different paid license.
            delete_option(self::OPTION_TRIAL_TOKEN);
        }

        if (function_exists('aegisify_update_log')) {
            aegisify_update_log('CLM activate response.', array(
                'http_code' => $data['http_code'] ?? null,
                'success'   => !empty($data['success']),
                'data'      => $data,
            ), !empty($data['success']) ? 'INFO' : 'ERROR');
        }

        $this->check_now($current_version, true);
        $st = $this->get_cached_status();
        $active_after = $this->is_status_active($st);
        if (!$active_after) {
            delete_transient(self::TRANSIENT_STATUS);
            $data['success'] = false;
            $data['status']  = 'email_or_license_mismatch';
            $data['message'] = $data['message'] ?? 'License activation failed: email and license key must match.';
        }

        return $data;
    }

    public function deactivate_now(string $current_version) : array {
        $site_url = home_url();
        $domain   = wp_parse_url($site_url, PHP_URL_HOST);

        $payload = array(
            'slug'        => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'product'     => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'version'     => (string) $current_version,
            'domain'      => (string) $domain,
            'site_url'    => (string) $site_url,
            'license_key' => (string) $this->get_key(),
            'email'       => (string) get_option(self::OPTION_EMAIL, get_option('admin_email', '')),
        );

        $data = $this->clm_post(defined('AEGISIFY_CLM_DEACTIVATE_ENDPOINT') ? AEGISIFY_CLM_DEACTIVATE_ENDPOINT : '', $payload, 20);

        if (function_exists('aegisify_update_log')) {
            aegisify_update_log('CLM deactivate response.', array(
                'http_code' => $data['http_code'] ?? null,
                'success'   => !empty($data['success']),
                'data'      => $data,
            ), !empty($data['success']) ? 'INFO' : 'ERROR');
        }

        if (!empty($data['success'])) {
            $row = array(
                'checked_at' => time(),
                'success'    => true,
                'status'     => 'inactive',
                'plan'       => '',
                'expires'    => '',
                'is_pro'     => 0,
                'raw'        => $data,
            );

            set_transient(self::TRANSIENT_STATUS, $row, 6 * HOUR_IN_SECONDS);
            update_option(self::OPTION_LAST_STATUS_CHECK, (int) $row['checked_at'], false);
            update_option(self::OPTION_LAST_STATUS_ROW, $row, false);
            update_option(self::OPTION_LAST_DAILY_CHECK, time(), false);
        } else {
            delete_transient(self::TRANSIENT_STATUS);
            $this->check_now($current_version, true);
        }

        return $data;
    }


    public function start_trial_now(string $current_version) : array {
        $site_url = home_url();
        $domain   = wp_parse_url($site_url, PHP_URL_HOST);

        $email = (string) get_option(self::OPTION_EMAIL, get_option('admin_email', ''));
        if ($email === '' || !is_email($email)) {
            $email = (string) get_option('admin_email', '');
        }

        // Collect minimal admin details (requested: admin details + domain).
        $admin_user = array();
        if (function_exists('wp_get_current_user')) {
            $u = wp_get_current_user();
            if ($u && !empty($u->ID)) {
                $admin_user = array(
                    'id'           => (int) $u->ID,
                    'user_login'   => (string) $u->user_login,
                    'display_name' => (string) $u->display_name,
                    'user_email'   => (string) $u->user_email,
                );
            }
        }

        $payload = array(
            'slug'        => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'product'     => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'version'     => (string) $current_version,
            'domain'      => (string) $domain,
            'site_url'    => (string) $site_url,
            'email'       => (string) $email,
            'admin_user'  => $admin_user,
            'wp_version'  => (string) get_bloginfo('version'),
            'php_version' => (string) PHP_VERSION,
        );

        $endpoint = defined('AEGISIFY_CLM_TRIAL_ENDPOINT') ? AEGISIFY_CLM_TRIAL_ENDPOINT : '';
        if (!$endpoint && defined('AEGISIFY_CLM_STATUS_ENDPOINT')) {
            $endpoint = str_replace('/status', '/trial', (string) AEGISIFY_CLM_STATUS_ENDPOINT);
        }

        $data = $this->clm_post($endpoint, $payload, 20);

        if (!empty($data['success'])) {
            $trial_key = '';
            if (!empty($data['license_key'])) {
                $trial_key = (string) $data['license_key'];
            } elseif (!empty($data['data']) && is_array($data['data']) && !empty($data['data']['license_key'])) {
                $trial_key = (string) $data['data']['license_key'];
            }

            if ($trial_key !== '') {
                $this->set_key($trial_key);
                update_option(self::OPTION_EMAIL, $email, false);

                // Store tamper-evident trial token (server-signed) if provided.
                if (!empty($data['trial_token'])) {
                    update_option(self::OPTION_TRIAL_TOKEN, (string) $data['trial_token'], false);
                } elseif (!empty($data['data']) && is_array($data['data']) && !empty($data['data']['trial_token'])) {
                    update_option(self::OPTION_TRIAL_TOKEN, (string) $data['data']['trial_token'], false);
                }


                // Force refresh so PRO is immediately enabled after trial issuance.
                $this->check_now($current_version, true);
                return $data;
            }

            $data['success'] = false;
            $data['status']  = 'missing_license_key';
            $data['message'] = $data['message'] ?? 'Trial response missing license_key.';
            return $data;
        }

        return is_array($data) ? $data : array('success'=>false,'status'=>'trial_failed','message'=>'Trial request failed.');
    }

    public function maybe_daily_check(string $current_version) : void {
        $last = (int) get_option(self::OPTION_LAST_DAILY_CHECK, 0);
        if ($last > 0 && (time() - $last) < DAY_IN_SECONDS) {
            return;
        }

        $this->check_now($current_version);

        $this->maybe_send_free_register($current_version);
    }
	
    public function maybe_send_free_register(string $current_version) : void {
        $optin = (int) get_option(self::OPTION_FREE_OPTIN, 0);
        if ($optin !== 1) {
            return;
        }

        $sent = get_transient('aegisify_clm_free_reg_sent');
        if ($sent) {
            return;
        }

        $site_url = home_url();
        $domain   = wp_parse_url($site_url, PHP_URL_HOST);

        $payload = array(
            'slug'      => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'product'   => defined('AEGISIFY_SLUG') ? AEGISIFY_SLUG : 'aegisify',
            'version'   => (string) $current_version,
            'domain'    => (string) $domain,
            'site_url'  => (string) $site_url,
            'admin_email' => (string) get_option('admin_email', ''),
        );

        $endpoint = defined('AEGISIFY_CLM_FREE_REGISTER_ENDPOINT') ? AEGISIFY_CLM_FREE_REGISTER_ENDPOINT : '';
        $data = $this->clm_post($endpoint, $payload, 20);

        if (!empty($data['success'])) {
            update_option(self::OPTION_FREE_STATUS, 'registered', false);
            set_transient('aegisify_clm_free_reg_sent', 1, DAY_IN_SECONDS);

            // Auto-issue/store the FREE license key returned by CLM (no manual entry).
            $existing_key = (string) $this->get_key();
            if ($existing_key === '' && !empty($data['license_key'])) {
                $this->set_key((string) $data['license_key']);
                update_option(self::OPTION_EMAIL, (string) get_option('admin_email', ''), false);
            }
        } else {
            update_option(self::OPTION_FREE_STATUS, 'error', false);
        }

        if (function_exists('aegisify_update_log')) {
            aegisify_update_log('CLM free register response.', array('data'=>$data), !empty($data['success']) ? 'INFO' : 'ERROR');
        }
    }
}
