<?php
/**
 * Optional external Remote Support Diagnostics service.
 *
 * Validates signed, time-limited support tokens and exposes only the diagnostic
 * scopes explicitly authorized by the site administrator. The external support
 * service may require a separate paid support entitlement.
 *
 * This file does not manage product licenses, resolve commercial plans, install
 * updates, or unlock Advanced/Premium functionality.
 */

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

if (!function_exists('custausu_support_diagnostics_now_utc')) {
  function custausu_support_diagnostics_now_utc(): string {
    return gmdate('Y-m-d H:i:s');
  }
}

if (!function_exists('custausu_support_diagnostics_to_utc_string')) {
  function custausu_support_diagnostics_to_utc_string(int $ts): string {
    return gmdate('Y-m-d H:i:s', $ts);
  }
}

if (!function_exists('custausu_support_diagnostics_parse_utc_ts')) {
  function custausu_support_diagnostics_parse_utc_ts(?string $value): int {
    $value = is_string($value) ? trim($value) : '';
    if ($value === '') return 0;

    $ts = strtotime($value . ' UTC');
    return is_int($ts) && $ts > 0 ? $ts : 0;
  }
}

if (!function_exists('custausu_support_diagnostics_sanitize_utc_datetime')) {
  function custausu_support_diagnostics_sanitize_utc_datetime($value): string {
    $value = is_string($value) ? trim($value) : '';
    if ($value === '') return '';

    $ts = custausu_support_diagnostics_parse_utc_ts($value);
    if ($ts <= 0) return '';

    return custausu_support_diagnostics_to_utc_string($ts);
  }
}

if (!function_exists('custausu_support_diagnostics_sanitize_hash')) {
  function custausu_support_diagnostics_sanitize_hash($value): string {
    $value = strtolower(trim((string)$value));
    return preg_match('/^[a-f0-9]{64}$/', $value) ? $value : '';
  }
}

if (!function_exists('custausu_support_diagnostics_sanitize_status')) {
  function custausu_support_diagnostics_sanitize_status($status, array $allowed, string $fallback = 'none'): string {
    $status = sanitize_key((string)$status);
    return in_array($status, $allowed, true) ? $status : $fallback;
  }
}

if (!function_exists('custausu_support_diagnostics_string')) {
  function custausu_support_diagnostics_string($value, int $max = 2000): string {
    $value = is_scalar($value) ? (string)$value : '';
    $value = trim(wp_strip_all_tags($value));
    if ($max > 0 && strlen($value) > $max) {
      $value = substr($value, 0, $max);
    }
    return $value;
  }
}

if (!function_exists('custausu_support_diagnostics_is_dev_environment')) {
  function custausu_support_diagnostics_is_dev_environment(): bool {
    $env = function_exists('wp_get_environment_type') ? (string) wp_get_environment_type() : 'production';
    $env = sanitize_key($env);

    if (in_array($env, ['local', 'development', 'staging'], true)) {
      return true;
    }

    $host = strtolower((string) wp_parse_url(home_url('/'), PHP_URL_HOST));
    if ($host === '') return false;

    if (in_array($host, ['localhost', '127.0.0.1', '::1'], true)) {
      return true;
    }

  foreach (['.local', '.test', '.invalid'] as $suffix) {
    if (substr($host, -strlen($suffix)) === $suffix) {
      return true;
    }
  }

    return false;
  }
}

if (!function_exists('custausu_support_diagnostics_base64url_decode')) {
  function custausu_support_diagnostics_base64url_decode(string $data) {
    $data = trim($data);
    if ($data === '') return false;

    $remainder = strlen($data) % 4;
    if ($remainder > 0) {
      $data .= str_repeat('=', 4 - $remainder);
    }

    return base64_decode(strtr($data, '-_', '+/'), true);
  }
}

if (!function_exists('custausu_support_diagnostics_site_fingerprint')) {
  function custausu_support_diagnostics_site_fingerprint(): string {
    $url = home_url('/');
    $parts = wp_parse_url($url);

    $scheme = strtolower((string)($parts['scheme'] ?? 'https'));
    $host   = strtolower((string)($parts['host'] ?? ''));
    $port   = isset($parts['port']) ? (int)$parts['port'] : 0;
    $path   = '/' . trim((string)($parts['path'] ?? ''), '/');

    if ($path === '//') $path = '/';

    $is_default_port = ($scheme === 'http' && $port === 80) || ($scheme === 'https' && $port === 443);
    $port_part = ($port > 0 && !$is_default_port) ? ':' . $port : '';

    $fp = $scheme . '://' . $host . $port_part . $path;
    return untrailingslashit($fp);
  }
}

if (!function_exists('custausu_support_diagnostics_site_hash')) {
  function custausu_support_diagnostics_site_hash(): string {
    return hash('sha256', custausu_support_diagnostics_site_fingerprint());
  }
}

if (!function_exists('custausu_support_diagnostics_host_fingerprint')) {
  function custausu_support_diagnostics_host_fingerprint(): string {
    $parts = wp_parse_url(home_url('/'));
    $host  = strtolower((string)($parts['host'] ?? ''));
    $port  = isset($parts['port']) ? (int)$parts['port'] : 0;

    if ($host === '') return '';

    $scheme = strtolower((string)($parts['scheme'] ?? 'https'));
    $is_default_port = ($scheme === 'http' && $port === 80) || ($scheme === 'https' && $port === 443);

    return ($port > 0 && !$is_default_port) ? ($host . ':' . $port) : $host;
  }
}

if (!function_exists('custausu_support_diagnostics_host_hash')) {
  function custausu_support_diagnostics_host_hash(): string {
    $fp = custausu_support_diagnostics_host_fingerprint();
    return $fp === '' ? '' : hash('sha256', $fp);
  }
}

// CAS Remote Support Diagnostics
// -----------------------------------------------------------------------------
// This is NOT a plan unlock mechanism.
// It never changes effective_plan and never grants Premium features.
// It only validates a time-limited signed support token that other admin tools
// may use to expose limited diagnostics for support purposes.

if (!function_exists('custausu_support_diagnostics_option_name')) {
  function custausu_support_diagnostics_option_name(): string {
    return 'custausu_support_diagnostics_state';
  }
}

