<?php
if (!defined('ABSPATH')) {
  exit;
}

// -----------------------------------------------------------------------------
// CAS Remote Support Diagnostics — client-initiated revocation delivery
// -----------------------------------------------------------------------------

if (!function_exists('custausu_support_diagnostics_client_revoke_queue_option_name')) {
  function custausu_support_diagnostics_client_revoke_queue_option_name(): string {
    return 'custausu_support_diagnostics_client_revoke_queue';
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_cron_hook')) {
  function custausu_support_diagnostics_client_revoke_cron_hook(): string {
    return 'custausu_support_diagnostics_client_revoke_retry';
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_queue_max_entries')) {
  function custausu_support_diagnostics_client_revoke_queue_max_entries(): int {
    $max = (int) apply_filters(
      'custausu_support_diagnostics_client_revoke_queue_max_entries',
      20
    );

    return max(5, min(50, $max));
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_max_attempts')) {
  function custausu_support_diagnostics_client_revoke_max_attempts(): int {
    $max = (int) apply_filters(
      'custausu_support_diagnostics_client_revoke_max_attempts',
      8
    );

    return max(3, min(12, $max));
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_backoff_seconds')) {
  function custausu_support_diagnostics_client_revoke_backoff_seconds(
    int $attempts
  ): int {
    $schedule = [
      5 * MINUTE_IN_SECONDS,
      15 * MINUTE_IN_SECONDS,
      HOUR_IN_SECONDS,
      3 * HOUR_IN_SECONDS,
      6 * HOUR_IN_SECONDS,
      12 * HOUR_IN_SECONDS,
      DAY_IN_SECONDS,
      2 * DAY_IN_SECONDS,
    ];

    $index = max(
      0,
      min(count($schedule) - 1, $attempts - 1)
    );

    return (int) $schedule[$index];
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_same_origin')) {
  function custausu_support_diagnostics_client_revoke_same_origin(
    string $first,
    string $second
  ): bool {
    $first_scheme = strtolower(
      (string) wp_parse_url($first, PHP_URL_SCHEME)
    );

    $second_scheme = strtolower(
      (string) wp_parse_url($second, PHP_URL_SCHEME)
    );

    $first_host = strtolower(
      (string) wp_parse_url($first, PHP_URL_HOST)
    );

    $second_host = strtolower(
      (string) wp_parse_url($second, PHP_URL_HOST)
    );

    $first_port = (int) wp_parse_url($first, PHP_URL_PORT);
    $second_port = (int) wp_parse_url($second, PHP_URL_PORT);

    if ($first_port <= 0) {
      $first_port = $first_scheme === 'https' ? 443 : 80;
    }

    if ($second_port <= 0) {
      $second_port = $second_scheme === 'https' ? 443 : 80;
    }

    return $first_scheme !== ''
      && $first_scheme === $second_scheme
      && $first_host !== ''
      && hash_equals($first_host, $second_host)
      && $first_port === $second_port;
  }
}

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

    /*
     * Client revocation must be derived only from the endpoint embedded in
     * the signed support token. Do not use the generic fallback URL here.
     */
    if ($revocation_url === '') {
      return '';
    }

    $revocation_url =
      custausu_support_diagnostics_safe_revocation_url(
        $revocation_url
      );

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

    $scheme = strtolower(
      (string) wp_parse_url(
        $revocation_url,
        PHP_URL_SCHEME
      )
    );

    $host = strtolower(
      (string) wp_parse_url(
        $revocation_url,
        PHP_URL_HOST
      )
    );

    $port = (int) wp_parse_url(
      $revocation_url,
      PHP_URL_PORT
    );

    $path = (string) wp_parse_url(
      $revocation_url,
      PHP_URL_PATH
    );

    if (
      $scheme === ''
      || $host === ''
      || $path === ''
      || !preg_match(
        '~/support-diagnostics/revocation/?$~',
        $path
      )
    ) {
      return '';
    }

    $client_path = preg_replace(
      '~/revocation/?$~',
      '/client-revoke',
      $path,
      1
    );

    if (
      !is_string($client_path)
      || $client_path === $path
    ) {
      return '';
    }

    $host_for_url = strpos($host, ':') !== false
      ? '[' . trim($host, '[]') . ']'
      : $host;

    $endpoint = $scheme
      . '://'
      . $host_for_url
      . ($port > 0 ? ':' . $port : '')
      . $client_path;

    $endpoint = esc_url_raw($endpoint);

    if (
      $endpoint === ''
      || !custausu_support_diagnostics_client_revoke_same_origin(
        $revocation_url,
        $endpoint
      )
    ) {
      return '';
    }

    return $endpoint;
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_canonical_payload')) {
  function custausu_support_diagnostics_client_revoke_canonical_payload(
    array $payload
  ): string {
    return implode("\n", [
      'version=1',
      'action=client_revoke',
      'source=client',
      'scope=' . (string) ($payload['scope'] ?? ''),
      'jti_hash=' . (string) ($payload['jti_hash'] ?? ''),
      'target_hash=' . (string) ($payload['target_hash'] ?? ''),
      'case_id=' . (string) ($payload['case_id'] ?? ''),
      'revoked_at=' . (string) absint(
        $payload['revoked_at'] ?? 0
      ),
      'request_id=' . (string) ($payload['request_id'] ?? ''),
    ]);
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_normalize_payload')) {
  function custausu_support_diagnostics_client_revoke_normalize_payload(
    array $payload
  ): array {
    $version = sanitize_key(
      (string) ($payload['version'] ?? '')
    );

    $source = sanitize_key(
      (string) ($payload['source'] ?? '')
    );

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

    if (!in_array($scope, ['site', 'host', 'dev'], true)) {
      $scope = '';
    }

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

    $target_hash = strtolower(
      trim((string) ($payload['target_hash'] ?? ''))
    );

    $case_id = sanitize_text_field(
      (string) ($payload['case_id'] ?? '')
    );

    $case_id = substr($case_id, 0, 80);

    $revoked_at = absint(
      $payload['revoked_at'] ?? 0
    );

    $request_id = strtolower(
      trim((string) ($payload['request_id'] ?? ''))
    );

    $proof = strtolower(
      trim((string) ($payload['proof'] ?? ''))
    );

    if (
      $version !== '1'
      || $source !== 'client'
      || $scope === ''
      || !preg_match('/^[a-f0-9]{64}$/', $jti_hash)
      || !preg_match('/^[a-f0-9]{64}$/', $target_hash)
      || $case_id === ''
      || $revoked_at <= 0
      || !preg_match('/^[a-f0-9]{32,64}$/', $request_id)
      || !preg_match('/^[a-f0-9]{64}$/', $proof)
    ) {
      return [];
    }

    return [
      'version'     => '1',
      'source'      => 'client',
      'scope'       => $scope,
      'jti_hash'    => $jti_hash,
      'target_hash' => $target_hash,
      'case_id'     => $case_id,
      'revoked_at'  => $revoked_at,
      'request_id'  => $request_id,
      'proof'       => $proof,
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_prepare_job')) {
  function custausu_support_diagnostics_client_revoke_prepare_job(
    array $state
  ): array {
    $token = is_string($state['token'] ?? null)
      ? trim((string) $state['token'])
      : '';

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

    $parsed = custausu_support_diagnostics_parse_token($token);

    if (
      empty($parsed['ok'])
      || !is_array($parsed['payload'] ?? null)
    ) {
      return [
        'ok'     => false,
        'reason' => 'token_parse_failed',
      ];
    }

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

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

    if (!in_array($scope, ['site', 'host', 'dev'], true)) {
      return [
        'ok'     => false,
        'reason' => 'scope_missing',
      ];
    }

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

    $jti_hash = custausu_support_diagnostics_jti_hash($jti);

    $target_hash = custausu_support_diagnostics_sanitize_hash(
      $claims['site_hash'] ?? ''
    );

    $case_id = custausu_support_diagnostics_string(
      $claims['case_id'] ?? '',
      80
    );

    $expires_at = '';

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

    if ($exp > 0) {
      $expires_at = custausu_support_diagnostics_to_utc_string($exp);
    }

    $endpoint =
      custausu_support_diagnostics_client_revoke_endpoint(
        $claims['revocation_url'] ?? ''
      );

    if (
      $jti === ''
      || $jti_hash === ''
      || $target_hash === ''
      || $case_id === ''
      || $expires_at === ''
      || $endpoint === ''
    ) {
      return [
        'ok'     => false,
        'reason' => 'claims_incomplete',
      ];
    }

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

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

    $state_target_hash = custausu_support_diagnostics_sanitize_hash(
      $state['site_hash'] ?? ''
    );

    $state_case_id = custausu_support_diagnostics_string(
      $state['case_id'] ?? '',
      80
    );

    if (
      ($state_scope !== '' && $state_scope !== $scope)
      || (
        preg_match('/^[a-f0-9]{64}$/', $state_jti_hash)
        && !hash_equals($state_jti_hash, $jti_hash)
      )
      || (
        $state_target_hash !== ''
        && !hash_equals($state_target_hash, $target_hash)
      )
      || (
        $state_case_id !== ''
        && !hash_equals($state_case_id, $case_id)
      )
    ) {
      return [
        'ok'     => false,
        'reason' => 'state_claim_mismatch',
      ];
    }

    $revoked_at = time();

    $token_hash = hash('sha256', $token);

    $request_id = hash(
      'sha256',
      $token_hash
        . '|'
        . $revoked_at
        . '|'
        . wp_generate_uuid4()
    );

    $payload = [
      'version'     => '1',
      'source'      => 'client',
      'scope'       => $scope,
      'jti_hash'    => $jti_hash,
      'target_hash' => $target_hash,
      'case_id'     => $case_id,
      'revoked_at'  => $revoked_at,
      'request_id'  => $request_id,
    ];

    $canonical =
      custausu_support_diagnostics_client_revoke_canonical_payload(
        $payload
      );

    $payload['proof'] = hash_hmac(
      'sha256',
      $canonical,
      $token_hash
    );

    $payload =
      custausu_support_diagnostics_client_revoke_normalize_payload(
        $payload
      );

    if (empty($payload)) {
      return [
        'ok'     => false,
        'reason' => 'payload_invalid',
      ];
    }

    /*
     * The full token, raw JTI and full-token SHA-256/HMAC key remain in
     * memory only and are never returned inside the queued job.
     */
    $local_state = $state;
    $local_state['jti'] = $jti;
    $local_state['jti_hash'] = $jti_hash;
    $local_state['expires_at'] = $expires_at;

    unset($token_hash, $token, $jti);

    return [
      'ok'          => true,
      'reason'      => 'prepared',
      'local_state' => $local_state,
      'job'         => [
        'schema_version' => 1,
        'endpoint'       => $endpoint,
        'payload'        => $payload,
        'attempts'       => 0,
        'created_at'     => $revoked_at,
        'updated_at'     => $revoked_at,
        'next_attempt_at'=> $revoked_at,
        'last_http_code' => 0,
        'last_reason'    => '',
      ],
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_normalize_job')) {
  function custausu_support_diagnostics_client_revoke_normalize_job(
    array $job
  ): array {
    $endpoint = esc_url_raw(
      (string) ($job['endpoint'] ?? '')
    );

    $payload =
      custausu_support_diagnostics_client_revoke_normalize_payload(
        is_array($job['payload'] ?? null)
          ? $job['payload']
          : []
      );

    if (
      $endpoint === ''
      || empty($payload)
      || !preg_match(
        '~/support-diagnostics/client-revoke/?$~',
        (string) wp_parse_url($endpoint, PHP_URL_PATH)
      )
    ) {
      return [];
    }

    $attempts = max(
      0,
      min(
        custausu_support_diagnostics_client_revoke_max_attempts(),
        absint($job['attempts'] ?? 0)
      )
    );

    $created_at = absint(
      $job['created_at'] ?? $payload['revoked_at']
    );

    $updated_at = absint(
      $job['updated_at'] ?? $created_at
    );

    $next_attempt_at = absint(
      $job['next_attempt_at'] ?? $created_at
    );

    if (
      $created_at <= 0
      || $updated_at <= 0
      || $next_attempt_at <= 0
      || $payload['request_id'] === ''
    ) {
      return [];
    }

    $last_reason = sanitize_key(
      (string) ($job['last_reason'] ?? '')
    );

    return [
      'schema_version' => 1,
      'endpoint'       => $endpoint,
      'payload'        => $payload,
      'attempts'       => $attempts,
      'created_at'     => $created_at,
      'updated_at'     => $updated_at,
      'next_attempt_at'=> $next_attempt_at,
      'last_http_code' => absint(
        $job['last_http_code'] ?? 0
      ),
      'last_reason'    => $last_reason,
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_queue_get')) {
  function custausu_support_diagnostics_client_revoke_queue_get(): array {
    $raw = get_option(
      custausu_support_diagnostics_client_revoke_queue_option_name(),
      []
    );

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

    $clean = [];
    $now = time();
    $max_age = 45 * DAY_IN_SECONDS;

    foreach ($raw as $request_id => $job) {
      $job = is_array($job) ? $job : [];

      $normalized =
        custausu_support_diagnostics_client_revoke_normalize_job(
          $job
        );

      if (empty($normalized)) {
        continue;
      }

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

      $normalized_request_id = (string) (
        $payload['request_id'] ?? ''
      );

      if (
        $normalized_request_id === ''
        || !hash_equals(
          $normalized_request_id,
          strtolower(trim((string) $request_id))
        )
        || (int) $normalized['created_at'] < ($now - $max_age)
      ) {
        continue;
      }

      $clean[$normalized_request_id] = $normalized;
    }

    uasort(
      $clean,
      static function (array $left, array $right): int {
        return ((int) $left['created_at'])
          <=> ((int) $right['created_at']);
      }
    );

    $max_entries =
      custausu_support_diagnostics_client_revoke_queue_max_entries();

    if (count($clean) > $max_entries) {
      $clean = array_slice(
        $clean,
        -$max_entries,
        null,
        true
      );
    }

    if ($clean !== $raw) {
      custausu_support_diagnostics_client_revoke_queue_set(
        $clean
      );
    }

    return $clean;
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_queue_set')) {
  function custausu_support_diagnostics_client_revoke_queue_set(
    array $queue
  ): bool {
    $clean = [];

    foreach ($queue as $request_id => $job) {
      $job = is_array($job) ? $job : [];

      $normalized =
        custausu_support_diagnostics_client_revoke_normalize_job(
          $job
        );

      if (empty($normalized)) {
        continue;
      }

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

      $normalized_request_id = (string) (
        $payload['request_id'] ?? ''
      );

      if (
        $normalized_request_id === ''
        || !hash_equals(
          $normalized_request_id,
          strtolower(trim((string) $request_id))
        )
      ) {
        continue;
      }

      $clean[$normalized_request_id] = $normalized;
    }

    uasort(
      $clean,
      static function (array $left, array $right): int {
        return ((int) $left['created_at'])
          <=> ((int) $right['created_at']);
      }
    );

    $max_entries =
      custausu_support_diagnostics_client_revoke_queue_max_entries();

    if (count($clean) > $max_entries) {
      $clean = array_slice(
        $clean,
        -$max_entries,
        null,
        true
      );
    }

    $option =
      custausu_support_diagnostics_client_revoke_queue_option_name();

    if (empty($clean)) {
      delete_option($option);
      wp_clear_scheduled_hook(
        custausu_support_diagnostics_client_revoke_cron_hook()
      );

      return get_option($option, null) === null;
    }

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

    return get_option($option, []) === $clean;
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_queue_add')) {
  function custausu_support_diagnostics_client_revoke_queue_add(
    array $job
  ): bool {
    $job =
      custausu_support_diagnostics_client_revoke_normalize_job(
        $job
      );

    if (empty($job)) {
      return false;
    }

    $request_id = (string) (
      $job['payload']['request_id'] ?? ''
    );

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

    $queue =
      custausu_support_diagnostics_client_revoke_queue_get();

    $queue[$request_id] = $job;

    $stored =
      custausu_support_diagnostics_client_revoke_queue_set(
        $queue
      );

    if ($stored) {
      custausu_support_diagnostics_client_revoke_schedule_retry();
    }

    return $stored;
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_queue_remove')) {
  function custausu_support_diagnostics_client_revoke_queue_remove(
    string $request_id
  ): void {
    $request_id = strtolower(trim($request_id));

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

    $queue =
      custausu_support_diagnostics_client_revoke_queue_get();

    unset($queue[$request_id]);

    custausu_support_diagnostics_client_revoke_queue_set(
      $queue
    );
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_log')) {
  function custausu_support_diagnostics_client_revoke_log(
    string $status,
    array $context = []
  ): void {
    $status = sanitize_key($status);

    $safe = [
      'status' => $status,
      'reason' => sanitize_key(
        (string) ($context['reason'] ?? '')
      ),
      'request_id_tag' => substr(
        strtolower(
          trim((string) ($context['request_id'] ?? ''))
        ),
        0,
        12
      ),
      'endpoint_host' => strtolower(
        (string) wp_parse_url(
          (string) ($context['endpoint'] ?? ''),
          PHP_URL_HOST
        )
      ),
      'attempts' => absint(
        $context['attempts'] ?? 0
      ),
      'http_code' => absint(
        $context['http_code'] ?? 0
      ),
    ];

    if (function_exists('custausu_log')) {
      custausu_log(
        'support',
        'Support diagnostics client revocation delivery.',
        $safe,
        in_array(
          $status,
          ['delivered', 'queued'],
          true
        )
          ? 'info'
          : 'warn'
      );
    }

    do_action(
      'custausu_support_diagnostics_client_revoke_log',
      $safe
    );
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_deliver')) {
  function custausu_support_diagnostics_client_revoke_deliver(
    array $job
  ): array {
    $job =
      custausu_support_diagnostics_client_revoke_normalize_job(
        $job
      );

    if (empty($job)) {
      return [
        'status'    => 'terminal',
        'reason'    => 'invalid_job',
        'http_code' => 0,
      ];
    }

    $endpoint = (string) $job['endpoint'];
    $payload = (array) $job['payload'];

    if (!function_exists('wp_remote_post')) {
      return [
        'status'    => 'transient',
        'reason'    => 'http_client_unavailable',
        'http_code' => 0,
      ];
    }

    $timeout = (float) apply_filters(
      'custausu_support_diagnostics_client_revoke_http_timeout',
      4.0
    );

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

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

    if (is_wp_error($response)) {
      return [
        'status'    => 'transient',
        'reason'    => 'transport_error',
        'http_code' => 0,
      ];
    }

    $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)
      && !empty($data['ok'])
      && sanitize_key(
        (string) ($data['status'] ?? '')
      ) === 'revoked'
      && !empty($data['request_id'])
      && hash_equals(
        (string) $payload['request_id'],
        strtolower(
          trim((string) $data['request_id'])
        )
      )
    ) {
      return [
        'status'    => 'delivered',
        'reason'    => sanitize_key(
          (string) ($data['reason'] ?? 'client_revoked')
        ),
        'http_code' => $code,
      ];
    }

    if (
      is_wp_error($response)
      || in_array($code, [408, 425, 429], true)
      || $code >= 500
      || (
        $code >= 200
        && $code < 300
        && !is_array($data)
      )
    ) {
      return [
        'status'    => 'transient',
        'reason'    => 'retryable_response',
        'http_code' => $code,
      ];
    }

    return [
      'status'    => 'terminal',
      'reason'    => sanitize_key(
        is_array($data)
          ? (string) (
              $data['reason']
              ?? 'remote_rejected'
            )
          : 'remote_rejected'
      ),
      'http_code' => $code,
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_process_request')) {
  function custausu_support_diagnostics_client_revoke_process_request(
    string $request_id
  ): array {
    $request_id = strtolower(trim($request_id));

    $queue =
      custausu_support_diagnostics_client_revoke_queue_get();

    if (
      !preg_match('/^[a-f0-9]{32,64}$/', $request_id)
      || empty($queue[$request_id])
    ) {
      return [
        'status'    => 'missing',
        'reason'    => 'queue_item_missing',
        'request_id'=> $request_id,
        'attempts'  => 0,
        'http_code' => 0,
      ];
    }

    $job = (array) $queue[$request_id];

    $attempts = absint($job['attempts'] ?? 0) + 1;

    $delivery =
      custausu_support_diagnostics_client_revoke_deliver(
        $job
      );

    $status = sanitize_key(
      (string) ($delivery['status'] ?? 'terminal')
    );

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

    $http_code = absint(
      $delivery['http_code'] ?? 0
    );

    if ($status === 'delivered') {
      unset($queue[$request_id]);

      custausu_support_diagnostics_client_revoke_queue_set(
        $queue
      );

      custausu_support_diagnostics_client_revoke_log(
        'delivered',
        [
          'reason'     => $reason,
          'request_id' => $request_id,
          'endpoint'   => $job['endpoint'] ?? '',
          'attempts'   => $attempts,
          'http_code'  => $http_code,
        ]
      );

      return [
        'status'     => 'delivered',
        'reason'     => $reason,
        'request_id' => $request_id,
        'attempts'   => $attempts,
        'http_code'  => $http_code,
      ];
    }

    $max_attempts =
      custausu_support_diagnostics_client_revoke_max_attempts();

    if (
      $status === 'terminal'
      || $attempts >= $max_attempts
    ) {
      unset($queue[$request_id]);

      custausu_support_diagnostics_client_revoke_queue_set(
        $queue
      );

      custausu_support_diagnostics_client_revoke_log(
        $status === 'terminal'
          ? 'terminal'
          : 'exhausted',
        [
          'reason'     => $reason,
          'request_id' => $request_id,
          'endpoint'   => $job['endpoint'] ?? '',
          'attempts'   => $attempts,
          'http_code'  => $http_code,
        ]
      );

      return [
        'status'     => $status === 'terminal'
          ? 'terminal'
          : 'exhausted',
        'reason'     => $reason,
        'request_id' => $request_id,
        'attempts'   => $attempts,
        'http_code'  => $http_code,
      ];
    }

    $now = time();

    $job['attempts'] = $attempts;
    $job['updated_at'] = $now;
    $job['next_attempt_at'] = $now
      + custausu_support_diagnostics_client_revoke_backoff_seconds(
          $attempts
        );
    $job['last_http_code'] = $http_code;
    $job['last_reason'] = $reason;

    $queue[$request_id] = $job;

    custausu_support_diagnostics_client_revoke_queue_set(
      $queue
    );

    custausu_support_diagnostics_client_revoke_schedule_retry();

    custausu_support_diagnostics_client_revoke_log(
      'queued',
      [
        'reason'     => $reason,
        'request_id' => $request_id,
        'endpoint'   => $job['endpoint'] ?? '',
        'attempts'   => $attempts,
        'http_code'  => $http_code,
      ]
    );

    return [
      'status'     => 'queued',
      'reason'     => $reason,
      'request_id' => $request_id,
      'attempts'   => $attempts,
      'http_code'  => $http_code,
      'next_attempt_at' =>
        (int) $job['next_attempt_at'],
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_schedule_retry')) {
  function custausu_support_diagnostics_client_revoke_schedule_retry(): void {
    $queue =
      custausu_support_diagnostics_client_revoke_queue_get();

    $hook =
      custausu_support_diagnostics_client_revoke_cron_hook();

    if (empty($queue)) {
      wp_clear_scheduled_hook($hook);
      return;
    }

    $next = 0;

    foreach ($queue as $job) {
      $candidate = absint(
        $job['next_attempt_at'] ?? 0
      );

      if (
        $candidate > 0
        && ($next === 0 || $candidate < $next)
      ) {
        $next = $candidate;
      }
    }

    if ($next <= 0) {
      $next = time() + MINUTE_IN_SECONDS;
    }

    $next = max(
      time() + MINUTE_IN_SECONDS,
      $next
    );

    $scheduled = wp_next_scheduled($hook);

    if (
      $scheduled
      && abs((int) $scheduled - $next)
        <= MINUTE_IN_SECONDS
    ) {
      return;
    }

    wp_clear_scheduled_hook($hook);

    wp_schedule_single_event(
      $next,
      $hook
    );
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_process_queue')) {
  function custausu_support_diagnostics_client_revoke_process_queue(): void {
    $lock_key =
      'cas_support_diagnostics_client_revoke_lock';

    if (get_transient($lock_key)) {
      return;
    }

    set_transient(
      $lock_key,
      1,
      2 * MINUTE_IN_SECONDS
    );

    try {
      $queue =
        custausu_support_diagnostics_client_revoke_queue_get();

      $now = time();
      $processed = 0;

      foreach ($queue as $request_id => $job) {
        if ($processed >= 5) {
          break;
        }

        if (
          absint($job['next_attempt_at'] ?? 0)
            > $now
        ) {
          continue;
        }

        custausu_support_diagnostics_client_revoke_process_request(
          (string) $request_id
        );

        $processed++;
      }
    } finally {
      delete_transient($lock_key);
      custausu_support_diagnostics_client_revoke_schedule_retry();
    }
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_maybe_schedule')) {
  function custausu_support_diagnostics_client_revoke_maybe_schedule(): void {
    custausu_support_diagnostics_client_revoke_schedule_retry();
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_unschedule')) {
  function custausu_support_diagnostics_client_revoke_unschedule(): void {
    wp_clear_scheduled_hook(
      custausu_support_diagnostics_client_revoke_cron_hook()
    );
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_dispatch')) {
  function custausu_support_diagnostics_client_revoke_dispatch(
    array $job
  ): array {
    $job =
      custausu_support_diagnostics_client_revoke_normalize_job(
        $job
      );

    if (empty($job)) {
      return [
        'status'    => 'not_prepared',
        'reason'    => 'invalid_job',
        'request_id'=> '',
        'attempts'  => 0,
        'http_code' => 0,
        'queued'    => false,
      ];
    }

    $request_id = (string) (
      $job['payload']['request_id'] ?? ''
    );

    $queued =
      custausu_support_diagnostics_client_revoke_queue_add(
        $job
      );

    if ($queued) {
      $result =
        custausu_support_diagnostics_client_revoke_process_request(
          $request_id
        );

      $result['queued'] =
        $result['status'] === 'queued';

      return $result;
    }

    /*
     * If persistence fails, local revocation remains final. Make one
     * immediate best-effort delivery attempt without retaining secrets.
     */
    $delivery =
      custausu_support_diagnostics_client_revoke_deliver(
        $job
      );

    return [
      'status' => (
        ($delivery['status'] ?? '') === 'delivered'
          ? 'delivered'
          : 'transient_unqueued'
      ),
      'reason' => sanitize_key(
        (string) (
          $delivery['reason']
          ?? 'queue_persist_failed'
        )
      ),
      'request_id' => $request_id,
      'attempts' => 1,
      'http_code' => absint(
        $delivery['http_code'] ?? 0
      ),
      'queued' => false,
    ];
  }
}

if (!function_exists('custausu_support_diagnostics_client_revoke_last_result')) {
  function custausu_support_diagnostics_client_revoke_last_result(): array {
    $result = $GLOBALS[
      'custausu_support_diagnostics_client_revoke_last_result'
    ] ?? [];

    return is_array($result) ? $result : [];
  }
}

add_action(
  'init',
  'custausu_support_diagnostics_client_revoke_maybe_schedule',
  30
);

add_action(
  custausu_support_diagnostics_client_revoke_cron_hook(),
  'custausu_support_diagnostics_client_revoke_process_queue'
);