if (!function_exists('custausu_support_diagnostics_get_default_state')) {
  function custausu_support_diagnostics_get_default_state(): array {
    return [
      'schema_version' => 1,
      'status'         => 'none',
      'token'          => '',
      'issued_at'      => '',
      'expires_at'     => '',
      'scope'          => '',
      'site_hash'      => '',
      'label'          => '',
      'case_id'        => '',
      'jti'            => '',
      'jti_hash'       => '',
      'revocation_url' => '',
      'revocation_checked_at' => '',
      'revocation_status'     => '',
      'capabilities'   => [],
      'checked_at'     => '',
      'reason'         => '',
      'viewer_policy'             => 'support_session',
      'activated_by_user_id'       => 0,
      'activated_by_session_hash'  => '',
      'activated_at_utc'           => '',      
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_get_public_key')) {
  function custausu_support_diagnostics_get_public_key(): string {
    $key = '';

    if (defined('CUSTAUSU_SUPPORT_DIAGNOSTICS_PUBLIC_KEY')) {
      $public_key = constant('CUSTAUSU_SUPPORT_DIAGNOSTICS_PUBLIC_KEY');

      if (is_string($public_key)) {
        $key = trim($public_key);
      }
    }

    $key = apply_filters('custausu_support_diagnostics_public_key', $key);
    $key = is_string($key) ? trim($key) : '';

    if ($key === '') {
      return '';
    }

    return strpos($key, 'BEGIN PUBLIC KEY') !== false ? $key : '';
  }
}

if (!function_exists('custausu_support_diagnostics_capabilities_catalog')) {
  function custausu_support_diagnostics_capabilities_catalog(): array {
    $capabilities = [
      'health_check',
      'package_context_read',
      'rest_connectivity',
      'settings_snapshot',
      'logs_read',
      'plugin_inventory',
      'diagnostic_export',
    ];

    $capabilities = apply_filters(
      'custausu_support_diagnostics_capabilities_catalog',
      $capabilities
    );

    $out = [];

    foreach ((array)$capabilities as $capability) {
      $capability = sanitize_key((string)$capability);

      if ($capability !== '') {
        $out[] = $capability;
      }
    }

    return array_values(array_unique($out));
  }
}

if (!function_exists('custausu_support_diagnostics_normalize_capabilities')) {
  function custausu_support_diagnostics_normalize_capabilities($value): array {
    $allowed = custausu_support_diagnostics_capabilities_catalog();

    if (is_string($value)) {
      $value = preg_split('/[\\s,;]+/', $value);
    }

    $out = [];

    foreach ((array)$value as $capability) {
      $capability = sanitize_key((string)$capability);

      /*
       * Compatibility alias for previously issued signed CAS Support Desk
       * tokens. It is not exposed in the normalized session state or reports.
       */
      if ($capability === 'license_client_debug') {
        $capability = 'package_context_read';
      }

      if ($capability !== '' && in_array($capability, $allowed, true)) {
        $out[] = $capability;
      }
    }

    return array_values(array_unique($out));
  }
}

if (!function_exists('custausu_support_diagnostics_sanitize_jti')) {
  function custausu_support_diagnostics_sanitize_jti($value): string {
    $value = is_scalar($value) ? trim((string) $value) : '';
    $value = preg_replace('/[^a-zA-Z0-9._:-]+/', '', $value);

    return substr((string) $value, 0, 120);
  }
}

if (!function_exists('custausu_support_diagnostics_jti_hash')) {
  function custausu_support_diagnostics_jti_hash(string $jti): string {
    $jti = custausu_support_diagnostics_sanitize_jti($jti);

    return $jti !== '' ? hash('sha256', $jti) : '';
  }
}


if (!function_exists('custausu_support_diagnostics_local_revocations_option_name')) {
  function custausu_support_diagnostics_local_revocations_option_name(): string {
    return 'custausu_support_diagnostics_local_revocations';
  }
}

if (!function_exists('custausu_support_diagnostics_local_revocations_get')) {
  function custausu_support_diagnostics_local_revocations_get(): array {
    $raw = get_option(custausu_support_diagnostics_local_revocations_option_name(), []);
    $raw = is_array($raw) ? $raw : [];

    $clean = [];
    $now = time();

    foreach ($raw as $jti_hash => $row) {
      $jti_hash = strtolower(trim((string) $jti_hash));

      if (!preg_match('/^[a-f0-9]{64}$/', $jti_hash)) {
        continue;
      }

      $row = is_array($row) ? $row : [];

      $expires_at = function_exists('custausu_support_diagnostics_sanitize_utc_datetime')
        ? custausu_support_diagnostics_sanitize_utc_datetime($row['expires_at'] ?? '')
        : sanitize_text_field((string) ($row['expires_at'] ?? ''));

      $expires_ts = $expires_at !== ''
        ? strtotime($expires_at . ' UTC')
        : false;

      if ($expires_ts === false || $expires_ts <= $now) {
        continue;
      }

      $revoked_at = function_exists('custausu_support_diagnostics_sanitize_utc_datetime')
        ? custausu_support_diagnostics_sanitize_utc_datetime($row['revoked_at'] ?? '')
        : sanitize_text_field((string) ($row['revoked_at'] ?? ''));

      $clean[$jti_hash] = [
        'expires_at'         => $expires_at,
        'revoked_at'         => $revoked_at,
        'revoked_by_user_id' => absint($row['revoked_by_user_id'] ?? 0),
      ];
    }

    if ($clean !== $raw) {
      update_option(
        custausu_support_diagnostics_local_revocations_option_name(),
        $clean,
        false
      );
    }

    return $clean;
  }
}

if (!function_exists('custausu_support_diagnostics_is_locally_revoked_hash')) {
  function custausu_support_diagnostics_is_locally_revoked_hash(string $jti_hash): bool {
    $jti_hash = strtolower(trim($jti_hash));

    if (!preg_match('/^[a-f0-9]{64}$/', $jti_hash)) {
      return false;
    }

    $rows = custausu_support_diagnostics_local_revocations_get();

    return isset($rows[$jti_hash]);
  }
}

if (!function_exists('custausu_support_diagnostics_revoke_state_locally')) {
  function custausu_support_diagnostics_revoke_state_locally(array $state): bool {
    $jti_hash = strtolower(
      trim((string) ($state['jti_hash'] ?? ''))
    );

    if (!preg_match('/^[a-f0-9]{64}$/', $jti_hash)) {
      $jti = function_exists(
        'custausu_support_diagnostics_sanitize_jti'
      )
        ? custausu_support_diagnostics_sanitize_jti(
            $state['jti'] ?? ''
          )
        : '';

      $jti_hash = $jti !== ''
        ? hash('sha256', $jti)
        : '';
    }

    if (!preg_match('/^[a-f0-9]{64}$/', $jti_hash)) {
      return false;
    }

    $expires_at = function_exists(
      'custausu_support_diagnostics_sanitize_utc_datetime'
    )
      ? custausu_support_diagnostics_sanitize_utc_datetime(
          $state['expires_at'] ?? ''
        )
      : sanitize_text_field(
          (string) ($state['expires_at'] ?? '')
        );

    $expires_ts = $expires_at !== ''
      ? strtotime($expires_at . ' UTC')
      : false;

    if ($expires_ts === false || $expires_ts <= time()) {
      return false;
    }

    $rows = custausu_support_diagnostics_local_revocations_get();

    $rows[$jti_hash] = [
      'expires_at'         => $expires_at,
      'revoked_at'         => gmdate('Y-m-d H:i:s'),
      'revoked_by_user_id' => get_current_user_id(),
    ];

    $option =
      custausu_support_diagnostics_local_revocations_option_name();

    if (get_option($option, null) === null) {
      add_option(
        $option,
        $rows,
        '',
        'no'
      );
    } else {
      update_option(
        $option,
        $rows,
        false
      );
    }

    $stored = get_option($option, []);
    $stored = is_array($stored) ? $stored : [];

    return isset($stored[$jti_hash]);
  }
}

if (!function_exists('custausu_support_diagnostics_is_local_revocation_url')) {
  function custausu_support_diagnostics_is_local_revocation_url(string $url): bool {
    $host = strtolower((string) wp_parse_url($url, PHP_URL_HOST));

    if ($host === '') {
      return false;
    }

    return in_array($host, ['localhost', '127.0.0.1', '::1'], true)
      || substr($host, -6) === '.local'
      || substr($host, -5) === '.test';
  }
}

if (!function_exists('custausu_support_diagnostics_safe_revocation_url')) {
  function custausu_support_diagnostics_safe_revocation_url($url): string {
    $url = is_string($url) ? trim($url) : '';

    if ($url === '' && (defined('CUSTAUSU_SUPPORT_DIAGNOSTICS_REVOCATION_URL') || defined('CAS_SUPPORT_DIAGNOSTICS_REVOCATION_URL'))) {
      $constant_url = (defined('CUSTAUSU_SUPPORT_DIAGNOSTICS_REVOCATION_URL') ? constant('CUSTAUSU_SUPPORT_DIAGNOSTICS_REVOCATION_URL') : constant('CAS_SUPPORT_DIAGNOSTICS_REVOCATION_URL'));
      $url = is_string($constant_url) ? trim($constant_url) : '';
    }

    if ($url === '') {
      $url = 'https://customauthsuite.com/wp-json/cas-support-desk/v1/support-diagnostics/revocation';
    }

    $url = esc_url_raw($url);

    if ($url === '') {
      return '';
    }

    $scheme = strtolower((string) wp_parse_url($url, PHP_URL_SCHEME));
    $host   = strtolower((string) wp_parse_url($url, PHP_URL_HOST));

    if ($host === '' || !in_array($scheme, ['https', 'http'], true)) {
      return '';
    }

    /*
     * Production must use HTTPS.
     * HTTP is accepted only for local/dev test hosts.
     */
    if ($scheme !== 'https' && !custausu_support_diagnostics_is_local_revocation_url($url)) {
      return '';
    }

    return $url;
  }
}

if (!function_exists('custausu_support_diagnostics_remote_revocation_check')) {
  function custausu_support_diagnostics_remote_revocation_check(array $payload): array {
    static $request_cache = [];

    $checked_at = custausu_support_diagnostics_now_utc();

    $jti = custausu_support_diagnostics_sanitize_jti(
      $payload['jti'] ?? ''
    );

    $jti_hash = custausu_support_diagnostics_jti_hash($jti);

    if ($jti === '' || $jti_hash === '') {
      return [
        'ok'         => false,
        'status'     => 'invalid',
        'reason'     => 'jti_missing',
        'checked_at' => $checked_at,
      ];
    }

    $url = custausu_support_diagnostics_safe_revocation_url(
      $payload['revocation_url'] ?? ''
    );

    if ($url === '') {
      return [
        'ok'         => false,
        'status'     => 'invalid',
        'reason'     => 'revocation_url_missing',
        'jti'        => $jti,
        'jti_hash'   => $jti_hash,
        'checked_at' => $checked_at,
      ];
    }

    $memory_key = hash('sha256', $url . '|' . $jti_hash);

    if (isset($request_cache[$memory_key])) {
      return $request_cache[$memory_key];
    }

    /*
     * A very short successful-status cache prevents every CAS hook in the
     * same navigation sequence from repeating the external status request.
     *
     * Local termination remains immediate. A revocation made in CAS Support
     * Desk is detected after at most this short cache window.
     */
    $cache_ttl = (int) apply_filters(
      'custausu_support_diagnostics_revocation_cache_ttl',
      10
    );

    $cache_ttl = max(1, min(30, $cache_ttl));

    $transient_key =
      'cas_sd_revocation_' . substr($jti_hash, 0, 40);

    $cached = get_transient($transient_key);

    if (
      is_array($cached)
      && !empty($cached['ok'])
      && sanitize_key((string)($cached['status'] ?? '')) === 'active'
      && !empty($cached['jti_hash'])
      && hash_equals(
        $jti_hash,
        strtolower((string)$cached['jti_hash'])
      )
    ) {
      $request_cache[$memory_key] = $cached;
      return $cached;
    }

    if (!function_exists('wp_remote_post')) {
      return [
        'ok'         => false,
        'status'     => 'invalid',
        'reason'     => 'http_client_unavailable',
        'jti'        => $jti,
        'jti_hash'   => $jti_hash,
        'checked_at' => $checked_at,
      ];
    }

    $body = [
      'jti'        => $jti,
      'jti_hash'   => $jti_hash,
      'case_id'    => custausu_support_diagnostics_string(
        $payload['case_id'] ?? '',
        100
      ),
      'site_hash'  => custausu_support_diagnostics_sanitize_hash(
        $payload['site_hash'] ?? ''
      ),
      'checked_at' => $checked_at,
    ];

    $timeout = (float) apply_filters(
      'custausu_support_diagnostics_revocation_http_timeout',
      3.0
    );

    $timeout = max(1.0, min(8.0, $timeout));

    $response = wp_remote_post($url, [
      'timeout'   => $timeout,
      'sslverify' =>
        !custausu_support_diagnostics_is_local_revocation_url($url),
      'headers'   => [
        'Content-Type' => 'application/json; charset=utf-8',
      ],
      'body'      => wp_json_encode($body),
    ]);

    if (is_wp_error($response)) {
      return [
        'ok'         => false,
        'status'     => 'invalid',
        'reason'     => 'revocation_check_failed',
        'message'    => $response->get_error_message(),
        'jti'        => $jti,
        'jti_hash'   => $jti_hash,
        'checked_at' => $checked_at,
      ];
    }

    $code = (int) wp_remote_retrieve_response_code($response);
    $raw  = (string) wp_remote_retrieve_body($response);
    $data = json_decode($raw, true);

    if ($code < 200 || $code >= 300 || !is_array($data)) {
      return [
        'ok'         => false,
        'status'     => 'invalid',
        'reason'     => 'revocation_endpoint_invalid_response',
        'http_code'  => $code,
        'jti'        => $jti,
        'jti_hash'   => $jti_hash,
        'checked_at' => $checked_at,
      ];
    }

    $remote_status = sanitize_key(
      (string)($data['status'] ?? '')
    );

    $remote_reason = sanitize_key(
      (string)($data['reason'] ?? '')
    );

    $is_revoked =
      !empty($data['revoked'])
      || $remote_status === 'revoked';

    if ($is_revoked) {
      delete_transient($transient_key);

      $result = [
        'ok'         => false,
        'status'     => 'revoked',
        'reason'     => 'token_revoked_remote',
        'jti'        => $jti,
        'jti_hash'   => $jti_hash,
        'checked_at' => $checked_at,
      ];

      $request_cache[$memory_key] = $result;
      return $result;
    }

    if (
      !empty($data['ok'])
      || $remote_status === 'active'
      || $remote_status === 'valid'
      || $remote_status === 'not_revoked'
      || (
        array_key_exists('revoked', $data)
        && empty($data['revoked'])
      )
    ) {
      $result = [
        'ok'         => true,
        'status'     => 'active',
        'reason'     => 'not_revoked',
        'jti'        => $jti,
        'jti_hash'   => $jti_hash,
        'checked_at' => $checked_at,
      ];

      set_transient(
        $transient_key,
        $result,
        $cache_ttl
      );

      $request_cache[$memory_key] = $result;
      return $result;
    }

    delete_transient($transient_key);

    if (
      in_array($remote_status, ['unknown', 'not_found'], true)
      || $remote_reason === 'unknown_jti'
    ) {
      return [
        'ok'         => false,
        'status'     => 'invalid',
        'reason'     => 'token_unknown_remote',
        'jti'        => $jti,
        'jti_hash'   => $jti_hash,
        'checked_at' => $checked_at,
      ];
    }

    return [
      'ok'         => false,
      'status'     => 'invalid',
      'reason'     => $remote_reason !== ''
        ? $remote_reason
        : 'revocation_endpoint_error',
      'jti'        => $jti,
      'jti_hash'   => $jti_hash,
      'checked_at' => $checked_at,
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_normalize_state')) {
  function custausu_support_diagnostics_normalize_state(array $state): array {
    $defaults = custausu_support_diagnostics_get_default_state();

    $out = $defaults;

    $out['schema_version'] = max(1, (int)($state['schema_version'] ?? 1));
    $out['status'] = custausu_support_diagnostics_sanitize_status(
      $state['status'] ?? 'none',
      ['none', 'active', 'expired', 'invalid', 'revoked'],
      'none'
    );

    $token = is_string($state['token'] ?? null) ? trim((string)$state['token']) : '';
    if (strlen($token) > 8000) {
      $token = substr($token, 0, 8000);
    }

    $scope = sanitize_key((string)($state['scope'] ?? ''));

    $out['token']        = $token;
    $out['issued_at']    = custausu_support_diagnostics_sanitize_utc_datetime($state['issued_at'] ?? '');
    $out['expires_at']   = custausu_support_diagnostics_sanitize_utc_datetime($state['expires_at'] ?? '');
    $out['scope']        = in_array($scope, ['site', 'host', 'dev'], true) ? $scope : '';
    $out['site_hash']    = custausu_support_diagnostics_sanitize_hash($state['site_hash'] ?? '');
    $out['label']        = custausu_support_diagnostics_string($state['label'] ?? '', 190);
    $out['case_id']      = custausu_support_diagnostics_string($state['case_id'] ?? '', 100);
    $out['jti']          = custausu_support_diagnostics_sanitize_jti($state['jti'] ?? '');
    $out['jti_hash']     = custausu_support_diagnostics_sanitize_hash($state['jti_hash'] ?? '');
    $out['revocation_url'] = custausu_support_diagnostics_safe_revocation_url($state['revocation_url'] ?? '');
    $out['revocation_checked_at'] = custausu_support_diagnostics_sanitize_utc_datetime($state['revocation_checked_at'] ?? '');
    $out['revocation_status'] = sanitize_key((string) ($state['revocation_status'] ?? ''));
    $out['capabilities'] = custausu_support_diagnostics_normalize_capabilities($state['capabilities'] ?? []);
    $out['checked_at']   = custausu_support_diagnostics_sanitize_utc_datetime($state['checked_at'] ?? '');
    $out['reason']       = sanitize_key((string)($state['reason'] ?? ''));
    $viewer_policy = sanitize_key((string)($state['viewer_policy'] ?? 'support_session'));
    if (!in_array($viewer_policy, ['support_session', 'any_admin'], true)) {
      $viewer_policy = 'support_session';
    }

    $out['viewer_policy'] = $viewer_policy;

    $out['activated_by_user_id'] = absint($state['activated_by_user_id'] ?? 0);

    $session_hash = strtolower(trim((string)($state['activated_by_session_hash'] ?? '')));
    $out['activated_by_session_hash'] = preg_match('/^[a-f0-9]{64}$/', $session_hash) ? $session_hash : '';

    $out['activated_at_utc'] = sanitize_text_field((string)($state['activated_at_utc'] ?? ''));

    return $out;
  }
}

if (!function_exists('custausu_support_diagnostics_get_stored_state')) {
  function custausu_support_diagnostics_get_stored_state(): array {
    $raw = get_option(custausu_support_diagnostics_option_name(), []);
    $raw = is_array($raw) ? $raw : [];

    $state = custausu_support_diagnostics_normalize_state($raw);

    $status = sanitize_key((string) ($state['status'] ?? 'none'));
    $expires_at = (string) ($state['expires_at'] ?? '');

    if ($status === 'active' && $expires_at !== '') {
      $expires_ts = strtotime($expires_at . ' UTC');

      if ($expires_ts !== false && $expires_ts <= time()) {
        $state['status'] = 'expired';
        $state['reason'] = 'token_expired';
        $state['token'] = '';
        $state['activated_by_user_id'] = 0;
        $state['activated_by_session_hash'] = '';
        $state['activated_at_utc'] = '';

        $state = custausu_support_diagnostics_normalize_state($state);

        update_option(
          custausu_support_diagnostics_option_name(),
          $state,
          false
        );
      }
    }

    return $state;
  }
}

if (!function_exists('custausu_support_diagnostics_update_state')) {
  function custausu_support_diagnostics_update_state(array $state): bool {
    $state = custausu_support_diagnostics_normalize_state($state);

    $updated = update_option(
      custausu_support_diagnostics_option_name(),
      $state,
      false
    );

    /*
     * Keep the current request coherent after Apply, Clear or terminal-state
     * cleanup. The next HTTP request starts with an empty in-memory cache.
     */
    $GLOBALS['custausu_support_diagnostics_request_state_cache'] = $state;

    return (bool) $updated;
  }
}

if (!function_exists('custausu_support_diagnostics_parse_token')) {
  function custausu_support_diagnostics_parse_token(string $token): array {
    $token = trim($token);

    if ($token === '') {
      return [
        'ok'     => false,
        'reason' => 'empty_token',
      ];
    }

    if (strlen($token) > 8000) {
      return [
        'ok'     => false,
        'reason' => 'token_too_long',
      ];
    }

    $parts = explode('.', $token);

    if (count($parts) !== 2) {
      return [
        'ok'     => false,
        'reason' => 'malformed_token',
      ];
    }

    [$payload_b64, $sig_b64] = $parts;

    $payload_json = custausu_support_diagnostics_base64url_decode($payload_b64);
    $signature    = custausu_support_diagnostics_base64url_decode($sig_b64);

    if (!is_string($payload_json) || $payload_json === '' || !is_string($signature) || $signature === '') {
      return [
        'ok'     => false,
        'reason' => 'decode_failed',
      ];
    }

    $payload = json_decode($payload_json, true);

    if (!is_array($payload)) {
      return [
        'ok'     => false,
        'reason' => 'invalid_payload_json',
      ];
    }

    return [
      'ok'            => true,
      'payload'       => $payload,
      'payload_json'  => $payload_json,
      'payload_b64'   => $payload_b64,
      'signature'     => $signature,
      'signature_b64' => $sig_b64,
      'token'         => $token,
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_validate_token')) {
  function custausu_support_diagnostics_validate_token(string $token): array {
    $checked_at = custausu_support_diagnostics_now_utc();

    $base = [
      'valid'        => false,
      'status'       => 'invalid',
      'issued_at'    => '',
      'expires_at'   => '',
      'scope'        => '',
      'site_hash'    => '',
      'label'        => '',
      'case_id'      => '',
      'capabilities' => [],
      'checked_at'   => $checked_at,
      'reason'       => 'invalid_token',
    ];

    $parsed = custausu_support_diagnostics_parse_token($token);

    if (empty($parsed['ok'])) {
      $base['reason'] = (string)($parsed['reason'] ?? 'parse_failed');
      return $base;
    }

    if (!function_exists('openssl_verify') || !function_exists('openssl_pkey_get_public')) {
      $base['reason'] = 'openssl_unavailable';
      return $base;
    }

    $public_key = custausu_support_diagnostics_get_public_key();

    if ($public_key === '') {
      $base['reason'] = 'public_key_missing';
      return $base;
    }

    $pkey = @openssl_pkey_get_public($public_key);

    if (!$pkey) {
      $base['reason'] = 'public_key_invalid';
      return $base;
    }

    $verified = @openssl_verify(
      (string)$parsed['payload_b64'],
      (string)$parsed['signature'],
      $pkey,
      OPENSSL_ALGO_SHA256
    );

    if ($verified !== 1) {
      $base['reason'] = 'signature_invalid';
      return $base;
    }

    $payload = (array)$parsed['payload'];

    $iss = custausu_support_diagnostics_string($payload['iss'] ?? '', 50);
    $typ = custausu_support_diagnostics_string($payload['typ'] ?? '', 50);

    if ($iss !== 'CAS' || $typ !== 'support_diagnostics') {
      $base['reason'] = 'claims_invalid';
      return $base;
    }

    $scope = sanitize_key((string)($payload['scope'] ?? ''));
    $scope = in_array($scope, ['site', 'host', 'dev'], true) ? $scope : '';

    $site_hash = custausu_support_diagnostics_sanitize_hash($payload['site_hash'] ?? '');
    $label     = custausu_support_diagnostics_string($payload['label'] ?? '', 190);
    $case_id   = custausu_support_diagnostics_string($payload['case_id'] ?? '', 100);
    $jti       = custausu_support_diagnostics_sanitize_jti($payload['jti'] ?? '');
    $jti_hash  = custausu_support_diagnostics_jti_hash($jti);
    $revocation_url = custausu_support_diagnostics_safe_revocation_url($payload['revocation_url'] ?? '');

    $consent_source  = sanitize_key((string) ($payload['consent_source'] ?? ''));
    $consent_granted = !empty($payload['consent_granted']);
    $consent_ticket  = custausu_support_diagnostics_string($payload['consent_ticket'] ?? '', 100);
    $consent_at      = custausu_support_diagnostics_string($payload['consent_at'] ?? '', 40);

    $capabilities = custausu_support_diagnostics_normalize_capabilities($payload['capabilities'] ?? []);

    $iat = isset($payload['iat']) && is_numeric($payload['iat']) ? (int)$payload['iat'] : 0;
    $nbf = isset($payload['nbf']) && is_numeric($payload['nbf']) ? (int)$payload['nbf'] : 0;
    $exp = isset($payload['exp']) && is_numeric($payload['exp']) ? (int)$payload['exp'] : 0;

    if ($scope === '' || $site_hash === '' || empty($capabilities) || $exp <= 0) {
      $base['reason'] = 'claims_incomplete';
      return $base;
    }

    if ($jti === '' || $jti_hash === '') {
      $base['reason'] = 'jti_missing';
      return $base;
    }

    /*
    * CAS Support Diagnostics hardening:
    * tokens are accepted only when generated from CAS Support Desk
    * after explicit customer diagnostics consent on a ticket.
    */
    if (
      $consent_source !== 'cas_support_desk_ticket'
      || !$consent_granted
      || $case_id === ''
      || $consent_ticket === ''
    ) {
      $base['reason'] = 'ticket_consent_missing';
      return $base;
    }

    $current_site_hash = function_exists('custausu_support_diagnostics_site_hash') ? custausu_support_diagnostics_site_hash() : '';
    $current_host_hash = function_exists('custausu_support_diagnostics_host_hash') ? custausu_support_diagnostics_host_hash() : '';

    $scope_ok = false;

    if ($scope === 'site') {
      $scope_ok = $current_site_hash !== '' && hash_equals($site_hash, $current_site_hash);
    } elseif ($scope === 'host') {
      $scope_ok = $current_host_hash !== '' && hash_equals($site_hash, $current_host_hash);
    } elseif ($scope === 'dev') {
      $scope_ok = function_exists('custausu_support_diagnostics_is_dev_environment')
        && custausu_support_diagnostics_is_dev_environment()
        && (
          ($current_site_hash !== '' && hash_equals($site_hash, $current_site_hash))
          || ($current_host_hash !== '' && hash_equals($site_hash, $current_host_hash))
        );
    }

    if (!$scope_ok) {
      $base['reason'] = 'scope_mismatch';
      return $base;
    }

    $now = time();

    if ($iat > 0 && $iat > ($now + HOUR_IN_SECONDS)) {
      $base['reason'] = 'issued_in_future';
      return $base;
    }

    if ($nbf > 0 && $nbf > $now) {
      $base['reason'] = 'not_before';
      return $base;
    }

    if ($exp <= $now) {
      $base['status']       = 'expired';
      $base['issued_at']    = $iat > 0 ? custausu_support_diagnostics_to_utc_string($iat) : '';
      $base['expires_at']   = custausu_support_diagnostics_to_utc_string($exp);
      $base['scope']        = $scope;
      $base['site_hash']    = $site_hash;
      $base['label']        = $label;
      $base['case_id']      = $case_id;
      $base['capabilities'] = $capabilities;
      $base['reason']       = 'token_expired';
      return $base;
    }

    /*
     * Safety limit: support diagnostics tokens should be short-lived.
     * Even if the server accidentally creates a longer token, the client refuses it.
     */
    if ($iat > 0 && ($exp - $iat) > (30 * DAY_IN_SECONDS)) {
      $base['reason'] = 'duration_too_long';
      return $base;
    }

    if (
      function_exists('custausu_support_diagnostics_is_locally_revoked_hash')
      && custausu_support_diagnostics_is_locally_revoked_hash($jti_hash)
    ) {
      $base['status']       = 'revoked';
      $base['issued_at']    = $iat > 0 ? custausu_support_diagnostics_to_utc_string($iat) : '';
      $base['expires_at']   = custausu_support_diagnostics_to_utc_string($exp);
      $base['scope']        = $scope;
      $base['site_hash']    = $site_hash;
      $base['label']        = $label;
      $base['case_id']      = $case_id;
      $base['jti']          = $jti;
      $base['jti_hash']     = $jti_hash;
      $base['revocation_url'] = $revocation_url;
      $base['revocation_status'] = 'locally_revoked';
      $base['capabilities'] = $capabilities;
      $base['reason']       = 'locally_revoked';

      return $base;
    }

    $revocation_check = custausu_support_diagnostics_remote_revocation_check($payload);

    if (empty($revocation_check['ok'])) {
      $base['status']       = ($revocation_check['status'] ?? '') === 'revoked' ? 'revoked' : 'invalid';
      $base['issued_at']    = $iat > 0 ? custausu_support_diagnostics_to_utc_string($iat) : '';
      $base['expires_at']   = custausu_support_diagnostics_to_utc_string($exp);
      $base['scope']        = $scope;
      $base['site_hash']    = $site_hash;
      $base['label']        = $label;
      $base['case_id']      = $case_id;
      $base['jti']          = $jti;
      $base['jti_hash']     = $jti_hash;
      $base['revocation_url'] = $revocation_url;
      $base['revocation_checked_at'] = (string) ($revocation_check['checked_at'] ?? $checked_at);
      $base['revocation_status'] = sanitize_key((string) ($revocation_check['status'] ?? 'invalid'));
      $base['capabilities'] = $capabilities;
      $base['reason']       = sanitize_key((string) ($revocation_check['reason'] ?? 'revocation_check_failed'));
      return $base;
    }

    return [
      'valid'        => true,
      'status'       => 'active',
      'issued_at'    => $iat > 0 ? custausu_support_diagnostics_to_utc_string($iat) : '',
      'expires_at'   => custausu_support_diagnostics_to_utc_string($exp),
      'scope'        => $scope,
      'site_hash'    => $site_hash,
      'label'        => $label,
      'case_id'      => $case_id,
      'jti'          => $jti,
      'jti_hash'     => $jti_hash,
      'revocation_url' => $revocation_url,
      'revocation_checked_at' => (string) ($revocation_check['checked_at'] ?? $checked_at),
      'revocation_status' => 'active',
      'capabilities' => $capabilities,
      'checked_at'   => $checked_at,
      'consent_source'  => $consent_source,
      'viewer_policy' => (static function($value): string {
        $value = sanitize_key((string)$value);
        return in_array($value, ['support_session', 'any_admin'], true)
          ? $value
          : 'support_session';
      })($payload['viewer_policy'] ?? 'support_session'),
      'consent_granted' => $consent_granted,
      'consent_ticket'  => $consent_ticket,
      'consent_at'      => $consent_at,
      'reason'       => 'ok',
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_current_viewer_session_hash')) {
  function custausu_support_diagnostics_current_viewer_session_hash(): string {
    if (!is_user_logged_in()) {
      return '';
    }

    $user_id = get_current_user_id();
    if ($user_id <= 0) {
      return '';
    }

    $session_token = function_exists('wp_get_session_token') ? (string) wp_get_session_token() : '';
    if ($session_token === '') {
      return '';
    }

    return hash_hmac(
      'sha256',
      $user_id . '|' . $session_token,
      wp_salt('auth')
    );
  }
}

if (!function_exists('custausu_support_diagnostics_current_admin_can_viewer')) {
  function custausu_support_diagnostics_current_admin_can_viewer(array $state = []): bool {
    if (!current_user_can('manage_options')) {
      return false;
    }

    if (empty($state)) {
      $state = function_exists('custausu_support_diagnostics_get_state')
        ? custausu_support_diagnostics_get_state()
        : custausu_support_diagnostics_get_stored_state();
    }

    $viewer_policy = sanitize_key((string)($state['viewer_policy'] ?? 'support_session'));

    if ($viewer_policy === 'any_admin') {
      return current_user_can('manage_options');
    }

    $owner_user_id = absint($state['activated_by_user_id'] ?? 0);
    $owner_hash    = strtolower(trim((string)($state['activated_by_session_hash'] ?? '')));

    if ($owner_user_id <= 0 || $owner_hash === '') {
      return false;
    }

    if ($owner_user_id !== get_current_user_id()) {
      return false;
    }

    $current_hash = custausu_support_diagnostics_current_viewer_session_hash();
    if ($current_hash === '') {
      return false;
    }

    return hash_equals($owner_hash, $current_hash);
  }
}

if (!function_exists('custausu_support_diagnostics_current_admin_can_clear_token')) {
  function custausu_support_diagnostics_current_admin_can_clear_token(array $state = []): bool {
    if (!current_user_can('manage_options')) {
      return false;
    }

    if (empty($state)) {
      $state = function_exists('custausu_support_diagnostics_get_stored_state')
        ? custausu_support_diagnostics_get_stored_state()
        : [];
    }

    $status = sanitize_key((string) ($state['status'] ?? 'none'));

    return $status === 'active'
      || (string) ($state['token'] ?? '') !== ''
      || (string) ($state['jti'] ?? '') !== ''
      || (string) ($state['jti_hash'] ?? '') !== '';
  }
}

if (!function_exists('custausu_support_diagnostics_apply_token')) {
  function custausu_support_diagnostics_apply_token(string $token): array {
    $token = trim($token);
    $validation = custausu_support_diagnostics_validate_token($token);

    $valid = !empty($validation['valid']);

    $state = custausu_support_diagnostics_get_default_state();
    $state['token']        = $valid ? $token : '';
    $state['status']       = $validation['status'] ?? 'invalid';
    $state['issued_at']    = $validation['issued_at'] ?? '';
    $state['expires_at']   = $validation['expires_at'] ?? '';
    $state['scope']        = $validation['scope'] ?? '';
    $state['site_hash']    = $validation['site_hash'] ?? '';
    $state['label']        = $validation['label'] ?? '';
    $state['case_id']      = $validation['case_id'] ?? '';
    $state['jti']          = $validation['jti'] ?? '';
    $state['jti_hash']     = $validation['jti_hash'] ?? '';
    $state['revocation_url'] = $validation['revocation_url'] ?? '';
    $state['revocation_checked_at'] = $validation['revocation_checked_at'] ?? '';
    $state['revocation_status'] = $validation['revocation_status'] ?? '';
    $state['capabilities'] = $validation['capabilities'] ?? [];
    $state['checked_at']   = $validation['checked_at'] ?? custausu_support_diagnostics_now_utc();
    $state['reason']       = $validation['reason'] ?? 'invalid_token';

    $viewer_policy = sanitize_key(
      (string) ($validation['viewer_policy'] ?? 'support_session')
    );

    if (!in_array($viewer_policy, ['support_session', 'any_admin'], true)) {
      $viewer_policy = 'support_session';
    }

    $state['viewer_policy'] = $viewer_policy;

    if ($valid) {
      $state['activated_by_user_id'] = get_current_user_id();
      $state['activated_by_session_hash'] =
        custausu_support_diagnostics_current_viewer_session_hash();
      $state['activated_at_utc'] = gmdate('Y-m-d H:i:s');

      if (
        $viewer_policy === 'support_session'
        && (
          empty($state['activated_by_user_id'])
          || empty($state['activated_by_session_hash'])
        )
      ) {
        return [
          'ok' => false,
          'validation' => [
            'ok' => false,
            'valid' => false,
            'status' => 'invalid',
            'reason' => 'viewer_session_unavailable',
          ],
        ];
      }
    }

    custausu_support_diagnostics_update_state($state);

    return [
      'ok'         => $valid,
      'validation' => $validation,
      'state'      => custausu_support_diagnostics_get_stored_state(),
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_clear_token')) {
  function custausu_support_diagnostics_clear_token(): bool {
    $state = function_exists(
      'custausu_support_diagnostics_get_stored_state'
    )
      ? custausu_support_diagnostics_get_stored_state()
      : [];

    $state = is_array($state) ? $state : [];

    $prepared =
      custausu_support_diagnostics_client_revoke_prepare_job(
        $state
      );

    $local_state = !empty($prepared['ok'])
      && is_array($prepared['local_state'] ?? null)
        ? (array) $prepared['local_state']
        : $state;

    $status = sanitize_key(
      (string) ($state['status'] ?? 'none')
    );

    $token_present =
      trim((string) ($state['token'] ?? '')) !== '';

    $expires_at = (string) (
      $local_state['expires_at']
      ?? $state['expires_at']
      ?? ''
    );

    $expires_ts = $expires_at !== ''
      ? strtotime($expires_at . ' UTC')
      : false;

    $needs_local_tombstone = (
      ($status === 'active' || $token_present)
      && $expires_ts !== false
      && $expires_ts > time()
    );

    $local_revoked = true;

    if ($needs_local_tombstone) {
      $local_revoked =
        custausu_support_diagnostics_revoke_state_locally(
          $local_state
        );

      $jti_hash = strtolower(
        trim(
          (string) (
            $local_state['jti_hash']
            ?? ''
          )
        )
      );

      if (
        $local_revoked
        && preg_match('/^[a-f0-9]{64}$/', $jti_hash)
      ) {
        $local_revoked =
          custausu_support_diagnostics_is_locally_revoked_hash(
            $jti_hash
          );
      }
    }

    if (!$local_revoked) {
      $GLOBALS[
        'custausu_support_diagnostics_client_revoke_last_result'
      ] = [
        'ok'             => false,
        'local_revoked'  => false,
        'state_cleared'  => false,
        'remote_status'  => 'not_attempted',
        'remote_reason'  => 'local_revocation_persist_failed',
        'queue_persisted'=> false,
        'request_id'     => '',
        'attempts'       => 0,
        'http_code'      => 0,
      ];

      return false;
    }

    custausu_support_diagnostics_update_state(
      custausu_support_diagnostics_get_default_state()
    );

    $stored = custausu_support_diagnostics_get_stored_state();

    $state_cleared = (
      (string) ($stored['token'] ?? '') === ''
      && (string) ($stored['jti'] ?? '') === ''
      && (string) ($stored['jti_hash'] ?? '') === ''
      && sanitize_key(
        (string) ($stored['status'] ?? 'none')
      ) === 'none'
    );

    if (!$state_cleared) {
      $GLOBALS[
        'custausu_support_diagnostics_client_revoke_last_result'
      ] = [
        'ok'             => false,
        'local_revoked'  => $local_revoked,
        'state_cleared'  => false,
        'remote_status'  => 'not_attempted',
        'remote_reason'  => 'state_clear_failed',
        'queue_persisted'=> false,
        'request_id'     => '',
        'attempts'       => 0,
        'http_code'      => 0,
      ];

      return false;
    }

    $remote = [
      'status'     => 'not_prepared',
      'reason'     => sanitize_key(
        (string) (
          $prepared['reason']
          ?? 'no_remote_job'
        )
      ),
      'request_id' => '',
      'attempts'   => 0,
      'http_code'  => 0,
      'queued'     => false,
    ];

    if (
      !empty($prepared['ok'])
      && is_array($prepared['job'] ?? null)
    ) {
      $remote =
        custausu_support_diagnostics_client_revoke_dispatch(
          (array) $prepared['job']
        );
    }

    $GLOBALS[
      'custausu_support_diagnostics_client_revoke_last_result'
    ] = [
      'ok'              => true,
      'local_revoked'   => $local_revoked,
      'state_cleared'   => true,
      'remote_status'   => sanitize_key(
        (string) ($remote['status'] ?? 'not_prepared')
      ),
      'remote_reason'   => sanitize_key(
        (string) ($remote['reason'] ?? '')
      ),
      'queue_persisted' => !empty($remote['queued']),
      'request_id'      => strtolower(
        trim((string) ($remote['request_id'] ?? ''))
      ),
      'attempts'        => absint(
        $remote['attempts'] ?? 0
      ),
      'http_code'       => absint(
        $remote['http_code'] ?? 0
      ),
    ];

    return true;
  }
}

if (!function_exists('custausu_support_diagnostics_get_state')) {
  function custausu_support_diagnostics_get_state(): array {
    if (
      isset($GLOBALS['custausu_support_diagnostics_request_state_cache'])
      && is_array(
        $GLOBALS['custausu_support_diagnostics_request_state_cache']
      )
    ) {
      return $GLOBALS[
        'custausu_support_diagnostics_request_state_cache'
      ];
    }

    $state = custausu_support_diagnostics_get_stored_state();

    if ((string)($state['token'] ?? '') === '') {
      $GLOBALS[
        'custausu_support_diagnostics_request_state_cache'
      ] = $state;

      return $state;
    }

    /*
     * Validate at most once per PHP request. Calls from individual debug
     * channels, capability checks and admin renderers reuse this result.
     */
    $validation = custausu_support_diagnostics_validate_token(
      (string)$state['token']
    );

    $new = $state;

    $new['status'] = $validation['status'] ?? 'invalid';
    $new['issued_at'] = $validation['issued_at'] ?? '';
    $new['expires_at'] = $validation['expires_at'] ?? '';
    $new['scope'] = $validation['scope'] ?? '';
    $new['site_hash'] = $validation['site_hash'] ?? '';
    $new['label'] = $validation['label'] ?? '';
    $new['case_id'] = $validation['case_id'] ?? '';
    $new['jti'] = $validation['jti'] ?? '';
    $new['jti_hash'] = $validation['jti_hash'] ?? '';
    $new['revocation_url'] =
      $validation['revocation_url'] ?? '';
    $new['revocation_checked_at'] =
      $validation['revocation_checked_at'] ?? '';
    $new['revocation_status'] =
      $validation['revocation_status'] ?? '';
    $new['capabilities'] =
      $validation['capabilities'] ?? [];
    $new['checked_at'] =
      $validation['checked_at'] ?? custausu_support_diagnostics_now_utc();
    $new['reason'] =
      $validation['reason'] ?? 'invalid_token';

    $terminal_status = sanitize_key(
      (string)($new['status'] ?? 'invalid')
    );

    if (
      in_array(
        $terminal_status,
        ['expired', 'revoked'],
        true
      )
    ) {
      $new['token'] = '';
      $new['activated_by_user_id'] = 0;
      $new['activated_by_session_hash'] = '';
      $new['activated_at_utc'] = '';
    }

    $new = custausu_support_diagnostics_normalize_state($new);

    if ($new !== $state) {
      custausu_support_diagnostics_update_state($new);
    } else {
      $GLOBALS[
        'custausu_support_diagnostics_request_state_cache'
      ] = $new;
    }

    return $new;
  }
}

if (!function_exists('custausu_support_diagnostics_is_active')) {
  function custausu_support_diagnostics_is_active(): bool {
    $state = custausu_support_diagnostics_get_state();

    return (string)($state['status'] ?? 'none') === 'active';
  }
}

if (!function_exists('custausu_support_diagnostics_can')) {
  function custausu_support_diagnostics_can(string $capability): bool {
    $capability = sanitize_key($capability);

    if ($capability === '' || !custausu_support_diagnostics_is_active()) {
      return false;
    }

    $state = custausu_support_diagnostics_get_state();
    $capabilities = custausu_support_diagnostics_normalize_capabilities($state['capabilities'] ?? []);

    return in_array($capability, $capabilities, true);
  }
}
