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

class ASA_Admin {

	private static function get_empty_report_data() {
		return array(
			'generated_at_gmt' => '',
			'site'             => array(
				'wp_version'       => '',
				'home_url'         => home_url(),
				'php_version'      => PHP_VERSION,
				'server_software'  => isset( $_SERVER['SERVER_SOFTWARE'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '',
				'timezone'         => wp_timezone_string(),
				'is_ssl'           => is_ssl(),
				'uploads_writable' => false,
			),
			'summary'          => array(
				'critical'    => 0,
				'high'        => 0,
				'medium'      => 0,
				'low'         => 0,
				'passed_info' => 0,
			),
			'events'           => array( 'cron_event_count' => 0 ),
			'site_health'      => array( 'count' => 0 ),
			'news'             => array( 'count' => 0 ),
			'inventory'        => array(
				'active_plugins'   => 0,
				'installed_plugins'=> 0,
				'installed_themes' => 0,
				'plugin_updates'   => 0,
			),
			'findings'         => array(),
		);
	}

	private static function get_empty_vulnerability_report_data() {
		return array(
			'generated_at_gmt'        => '',
			'summary'                 => array(),
			'provider_status'         => array(),
			'advisories'              => array(),
			'local_wordpress_findings'=> array(),
			'results'                 => array(),
			'inventory'               => array(),
			'scan_details'            => array(),
			'remote_job_id'           => 0,
			'scan_profile'            => '',
			'request_domain'          => '',
		);
	}

	private static function get_empty_static_report_data() {
		return array(
			'generated_at_gmt'      => '',
			'results'               => array(),
			'findings'              => array(),
			'summary'               => array(),
			'privacy'               => array(),
			'selected_plugins'      => array(),
			'selected_plugin_files' => array(),
			'remote_job_id'         => 0,
			'scan_profile'          => '',
			'request_domain'        => '',
		);
	}

	private static function get_empty_compliance_report_data() {
		return array(
			'compliance_version' => '',
			'generated_at_gmt'   => '',
			'results'            => array(),
			'findings'           => array(),
			'summary'            => array(),
			'privacy'            => array(),
			'remote_job_id'      => 0,
			'scan_profile'       => '',
			'request_domain'     => '',
		);
	}

	private static function get_cached_vulnerability_report_safe() {
		$empty_report = self::get_empty_vulnerability_report_data();
		$report       = get_option( 'asa_cached_vulnerability_report', array() );
		if ( ! is_array( $report ) ) {
			return $empty_report;
		}

		$report['summary'] = isset( $report['summary'] ) && is_array( $report['summary'] ) ? $report['summary'] : array();
		$report['provider_status'] = isset( $report['provider_status'] ) && is_array( $report['provider_status'] ) ? $report['provider_status'] : array();
		$report['advisories'] = isset( $report['advisories'] ) && is_array( $report['advisories'] ) ? $report['advisories'] : array();
		$report['local_wordpress_findings'] = isset( $report['local_wordpress_findings'] ) && is_array( $report['local_wordpress_findings'] ) ? $report['local_wordpress_findings'] : array();
		$report['results'] = isset( $report['results'] ) && is_array( $report['results'] ) ? $report['results'] : array();
		$report['inventory'] = isset( $report['inventory'] ) && is_array( $report['inventory'] ) ? $report['inventory'] : array();
		$report['scan_details'] = isset( $report['scan_details'] ) && is_array( $report['scan_details'] ) ? $report['scan_details'] : array();
		$report['generated_at_gmt'] = isset( $report['generated_at_gmt'] ) ? sanitize_text_field( (string) $report['generated_at_gmt'] ) : '';
		$report['remote_job_id'] = isset( $report['remote_job_id'] ) ? absint( $report['remote_job_id'] ) : 0;
		$report['scan_profile'] = isset( $report['scan_profile'] ) ? sanitize_key( (string) $report['scan_profile'] ) : '';
		$report['request_domain'] = isset( $report['request_domain'] ) ? sanitize_text_field( (string) $report['request_domain'] ) : '';

		return wp_parse_args( $report, $empty_report );
	}

	private static function get_cached_static_report_safe() {
		$empty_report = self::get_empty_static_report_data();
		$report       = get_option( 'asa_cached_static_report', array() );
		if ( ! is_array( $report ) ) {
			return $empty_report;
		}

		$report['results']               = isset( $report['results'] ) && is_array( $report['results'] ) ? $report['results'] : array();
		$report['findings']              = isset( $report['findings'] ) && is_array( $report['findings'] ) ? $report['findings'] : array();
		$report['summary']               = isset( $report['summary'] ) && is_array( $report['summary'] ) ? $report['summary'] : array();
		$report['privacy']               = isset( $report['privacy'] ) && is_array( $report['privacy'] ) ? $report['privacy'] : array();
		$report['selected_plugins']      = isset( $report['selected_plugins'] ) && is_array( $report['selected_plugins'] ) ? $report['selected_plugins'] : array();
		$report['selected_plugin_files'] = isset( $report['selected_plugin_files'] ) && is_array( $report['selected_plugin_files'] ) ? $report['selected_plugin_files'] : array();
		$report['generated_at_gmt']      = isset( $report['generated_at_gmt'] ) ? sanitize_text_field( (string) $report['generated_at_gmt'] ) : '';
		$report['remote_job_id']         = isset( $report['remote_job_id'] ) ? absint( $report['remote_job_id'] ) : 0;
		$report['scan_profile']          = isset( $report['scan_profile'] ) ? sanitize_key( (string) $report['scan_profile'] ) : '';
		$report['request_domain']        = isset( $report['request_domain'] ) ? sanitize_text_field( (string) $report['request_domain'] ) : '';

		return wp_parse_args( $report, $empty_report );
	}

	private static function get_cached_compliance_report_safe() {
		$empty_report = self::get_empty_compliance_report_data();
		$report       = get_option( 'asa_cached_compliance_report', array() );
		if ( ! is_array( $report ) ) {
			return $empty_report;
		}

		$report['results']            = isset( $report['results'] ) && is_array( $report['results'] ) ? $report['results'] : array();
		$report['findings']           = isset( $report['findings'] ) && is_array( $report['findings'] ) ? $report['findings'] : array();
		$report['summary']            = isset( $report['summary'] ) && is_array( $report['summary'] ) ? $report['summary'] : array();
		$report['privacy']            = isset( $report['privacy'] ) && is_array( $report['privacy'] ) ? $report['privacy'] : array();
		$report['compliance_version'] = isset( $report['compliance_version'] ) ? sanitize_text_field( (string) $report['compliance_version'] ) : '';
		$report['generated_at_gmt']   = isset( $report['generated_at_gmt'] ) ? sanitize_text_field( (string) $report['generated_at_gmt'] ) : '';
		$report['remote_job_id']      = isset( $report['remote_job_id'] ) ? absint( $report['remote_job_id'] ) : 0;
		$report['scan_profile']       = isset( $report['scan_profile'] ) ? sanitize_key( (string) $report['scan_profile'] ) : '';
		$report['request_domain']     = isset( $report['request_domain'] ) ? sanitize_text_field( (string) $report['request_domain'] ) : '';

		return wp_parse_args( $report, $empty_report );
	}

	public static function get_cached_vulnerability_report_for_rest() {
		return self::get_cached_vulnerability_report_safe();
	}

	public static function get_cached_static_report_for_rest() {
		return self::get_cached_static_report_safe();
	}

	public static function get_cached_compliance_report_for_rest() {
		return self::get_cached_compliance_report_safe();
	}

	private static function get_cached_report_safe() {
		$empty_report = self::get_empty_report_data();

		if ( ! class_exists( 'ASA_Report_Builder' ) || ! is_callable( array( 'ASA_Report_Builder', 'get_cached_report' ) ) ) {
			return $empty_report;
		}

		try {
			$report = ASA_Report_Builder::get_cached_report();
		} catch ( Throwable $throwable ) {
			return $empty_report;
		}

		if ( ! is_array( $report ) ) {
			return $empty_report;
		}

		$report['site'] = wp_parse_args( isset( $report['site'] ) && is_array( $report['site'] ) ? $report['site'] : array(), $empty_report['site'] );
		$report['summary'] = wp_parse_args( isset( $report['summary'] ) && is_array( $report['summary'] ) ? $report['summary'] : array(), $empty_report['summary'] );
		$report['events'] = wp_parse_args( isset( $report['events'] ) && is_array( $report['events'] ) ? $report['events'] : array(), $empty_report['events'] );
		$report['site_health'] = wp_parse_args( isset( $report['site_health'] ) && is_array( $report['site_health'] ) ? $report['site_health'] : array(), $empty_report['site_health'] );
		$report['news'] = wp_parse_args( isset( $report['news'] ) && is_array( $report['news'] ) ? $report['news'] : array(), $empty_report['news'] );
		$report['inventory'] = wp_parse_args( isset( $report['inventory'] ) && is_array( $report['inventory'] ) ? $report['inventory'] : array(), $empty_report['inventory'] );
		$report['findings'] = isset( $report['findings'] ) && is_array( $report['findings'] ) ? $report['findings'] : array();
		$report['generated_at_gmt'] = isset( $report['generated_at_gmt'] ) ? sanitize_text_field( (string) $report['generated_at_gmt'] ) : '';

		return wp_parse_args( $report, $empty_report );
	}

	public static function activate() {
		add_option( 'asa_security_key', '', '', false );
		add_option( 'asa_agent_connection_status', array(), '', false );
		add_option( 'asa_finding_actions', array(), '', false );
		add_option( 'asa_telemetry_policy', ASA_Telemetry::get_default_policy(), '', false );
		add_option( 'asa_snapshot_diff_history', array(), '', false );
		add_option( 'asa_file_drift_timeline', array(), '', false );
		add_option( 'asa_scan_state', self::get_default_scan_state(), '', false );
		add_option( 'asa_vulnerability_scan_state', self::get_default_vulnerability_scan_state(), '', false );
		add_option( 'asa_static_scan_state', self::get_default_static_scan_state(), '', false );
		add_option( ASA_Logger::OPTION_KEY, array(), '', false );
		add_option( ASA_Logger::RETENTION_OPTION_KEY, ASA_Logger::DEFAULT_RETENTION_DAYS, '', false );
		if ( class_exists( 'ASA_Report_Builder' ) && defined( 'ASA_Report_Builder::REPORT_OPTION' ) && is_callable( array( 'ASA_Report_Builder', 'empty_report' ) ) ) {
			add_option( ASA_Report_Builder::REPORT_OPTION, ASA_Report_Builder::empty_report(), '', false );
		} else {
			add_option( 'asa_cached_report', self::get_empty_report_data(), '', false );
		}
		add_option( 'asa_cached_vulnerability_report', self::get_empty_vulnerability_report_data(), '', false );
		add_option( 'asa_cached_static_report', self::get_empty_static_report_data(), '', false );
		add_option( 'asa_cached_compliance_report', self::get_empty_compliance_report_data(), '', false );
	}

	public function init() {
		add_action( 'admin_menu', array( $this, 'register_menu' ) );
		add_action( 'admin_post_asa_save_key', array( $this, 'handle_save_key' ) );
		add_action( 'admin_post_asa_save_finding_action', array( $this, 'handle_save_finding_action' ) );
		add_action( 'admin_post_asa_save_telemetry_policy', array( $this, 'handle_save_telemetry_policy' ) );
		add_action( 'admin_post_asa_save_log_settings', array( $this, 'handle_save_log_settings' ) );
		add_action( 'admin_post_asa_save_wp_activity_log_settings', array( $this, 'handle_save_wp_activity_log_settings' ) );
		add_action( 'admin_post_asa_manage_scan_queue', array( $this, 'handle_manage_scan_queue' ) );
		add_action( 'admin_post_asa_run_scan', array( $this, 'handle_run_scan' ) );
		add_action( 'admin_post_asa_run_vulnerability_scan', array( $this, 'handle_run_vulnerability_scan' ) );
		add_action( 'asa_run_manual_scan_event', array( __CLASS__, 'run_queued_scan' ) );
		add_action( 'asa_run_manual_vulnerability_scan_event', array( __CLASS__, 'run_queued_vulnerability_scan' ) );
		add_action( 'asa_run_manual_static_scan_event', array( __CLASS__, 'run_queued_static_scan' ) );
		add_action( 'admin_init', array( $this, 'handle_inline_finding_action' ) );
	}

	public function register_menu() {
		add_menu_page(
			__( 'Aegisify Audit Agent', 'aegisify-audit-agent' ),
			__( 'Aegisify Audit Agent', 'aegisify-audit-agent' ),
			'manage_options',
			'aegisify-audit-agent',
			array( $this, 'render_page' ),
			'dashicons-shield-alt',
			59
		);

		add_submenu_page(
			'aegisify-audit-agent',
			__( 'Agent Settings and Logs', 'aegisify-audit-agent' ),
			__( 'Agent Settings and Logs', 'aegisify-audit-agent' ),
			'manage_options',
			'aegisify-audit-agent-logs',
			array( $this, 'render_logs_page' )
		);

		add_submenu_page(
			'aegisify-audit-agent',
			__( 'WordPress Activity Log', 'aegisify-audit-agent' ),
			__( 'WordPress Activity Log', 'aegisify-audit-agent' ),
			'manage_options',
			'aegisify-audit-agent-wp-activity-log',
			array( $this, 'render_wp_activity_log_page' )
		);
	}


	private static function get_scan_queue_definitions() {
		return array(
			'agent' => array(
				'label'         => __( 'Agent Scan Queue', 'aegisify-audit-agent' ),
				'hook'          => 'asa_run_manual_scan_event',
				'state_getter'  => 'get_scan_state',
				'state_updater' => 'update_scan_state',
			),
			'vulnerability' => array(
				'label'         => __( 'Vulnerability Scan Queue', 'aegisify-audit-agent' ),
				'hook'          => 'asa_run_manual_vulnerability_scan_event',
				'state_getter'  => 'get_vulnerability_scan_state',
				'state_updater' => 'update_vulnerability_scan_state',
			),
			'static' => array(
				'label'         => __( 'Static Analysis Queue', 'aegisify-audit-agent' ),
				'hook'          => 'asa_run_manual_static_scan_event',
				'state_getter'  => 'get_static_scan_state',
				'state_updater' => 'update_static_scan_state',
			),
		);
	}

	private static function get_scan_queue_state( $queue_key ) {
		$definitions = self::get_scan_queue_definitions();
		if ( empty( $definitions[ $queue_key ]['state_getter'] ) ) {
			return array();
		}

		$state_getter = $definitions[ $queue_key ]['state_getter'];
		if ( is_callable( array( __CLASS__, $state_getter ) ) ) {
			return call_user_func( array( __CLASS__, $state_getter ) );
		}

		return array();
	}

	private static function update_scan_queue_state( $queue_key, array $state ) {
		$definitions = self::get_scan_queue_definitions();
		if ( empty( $definitions[ $queue_key ]['state_updater'] ) ) {
			return;
		}

		$state_updater = $definitions[ $queue_key ]['state_updater'];
		if ( is_callable( array( __CLASS__, $state_updater ) ) ) {
			call_user_func( array( __CLASS__, $state_updater ), $state );
		}
	}

	private static function get_scan_queue_events( $hook ) {
		$events = array();

		if ( ! function_exists( '_get_cron_array' ) ) {
			$next_scheduled = wp_next_scheduled( $hook );
			if ( $next_scheduled ) {
				$events[] = array(
					'timestamp' => absint( $next_scheduled ),
					'args'      => array(),
				);
			}
			return $events;
		}

		$cron = _get_cron_array();
		if ( empty( $cron ) || ! is_array( $cron ) ) {
			return $events;
		}

		foreach ( $cron as $timestamp => $cron_hooks ) {
			if ( empty( $cron_hooks[ $hook ] ) || ! is_array( $cron_hooks[ $hook ] ) ) {
				continue;
			}

			foreach ( $cron_hooks[ $hook ] as $cron_event ) {
				$events[] = array(
					'timestamp' => absint( $timestamp ),
					'args'      => ! empty( $cron_event['args'] ) && is_array( $cron_event['args'] ) ? $cron_event['args'] : array(),
				);
			}
		}

		usort(
			$events,
			function ( $left, $right ) {
				$left_ts  = isset( $left['timestamp'] ) ? absint( $left['timestamp'] ) : 0;
				$right_ts = isset( $right['timestamp'] ) ? absint( $right['timestamp'] ) : 0;
				if ( $left_ts === $right_ts ) {
					return 0;
				}
				return ( $left_ts < $right_ts ) ? -1 : 1;
			}
		);

		return $events;
	}

	private static function clear_scan_queue_events( $hook, $only_overdue = false ) {
		$events  = self::get_scan_queue_events( $hook );
		$deleted = 0;
		$now     = time();

		foreach ( $events as $event ) {
			$timestamp = ! empty( $event['timestamp'] ) ? absint( $event['timestamp'] ) : 0;
			if ( $only_overdue && $timestamp > $now ) {
				continue;
			}

			$unscheduled = wp_unschedule_event( $timestamp, $hook, ! empty( $event['args'] ) && is_array( $event['args'] ) ? $event['args'] : array() );
			if ( false !== $unscheduled ) {
				$deleted++;
			}
		}

		return $deleted;
	}

	private static function schedule_scan_queue_event( $hook, $delay = 1 ) {
		$hook  = sanitize_key( (string) $hook );
		$delay = max( 1, absint( $delay ) );
		if ( '' === $hook ) {
			return false;
		}

		self::clear_scan_queue_events( $hook, false );
		$scheduled = wp_schedule_single_event( time() + $delay, $hook );
		if ( function_exists( 'spawn_cron' ) ) {
			spawn_cron( time() + $delay );
		}

		return false !== $scheduled;
	}

	private static function is_scan_queue_state_stale( array $state, $hook ) {
		$status = ! empty( $state['status'] ) ? sanitize_key( (string) $state['status'] ) : 'idle';
		if ( ! in_array( $status, array( 'queued', 'running' ), true ) ) {
			return false;
		}

		if ( ! empty( self::get_scan_queue_events( $hook ) ) ) {
			return false;
		}

		if ( 'queued' === $status ) {
			return true;
		}

		$started_at = ! empty( $state['started_at'] ) ? strtotime( (string) $state['started_at'] ) : 0;
		if ( $started_at && ( time() - $started_at ) < ( 5 * MINUTE_IN_SECONDS ) ) {
			return false;
		}

		$requested_at = ! empty( $state['requested_at'] ) ? strtotime( (string) $state['requested_at'] ) : 0;
		if ( ! $started_at && $requested_at && ( time() - $requested_at ) < ( 2 * MINUTE_IN_SECONDS ) ) {
			return false;
		}

		return true;
	}

	private static function get_scan_queue_rows() {
		$definitions = self::get_scan_queue_definitions();
		$rows        = array();
		$now         = time();

		foreach ( $definitions as $queue_key => $definition ) {
			$state           = self::get_scan_queue_state( $queue_key );
			$events          = self::get_scan_queue_events( $definition['hook'] );
			$scheduled_count = count( $events );
			$overdue_count   = 0;
			$next_run_ts     = 0;

			foreach ( $events as $event ) {
				$event_ts = ! empty( $event['timestamp'] ) ? absint( $event['timestamp'] ) : 0;
				if ( $event_ts && ( 0 === $next_run_ts || $event_ts < $next_run_ts ) ) {
					$next_run_ts = $event_ts;
				}
				if ( $event_ts && $event_ts <= $now ) {
					$overdue_count++;
				}
			}

			$status = ! empty( $state['status'] ) ? sanitize_key( (string) $state['status'] ) : 'idle';
			$rows[ $queue_key ] = array(
				'key'             => $queue_key,
				'label'           => $definition['label'],
				'hook'            => $definition['hook'],
				'state'           => is_array( $state ) ? $state : array(),
				'status'          => $status,
				'requested_at'    => ! empty( $state['requested_at'] ) ? sanitize_text_field( (string) $state['requested_at'] ) : '',
				'started_at'      => ! empty( $state['started_at'] ) ? sanitize_text_field( (string) $state['started_at'] ) : '',
				'completed_at'    => ! empty( $state['completed_at'] ) ? sanitize_text_field( (string) $state['completed_at'] ) : '',
				'scheduled_count' => $scheduled_count,
				'overdue_count'   => $overdue_count,
				'next_run_ts'     => $next_run_ts,
				'next_run'        => $next_run_ts ? wp_date( 'Y-m-d H:i:s', $next_run_ts ) : '',
				'is_state_stale'  => in_array( $status, array( 'queued', 'running' ), true ) && 0 === $scheduled_count,
				'remote_job_id'   => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				'request_domain'  => ! empty( $state['request_domain'] ) ? sanitize_text_field( (string) $state['request_domain'] ) : '',
			);
		}

		return $rows;
	}

	public function handle_manage_scan_queue() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		check_admin_referer( 'asa_manage_scan_queue', 'asa_manage_scan_queue_nonce' );

		$queue_key    = isset( $_POST['asa_queue_key'] ) ? sanitize_key( wp_unslash( $_POST['asa_queue_key'] ) ) : '';
		$queue_action = isset( $_POST['asa_queue_action'] ) ? sanitize_key( wp_unslash( $_POST['asa_queue_action'] ) ) : '';
		$definitions  = self::get_scan_queue_definitions();

		if ( empty( $definitions[ $queue_key ] ) || ! in_array( $queue_action, array( 'clear_queue', 'clear_stale', 'reset_state' ), true ) ) {
			wp_safe_redirect( add_query_arg( array( 'page' => 'aegisify-audit-agent-logs', 'asa_log_msg' => 'queue_invalid' ), admin_url( 'admin.php' ) ) );
			exit;
		}

		$queue_definition = $definitions[ $queue_key ];
		$state            = self::get_scan_queue_state( $queue_key );
		$deleted_events   = 0;
		$redirect_msg     = 'queue_updated';

		if ( 'clear_queue' === $queue_action ) {
			$deleted_events = self::clear_scan_queue_events( $queue_definition['hook'], false );
			if ( 'queued' === ( ! empty( $state['status'] ) ? sanitize_key( (string) $state['status'] ) : '' ) ) {
				self::update_scan_queue_state(
					$queue_key,
					array(
						'status'       => 'idle',
						'message'      => __( 'Queued scan was removed from the queue from the Logs page.', 'aegisify-audit-agent' ),
						'completed_at' => current_time( 'mysql' ),
						'last_error'   => '',
					)
				);
			}
			$redirect_msg = 'queue_cleared';
		} elseif ( 'clear_stale' === $queue_action ) {
			$deleted_events = self::clear_scan_queue_events( $queue_definition['hook'], true );
			$events_after   = self::get_scan_queue_events( $queue_definition['hook'] );
			if ( in_array( ! empty( $state['status'] ) ? sanitize_key( (string) $state['status'] ) : '', array( 'queued', 'running' ), true ) && empty( $events_after ) ) {
				self::update_scan_queue_state(
					$queue_key,
					array(
						'status'       => 'idle',
						'message'      => __( 'Stale scan queue state was cleared from the Logs page.', 'aegisify-audit-agent' ),
						'completed_at' => current_time( 'mysql' ),
						'last_error'   => '',
					)
				);
			}
			$redirect_msg = 'queue_stale_cleared';
		} else {
			self::update_scan_queue_state(
				$queue_key,
				array(
					'status'       => 'idle',
					'message'      => __( 'Scan queue state was reset from the Logs page.', 'aegisify-audit-agent' ),
					'completed_at' => current_time( 'mysql' ),
					'last_error'   => '',
				)
			);
			$redirect_msg = 'queue_reset';
		}

		ASA_Logger::log(
			'scan',
			'success',
			'admin',
			'manage_scan_queue',
			__( 'A scan queue management action was executed from the Logs page.', 'aegisify-audit-agent' ),
			array(
				'queue_key'       => $queue_key,
				'queue_action'    => $queue_action,
				'deleted_events'  => $deleted_events,
				'previous_status' => ! empty( $state['status'] ) ? sanitize_key( (string) $state['status'] ) : 'idle',
			),
			10
		);

		wp_safe_redirect(
			add_query_arg(
				array(
					'page'          => 'aegisify-audit-agent-logs',
					'asa_log_msg'   => $redirect_msg,
					'asa_queue_key' => $queue_key,
				),
				admin_url( 'admin.php' )
			)
		);
		exit;
	}

	public function handle_save_key() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}
		check_admin_referer( 'asa_save_key_action', 'asa_save_key_nonce' );
		$key           = isset( $_POST['asa_security_key'] ) ? trim( sanitize_textarea_field( wp_unslash( $_POST['asa_security_key'] ) ) ) : '';
		$key_action    = isset( $_POST['asa_key_submit_action'] ) ? sanitize_key( wp_unslash( $_POST['asa_key_submit_action'] ) ) : 'save';
		$redirect_args = array( 'page' => 'aegisify-audit-agent' );

		ASA_Auth::save_security_key( $key );
		ASA_Logger::log(
			'configuration',
			'success',
			'admin',
			'save_security_key',
			__( 'The agent security key was saved from wp-admin.', 'aegisify-audit-agent' ),
			array(
				'key_present' => '' !== $key,
				'key_action'  => $key_action,
			),
			10
		);

		if ( 'connect' === $key_action ) {
			$status              = ASA_Auth::refresh_connection_status();
			$status['connected'] = ! empty( $status['verified'] );
			update_option( 'asa_agent_connection_status', $status, false );
			ASA_Logger::log(
				'connectivity',
				! empty( $status['verified'] ) ? 'success' : 'error',
				'admin',
				'connect_agent',
				! empty( $status['verified'] ) ? __( 'The agent connection was verified successfully from wp-admin.', 'aegisify-audit-agent' ) : __( 'The agent connection verification failed from wp-admin.', 'aegisify-audit-agent' ),
				array(
					'verified'      => ! empty( $status['verified'] ),
					'checked_at'    => ! empty( $status['checked_at'] ) ? (string) $status['checked_at'] : '',
					'remote'        => ! empty( $status['remote'] ) ? (string) $status['remote'] : '',
					'current_host'  => ! empty( $status['current_host'] ) ? (string) $status['current_host'] : '',
					'verified_host' => ! empty( $status['verified_host'] ) ? (string) $status['verified_host'] : '',
					'message'       => ! empty( $status['message'] ) ? (string) $status['message'] : '',
				),
				10
			);
			$redirect_args['asa_msg'] = ! empty( $status['verified'] ) ? 'connected' : 'connect_failed';
		} elseif ( 'disconnect' === $key_action ) {
			$status = ASA_Auth::get_connection_status();
			if ( ! is_array( $status ) ) {
				$status = array();
			}
			$status['verified']   = false;
			$status['connected']  = false;
			$status['checked_at'] = current_time( 'mysql' );
			$status['message']    = __( 'Agent disconnected from Aegisify Audit SaaS.', 'aegisify-audit-agent' );
			update_option( 'asa_agent_connection_status', $status, false );
			ASA_Logger::log(
				'connectivity',
				'warning',
				'admin',
				'disconnect_agent',
				__( 'The agent was disconnected from wp-admin.', 'aegisify-audit-agent' ),
				array( 'checked_at' => $status['checked_at'] ),
				10
			);
			$redirect_args['asa_msg'] = 'disconnected';
		} else {
			$redirect_args['asa_msg'] = 'saved';
		}

		wp_safe_redirect( add_query_arg( $redirect_args, admin_url( 'admin.php' ) ) );
		exit;
	}


	public function handle_save_telemetry_policy() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		check_admin_referer( 'asa_save_telemetry_policy', 'asa_save_telemetry_policy_nonce' );

		$raw_categories = isset( $_POST['asa_telemetry_categories'] ) && is_array( $_POST['asa_telemetry_categories'] )
			? array_map( 'sanitize_key', wp_unslash( $_POST['asa_telemetry_categories'] ) )
			: array();
		$categories     = array();
		foreach ( ASA_Telemetry::get_category_labels() as $category_key => $label ) {
			$categories[ $category_key ] = in_array( $category_key, $raw_categories, true ) ? 1 : 0;
		}

		ASA_Telemetry::save_policy(
			array(
				'push_enabled' => isset( $_POST['asa_telemetry_push_enabled'] ) ? 1 : 0,
				'categories'   => $categories,
			)
		);

		ASA_Logger::log(
			'configuration',
			'success',
			'admin',
			'save_telemetry_policy',
			__( 'Telemetry access control settings were updated from wp-admin.', 'aegisify-audit-agent' ),
			array(
				'push_enabled'       => isset( $_POST['asa_telemetry_push_enabled'] ) ? 1 : 0,
				'enabled_categories' => count( array_filter( $categories ) ),
			),
			10
		);

		if ( class_exists( 'ASA_WP_Activity_Log' ) ) {
			ASA_WP_Activity_Log::log_event(
				'settings_update',
				__( 'Telemetry access control settings were updated.', 'aegisify-audit-agent' ),
				array(
					'push_enabled'       => isset( $_POST['asa_telemetry_push_enabled'] ) ? 1 : 0,
					'enabled_categories' => count( array_filter( $categories ) ),
				),
				array()
			);
		}

		wp_safe_redirect(
			add_query_arg(
				array(
					'page'    => 'aegisify-audit-agent',
					'asa_msg' => 'telemetry_saved',
				),
				admin_url( 'admin.php' )
			)
		);
		exit;
	}

	public function handle_save_log_settings() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		check_admin_referer( 'asa_save_log_settings', 'asa_save_log_settings_nonce' );

		$previous_retention_days = ASA_Logger::get_retention_days();
		$retention_days          = isset( $_POST['asa_log_retention_days'] ) ? max( 1, absint( wp_unslash( $_POST['asa_log_retention_days'] ) ) ) : ASA_Logger::DEFAULT_RETENTION_DAYS;
		$log_count_before        = count( ASA_Logger::get_logs() );

		update_option( ASA_Logger::RETENTION_OPTION_KEY, $retention_days, false );
		$pruned_logs      = ASA_Logger::prune_expired_logs( $retention_days );
		$log_count_after  = count( $pruned_logs );
		$deleted_entries  = max( 0, $log_count_before - $log_count_after );

		ASA_Logger::log(
			'configuration',
			'success',
			'admin',
			'save_log_settings',
			__( 'Agent log retention settings were updated from wp-admin.', 'aegisify-audit-agent' ),
			array(
				'previous_retention_days' => $previous_retention_days,
				'retention_days'          => $retention_days,
				'deleted_log_entries'     => $deleted_entries,
			),
			10
		);

		if ( class_exists( 'ASA_WP_Activity_Log' ) ) {
			ASA_WP_Activity_Log::log_event(
				'settings_update',
				__( 'Agent log retention settings were updated.', 'aegisify-audit-agent' ),
				array(
					'previous_retention_days' => $previous_retention_days,
					'retention_days'          => $retention_days,
					'deleted_log_entries'     => $deleted_entries,
				),
				array()
			);
		}

		wp_safe_redirect(
			add_query_arg(
				array(
					'page'        => 'aegisify-audit-agent-logs',
					'asa_log_msg' => 'settings_saved',
				),
				admin_url( 'admin.php' )
			)
		);
		exit;
	}

	public function handle_inline_finding_action() {
		if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( ! isset( $_POST['asa_form_action'], $_POST['asa_save_finding_action_nonce'] ) ) {
			return;
		}

		$inline_nonce = sanitize_text_field( wp_unslash( $_POST['asa_save_finding_action_nonce'] ) );
		if ( ! wp_verify_nonce( $inline_nonce, 'asa_save_finding_action' ) ) {
			return;
		}

		$form_action = sanitize_key( wp_unslash( $_POST['asa_form_action'] ) );
		if ( 'save_finding_action' !== $form_action ) {
			return;
		}

		$this->save_finding_action_and_redirect();
	}

	public function handle_save_finding_action() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		$this->save_finding_action_and_redirect();
	}

	private function save_finding_action_and_redirect() {
		check_admin_referer( 'asa_save_finding_action', 'asa_save_finding_action_nonce' );

		$finding_id = isset( $_POST['asa_finding_id'] ) ? sanitize_key( wp_unslash( $_POST['asa_finding_id'] ) ) : '';
		$action     = isset( $_POST['asa_finding_action'] ) ? sanitize_key( wp_unslash( $_POST['asa_finding_action'] ) ) : '';
		$severity   = isset( $_POST['asa_finding_override_severity'] ) ? sanitize_key( wp_unslash( $_POST['asa_finding_override_severity'] ) ) : '';

		$allowed_actions  = array( '', 'ignore', 'escalate', 'remediated', 'delete' );
		$allowed_severity = array( '', 'critical', 'high', 'medium', 'low', 'passed', 'info' );
		$finding_actions  = get_option( 'asa_finding_actions', array() );

		if ( ! in_array( $action, $allowed_actions, true ) ) {
			$action = '';
		}
		if ( ! in_array( $severity, $allowed_severity, true ) ) {
			$severity = '';
		}

		if ( '' !== $finding_id ) {
			if ( 'delete' === $action || ( '' === $action && '' === $severity ) ) {
				unset( $finding_actions[ $finding_id ] );
			} else {
				$finding_actions[ $finding_id ] = array(
					'action'   => $action,
					'severity' => $severity,
				);
			}
			update_option( 'asa_finding_actions', $finding_actions, false );
			ASA_Logger::log(
				'configuration',
				'success',
				'admin',
				'save_finding_action',
				__( 'A finding action override was updated from wp-admin.', 'aegisify-audit-agent' ),
				array(
					'finding_id' => $finding_id,
					'action'     => $action,
					'severity'   => $severity,
				),
				10
			);
		}

		$redirect_args = array(
			'page'                        => 'aegisify-audit-agent',
			'asa_msg'                     => 'finding_saved',
			'asa_sort'                    => isset( $_POST['asa_sort'] ) ? sanitize_key( wp_unslash( $_POST['asa_sort'] ) ) : 'severity',
			'asa_order'                   => isset( $_POST['asa_order'] ) ? sanitize_key( wp_unslash( $_POST['asa_order'] ) ) : 'asc',
			'asa_per_page'                => isset( $_POST['asa_per_page'] ) ? absint( wp_unslash( $_POST['asa_per_page'] ) ) : 25,
			'asa_paged'                   => isset( $_POST['asa_paged'] ) ? max( 1, absint( wp_unslash( $_POST['asa_paged'] ) ) ) : 1,
			'asa_plugin_filter'           => isset( $_POST['asa_plugin_filter'] ) ? sanitize_key( wp_unslash( $_POST['asa_plugin_filter'] ) ) : '',
			'asa_vuln_sort'               => isset( $_POST['asa_vuln_sort'] ) ? sanitize_key( wp_unslash( $_POST['asa_vuln_sort'] ) ) : 'severity',
			'asa_vuln_order'              => isset( $_POST['asa_vuln_order'] ) ? sanitize_key( wp_unslash( $_POST['asa_vuln_order'] ) ) : 'asc',
			'asa_vuln_per_page'           => isset( $_POST['asa_vuln_per_page'] ) ? absint( wp_unslash( $_POST['asa_vuln_per_page'] ) ) : 25,
			'asa_vuln_paged'              => isset( $_POST['asa_vuln_paged'] ) ? max( 1, absint( wp_unslash( $_POST['asa_vuln_paged'] ) ) ) : 1,
			'asa_vuln_component_filter'   => isset( $_POST['asa_vuln_component_filter'] ) ? sanitize_key( wp_unslash( $_POST['asa_vuln_component_filter'] ) ) : '',
		);

		wp_safe_redirect( add_query_arg( $redirect_args, admin_url( 'admin.php' ) ) );
		exit;
	}

	private function get_finding_id( $finding ) {
		return substr( md5( wp_json_encode( array(
			'severity'    => isset( $finding['severity'] ) ? $finding['severity'] : '',
			'plugin_slug' => isset( $finding['plugin_slug'] ) ? $finding['plugin_slug'] : '',
			'category'    => isset( $finding['category'] ) ? $finding['category'] : '',
			'title'       => isset( $finding['title'] ) ? $finding['title'] : '',
			'file_path'   => isset( $finding['file_path'] ) ? $finding['file_path'] : '',
			'line'        => isset( $finding['line'] ) ? absint( $finding['line'] ) : 0,
			'code'        => isset( $finding['code'] ) ? $finding['code'] : '',
			'details'     => isset( $finding['details'] ) ? wp_strip_all_tags( (string) $finding['details'] ) : '',
		) ) ), 0, 16 );
	}

	private function get_effective_severity( $finding, $finding_actions ) {
		$finding_id = $this->get_finding_id( $finding );

		if ( ! empty( $finding_actions[ $finding_id ]['severity'] ) ) {
			return (string) $finding_actions[ $finding_id ]['severity'];
		}

		return isset( $finding['severity'] ) ? (string) $finding['severity'] : '';
	}

	private function get_action_for_finding( $finding, $finding_actions ) {
		$finding_id = $this->get_finding_id( $finding );

		return isset( $finding_actions[ $finding_id ]['action'] ) ? (string) $finding_actions[ $finding_id ]['action'] : '';
	}

	private function get_severity_class( $severity ) {
		$severity = strtolower( (string) $severity );

		if ( ! in_array( $severity, array( 'critical', 'high', 'medium', 'low', 'passed', 'info' ), true ) ) {
			$severity = 'info';
		}

		return 'asa-severity--' . $severity;
	}

	private function sort_findings( $findings, $sort_by, $sort_order, $finding_actions = array() ) {
		$severity_rank = array(
			'critical' => 1,
			'high'     => 2,
			'medium'   => 3,
			'low'      => 4,
			'passed'   => 5,
			'info'     => 6,
		);

		usort(
			$findings,
			function ( $a, $b ) use ( $sort_by, $sort_order, $severity_rank, $finding_actions ) {
				$a_value = isset( $a[ $sort_by ] ) ? (string) $a[ $sort_by ] : '';
				$b_value = isset( $b[ $sort_by ] ) ? (string) $b[ $sort_by ] : '';

				if ( 'severity' === $sort_by ) {
					$a_value = isset( $severity_rank[ strtolower( $this->get_effective_severity( $a, $finding_actions ) ) ] ) ? $severity_rank[ strtolower( $this->get_effective_severity( $a, $finding_actions ) ) ] : 999;
					$b_value = isset( $severity_rank[ strtolower( $this->get_effective_severity( $b, $finding_actions ) ) ] ) ? $severity_rank[ strtolower( $this->get_effective_severity( $b, $finding_actions ) ) ] : 999;
				} elseif ( 'plugin' === $sort_by ) {
					$a_value = strtolower( $this->get_finding_plugin_label( $a ) );
					$b_value = strtolower( $this->get_finding_plugin_label( $b ) );
				} elseif ( 'file_name' === $sort_by ) {
					$a_value = strtolower( $this->get_finding_file_name( $a ) );
					$b_value = strtolower( $this->get_finding_file_name( $b ) );
				} elseif ( 'line' === $sort_by ) {
					$a_value = isset( $a['line'] ) ? absint( $a['line'] ) : 0;
					$b_value = isset( $b['line'] ) ? absint( $b['line'] ) : 0;
				} elseif ( 'type' === $sort_by ) {
					$a_value = strtolower( $this->get_finding_type_label( $a ) );
					$b_value = strtolower( $this->get_finding_type_label( $b ) );
				} elseif ( 'code' === $sort_by ) {
					$a_value = strtolower( isset( $a['code'] ) ? (string) $a['code'] : '' );
					$b_value = strtolower( isset( $b['code'] ) ? (string) $b['code'] : '' );
				}

				if ( $a_value === $b_value ) {
					return 0;
				}

				$result = ( $a_value < $b_value ) ? -1 : 1;

				return ( 'desc' === $sort_order ) ? -$result : $result;
			}
		);

		return $findings;
	}

	private function get_sort_url( $sort_key, $current_sort, $current_order, $per_page, $paged, $plugin_filter = '' ) {
		$order = ( $current_sort === $sort_key && 'asc' === $current_order ) ? 'desc' : 'asc';

		return add_query_arg(
			array(
				'page'               => 'aegisify-audit-agent',
				'asa_sort'           => $sort_key,
				'asa_order'          => $order,
				'asa_per_page'       => $per_page,
				'asa_paged'          => $paged,
				'asa_plugin_filter'  => $plugin_filter,
			),
			admin_url( 'admin.php' )
		);
	}

	private function get_prefixed_sort_url( $prefix, $sort_key, $current_sort, $current_order, $per_page, $paged, $filter_key = '' ) {
		$order = ( $current_sort === $sort_key && 'asc' === $current_order ) ? 'desc' : 'asc';

		return add_query_arg(
			array(
				'page'                        => 'aegisify-audit-agent',
				$prefix . '_sort'             => $sort_key,
				$prefix . '_order'            => $order,
				$prefix . '_per_page'         => $per_page,
				$prefix . '_paged'            => $paged,
				$prefix . '_component_filter' => $filter_key,
			),
			admin_url( 'admin.php' )
		);
	}

	private function build_vulnerability_table_findings( array $report ) {
		$findings   = array();
		$advisories = ! empty( $report['advisories'] ) && is_array( $report['advisories'] ) ? $report['advisories'] : array();
		foreach ( $advisories as $advisory ) {
			if ( ! is_array( $advisory ) ) {
				continue;
			}
			$fixed_versions = ! empty( $advisory['fixed_versions'] ) && is_array( $advisory['fixed_versions'] ) ? array_values( array_filter( array_map( 'sanitize_text_field', $advisory['fixed_versions'] ) ) ) : array();
			$aliases = ! empty( $advisory['aliases'] ) && is_array( $advisory['aliases'] ) ? array_values( array_filter( array_map( 'sanitize_text_field', $advisory['aliases'] ) ) ) : array();
			$component_label = ! empty( $advisory['name'] ) ? sanitize_text_field( (string) $advisory['name'] ) : __( 'WordPress / Site', 'aegisify-audit-agent' );
			$component_slug  = ! empty( $advisory['slug'] ) ? sanitize_key( (string) $advisory['slug'] ) : sanitize_key( strtolower( str_replace( ' ', '-', $component_label ) ) );
			$file_name = '';
			if ( ! empty( $advisory['component_type'] ) ) {
				$file_name = sanitize_key( (string) $advisory['component_type'] );
			}
			if ( ! empty( $advisory['installed_version'] ) ) {
				$file_name .= ( '' !== $file_name ? ' | ' : '' ) . sanitize_text_field( (string) $advisory['installed_version'] );
			}
			if ( ! empty( $fixed_versions ) ) {
				/* translators: Dynamic values are inserted into the translated message. */
				$file_name .= ' | ' . sprintf( __( 'Fixed: %s', 'aegisify-audit-agent' ), implode( ', ', $fixed_versions ) );
			}
			$details = ! empty( $advisory['description'] ) ? wp_strip_all_tags( (string) $advisory['description'] ) : '';
			if ( ! empty( $advisory['cve_id'] ) ) {
				$details = trim( 'CVE: ' . sanitize_text_field( (string) $advisory['cve_id'] ) . '. ' . $details );
			} elseif ( ! empty( $aliases ) ) {
				$details = trim( 'Aliases: ' . implode( ', ', $aliases ) . '. ' . $details );
			}
			if ( ! empty( $fixed_versions ) ) {
				/* translators: Dynamic values are inserted into the translated message. */
				$details .= ' ' . sprintf( __( 'Fixed version(s): %s.', 'aegisify-audit-agent' ), implode( ', ', $fixed_versions ) );
			}
			$findings[] = array(
				'severity'    => ! empty( $advisory['severity_label'] ) ? sanitize_key( (string) $advisory['severity_label'] ) : 'info',
				'plugin_name' => $component_label,
				'plugin_slug' => $component_slug,
				'category'    => 'vulnerability',
				'title'       => ! empty( $advisory['title'] ) ? sanitize_text_field( (string) $advisory['title'] ) : __( 'WPVulnerability advisory', 'aegisify-audit-agent' ),
				'file_name'   => '' !== $file_name ? $file_name : '—',
				'line'        => '',
				'type'        => ! empty( $advisory['api_type'] ) ? sanitize_key( (string) $advisory['api_type'] ) : 'wpvulnerability',
				'code'        => ! empty( $advisory['cve_id'] ) ? sanitize_text_field( (string) $advisory['cve_id'] ) : ( ! empty( $aliases[0] ) ? $aliases[0] : ( ! empty( $advisory['provider_record_id'] ) ? sanitize_text_field( (string) $advisory['provider_record_id'] ) : '—' ) ),
				'details'     => '' !== trim( $details ) ? trim( $details ) : __( 'WPVulnerability API advisory returned without additional description.', 'aegisify-audit-agent' ),
			);
		}

		$local_findings = ! empty( $report['local_wordpress_findings'] ) && is_array( $report['local_wordpress_findings'] ) ? $report['local_wordpress_findings'] : array();
		foreach ( $local_findings as $finding ) {
			if ( ! is_array( $finding ) ) {
				continue;
			}
			$file_name = ! empty( $finding['component_type'] ) ? sanitize_key( (string) $finding['component_type'] ) : '';
			if ( ! empty( $finding['installed_version'] ) ) {
				$file_name .= ( '' !== $file_name ? ' | ' : '' ) . sanitize_text_field( (string) $finding['installed_version'] );
			}
			if ( ! empty( $finding['fixed_version'] ) ) {
				/* translators: Dynamic values are inserted into the translated message. */
				$file_name .= ' | ' . sprintf( __( 'Fixed: %s', 'aegisify-audit-agent' ), sanitize_text_field( (string) $finding['fixed_version'] ) );
			}
			$details = ! empty( $finding['description'] ) ? wp_strip_all_tags( (string) $finding['description'] ) : __( 'The agent identified a local WordPress component risk signal.', 'aegisify-audit-agent' );
			$findings[] = array(
				'severity'    => ! empty( $finding['severity_label'] ) ? sanitize_key( (string) $finding['severity_label'] ) : 'medium',
				'plugin_name' => ! empty( $finding['name'] ) ? sanitize_text_field( (string) $finding['name'] ) : __( 'WordPress / Site', 'aegisify-audit-agent' ),
				'plugin_slug' => ! empty( $finding['slug'] ) ? sanitize_key( (string) $finding['slug'] ) : '',
				'category'    => 'vulnerability',
				'title'       => ! empty( $finding['title'] ) ? sanitize_text_field( (string) $finding['title'] ) : __( 'Agent local WordPress risk signal', 'aegisify-audit-agent' ),
				'file_name'   => '' !== $file_name ? $file_name : '—',
				'line'        => '',
				'type'        => ! empty( $finding['component_type'] ) ? sanitize_key( (string) $finding['component_type'] ) : 'wordpress',
				'code'        => ! empty( $finding['risk_key'] ) ? sanitize_text_field( (string) $finding['risk_key'] ) : '—',
				'details'     => $details,
			);
		}

		if ( ! empty( $findings ) ) {
			return $findings;
		}

		$results = ! empty( $report['results'] ) && is_array( $report['results'] ) ? $report['results'] : array();
		foreach ( $results as $result ) {
			if ( ! is_array( $result ) ) {
				continue;
			}
			$findings[] = array(
				'severity'    => ! empty( $result['severity'] ) ? sanitize_key( (string) $result['severity'] ) : 'info',
				'plugin_name' => __( 'Agent Runtime', 'aegisify-audit-agent' ),
				'plugin_slug' => 'agent-runtime',
				'category'    => ! empty( $result['category'] ) ? sanitize_key( (string) $result['category'] ) : 'vulnerability',
				'title'       => ! empty( $result['title'] ) ? sanitize_text_field( (string) $result['title'] ) : __( 'Vulnerability scan status', 'aegisify-audit-agent' ),
				'file_name'   => '—',
				'line'        => '',
				'type'        => 'agent',
				'code'        => 'status',
				'details'     => ! empty( $result['details'] ) ? wp_strip_all_tags( (string) $result['details'] ) : __( 'The vulnerability scan completed without advisory rows to display.', 'aegisify-audit-agent' ),
			);
		}

		if ( ! empty( $findings ) ) {
			return $findings;
		}

		$provider_statuses = ! empty( $report['provider_status'] ) && is_array( $report['provider_status'] ) ? $report['provider_status'] : array();
		foreach ( $provider_statuses as $provider_key => $provider_status ) {
			if ( ! is_array( $provider_status ) ) {
				continue;
			}
			$findings[] = array(
				'severity'    => in_array( ! empty( $provider_status['status'] ) ? (string) $provider_status['status'] : '', array( 'remote_error', 'error', 'unavailable', 'failed' ), true ) ? 'medium' : 'info',
				'plugin_name' => __( 'Agent Provider', 'aegisify-audit-agent' ),
				'plugin_slug' => sanitize_key( (string) $provider_key ),
				'category'    => 'vulnerability',
				/* translators: Dynamic values are inserted into the translated message. */
				'title'       => sprintf( __( 'Provider status: %s', 'aegisify-audit-agent' ), sanitize_text_field( str_replace( '_', ' ', (string) $provider_key ) ) ),
				'file_name'   => '—',
				'line'        => '',
				'type'        => 'agent',
				'code'        => ! empty( $provider_status['status'] ) ? sanitize_text_field( (string) $provider_status['status'] ) : 'status',
				'details'     => ! empty( $provider_status['details'] ) ? wp_strip_all_tags( (string) $provider_status['details'] ) : __( 'No additional provider status details were returned.', 'aegisify-audit-agent' ),
			);
		}

		return $findings;
	}

	private function get_findings_filter_options( array $findings ) {
		$options = array();
		foreach ( $findings as $finding ) {
			$key = $this->get_finding_plugin_key( $finding );
			if ( '' === $key || ! empty( $options[ $key ] ) ) {
				continue;
			}
			$options[ $key ] = $this->get_finding_plugin_label( $finding );
		}
		asort( $options, SORT_NATURAL | SORT_FLAG_CASE );
		return $options;
	}

	private static function is_remote_static_profile( $scan_profile ) {
		$scan_profile = sanitize_key( (string) $scan_profile );
		return in_array( $scan_profile, array( 'defensive_deep_agent', 'static_code_analysis', 'deep_code_analysis' ), true );
	}

	private static function normalize_scan_request_context( array $request_context = array() ) {
		return array(
			'scan_profile'     => ! empty( $request_context['scan_profile'] ) ? sanitize_key( (string) $request_context['scan_profile'] ) : '',
			'job_id'           => ! empty( $request_context['job_id'] ) ? absint( $request_context['job_id'] ) : 0,
			'domain'           => ! empty( $request_context['domain'] ) ? sanitize_text_field( (string) $request_context['domain'] ) : '',
			'selected_plugins' => ! empty( $request_context['selected_plugins'] ) && is_array( $request_context['selected_plugins'] ) ? self::sanitize_static_selected_plugins( $request_context['selected_plugins'] ) : array(),
		);
	}

	private static function update_static_state_from_manual_scan( array $scan_state, $status = '' ) {
		if ( ! self::is_remote_static_profile( ! empty( $scan_state['scan_profile'] ) ? $scan_state['scan_profile'] : '' ) ) {
			return;
		}

		$static_state = array(
			'status'         => '' !== $status ? sanitize_key( (string) $status ) : ( ! empty( $scan_state['status'] ) ? sanitize_key( (string) $scan_state['status'] ) : 'idle' ),
			'message'        => ! empty( $scan_state['message'] ) ? sanitize_text_field( (string) $scan_state['message'] ) : '',
			'requested_at'   => ! empty( $scan_state['requested_at'] ) ? sanitize_text_field( (string) $scan_state['requested_at'] ) : '',
			'started_at'     => ! empty( $scan_state['started_at'] ) ? sanitize_text_field( (string) $scan_state['started_at'] ) : '',
			'completed_at'   => ! empty( $scan_state['completed_at'] ) ? sanitize_text_field( (string) $scan_state['completed_at'] ) : '',
			'last_error'     => ! empty( $scan_state['last_error'] ) ? sanitize_text_field( (string) $scan_state['last_error'] ) : '',
			'findings_count' => ! empty( $scan_state['findings_count'] ) ? absint( $scan_state['findings_count'] ) : 0,
			'scan_profile'   => ! empty( $scan_state['scan_profile'] ) ? sanitize_key( (string) $scan_state['scan_profile'] ) : '',
			'remote_job_id'  => ! empty( $scan_state['remote_job_id'] ) ? absint( $scan_state['remote_job_id'] ) : 0,
			'request_domain' => ! empty( $scan_state['request_domain'] ) ? sanitize_text_field( (string) $scan_state['request_domain'] ) : '',
			'selected_plugins' => ! empty( $scan_state['selected_plugins'] ) && is_array( $scan_state['selected_plugins'] ) ? self::sanitize_static_selected_plugins( $scan_state['selected_plugins'] ) : array(),
		);
		self::update_static_scan_state( $static_state );
	}

	private static function cache_compliance_report_from_scan_state( array $scan_state ) {
		$scan_profile = ! empty( $scan_state['scan_profile'] ) ? sanitize_key( (string) $scan_state['scan_profile'] ) : '';
		if ( '' === $scan_profile || ! self::is_remote_static_profile( $scan_profile ) ) {
			return array();
		}

		$payload = ( new ASA_Compliance_Scan() )->build_payload( $scan_profile );
		$report  = wp_parse_args(
			array(
				'compliance_version' => ! empty( $payload['compliance_version'] ) ? sanitize_text_field( (string) $payload['compliance_version'] ) : '1.0.0',
				'generated_at_gmt'   => ! empty( $payload['generated_at_gmt'] ) ? sanitize_text_field( (string) $payload['generated_at_gmt'] ) : gmdate( 'Y-m-d H:i:s' ),
				'results'            => ! empty( $payload['results'] ) && is_array( $payload['results'] ) ? $payload['results'] : array(),
				'findings'           => ! empty( $payload['findings'] ) && is_array( $payload['findings'] ) ? $payload['findings'] : array(),
				'summary'            => ! empty( $payload['summary'] ) && is_array( $payload['summary'] ) ? $payload['summary'] : array(),
				'privacy'            => ! empty( $payload['privacy'] ) && is_array( $payload['privacy'] ) ? $payload['privacy'] : array(),
				'remote_job_id'      => ! empty( $scan_state['remote_job_id'] ) ? absint( $scan_state['remote_job_id'] ) : 0,
				'scan_profile'       => $scan_profile,
				'request_domain'     => ! empty( $scan_state['request_domain'] ) ? sanitize_text_field( (string) $scan_state['request_domain'] ) : '',
			),
			self::get_empty_compliance_report_data()
		);
		update_option( 'asa_cached_compliance_report', $report, false );
		return $report;
	}

	private static function reset_manual_scan_cached_reports() {
		if ( class_exists( 'ASA_Report_Builder' ) && is_callable( array( 'ASA_Report_Builder', 'empty_report' ) ) ) {
			update_option( ASA_Report_Builder::REPORT_OPTION, ASA_Report_Builder::empty_report(), false );
		} else {
			update_option( 'asa_cached_report', self::get_empty_report_data(), false );
		}

		update_option( 'asa_cached_static_report', self::get_empty_static_report_data(), false );
		update_option( 'asa_cached_compliance_report', self::get_empty_compliance_report_data(), false );
	}

	private static function cache_static_report_from_full_report( array $report, array $scan_state ) {
		$scan_profile = ! empty( $scan_state['scan_profile'] ) ? sanitize_key( (string) $scan_state['scan_profile'] ) : '';
		if ( '' === $scan_profile || ! self::is_remote_static_profile( $scan_profile ) ) {
			return array();
		}

		$static_report = wp_parse_args(
			array(
				'generated_at_gmt'      => ! empty( $report['generated_at_gmt'] ) ? sanitize_text_field( (string) $report['generated_at_gmt'] ) : gmdate( 'Y-m-d H:i:s' ),
				'results'               => array(),
				'findings'              => ! empty( $report['findings'] ) && is_array( $report['findings'] ) ? $report['findings'] : array(),
				'summary'               => ! empty( $report['summary'] ) && is_array( $report['summary'] ) ? $report['summary'] : array(),
				'privacy'               => array(
					'mode'        => 'metadata_only',
					'description' => 'Static findings were derived from the latest local Scan Now execution and exclude customer content, secrets, tokens, and database row values.',
				),
				'selected_plugins'      => ! empty( $report['scan_filters']['plugins'] ) && is_array( $report['scan_filters']['plugins'] ) ? array_values( array_unique( array_map( 'sanitize_text_field', array_map( 'strval', $report['scan_filters']['plugins'] ) ) ) ) : array(),
				'selected_plugin_files' => ! empty( $report['scan_filters']['plugins'] ) && is_array( $report['scan_filters']['plugins'] ) ? array_values( array_unique( array_map( 'plugin_basename', array_map( 'strval', $report['scan_filters']['plugins'] ) ) ) ) : array(),
				'remote_job_id'         => ! empty( $scan_state['remote_job_id'] ) ? absint( $scan_state['remote_job_id'] ) : 0,
				'scan_profile'          => $scan_profile,
				'request_domain'        => ! empty( $scan_state['request_domain'] ) ? sanitize_text_field( (string) $scan_state['request_domain'] ) : '',
			),
			self::get_empty_static_report_data()
		);
		update_option( 'asa_cached_static_report', $static_report, false );
		return $static_report;
	}

	public static function queue_remote_scan( array $request_context = array() ) {
		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			self::update_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Manual scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			return self::get_scan_state();
		}

		$queue_hook = 'asa_run_manual_scan_event';
		$state      = self::get_scan_state();
		if ( in_array( $state['status'], array( 'queued', 'running' ), true ) ) {
			if ( ! self::is_scan_queue_state_stale( $state, $queue_hook ) ) {
				return $state;
			}

			ASA_Logger::log(
				'scan',
				'warning',
				'rest',
				'queue_remote_scan_stale_recovery',
				__( 'A stale manual Scan Now queue state was detected and is being re-queued.', 'aegisify-audit-agent' ),
				array(
					'status'        => $state['status'],
					'remote_job_id' => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				),
				10
			);
		}

		$context = self::normalize_scan_request_context( $request_context );
		self::update_scan_state( array(
			'status'              => 'queued',
			'message'             => __( 'Manual scan queued from SaaS. Results will be fetched after the agent completes the local scan.', 'aegisify-audit-agent' ),
			'requested_at'        => current_time( 'mysql' ),
			'last_error'          => '',
			'selected_plugins'    => array(),
			'selected_severities' => self::get_default_selected_severities(),
			'scan_profile'        => $context['scan_profile'],
			'remote_job_id'       => $context['job_id'],
			'request_domain'      => $context['domain'],
		) );

		self::update_static_state_from_manual_scan( self::get_scan_state(), 'queued' );
		update_option( 'asa_cached_compliance_report', wp_parse_args( array( 'remote_job_id' => $context['job_id'], 'scan_profile' => $context['scan_profile'], 'request_domain' => $context['domain'] ), self::get_empty_compliance_report_data() ), false );
		update_option( 'asa_cached_static_report', wp_parse_args( array( 'remote_job_id' => $context['job_id'], 'scan_profile' => $context['scan_profile'], 'request_domain' => $context['domain'] ), self::get_empty_static_report_data() ), false );

		self::schedule_scan_queue_event( $queue_hook, 1 );

		ASA_Logger::log(
			'scan',
			'info',
			'rest',
			'queue_remote_scan',
			__( 'A remote manual Scan Now request was queued from SaaS.', 'aegisify-audit-agent' ),
			array(
				'scan_profile' => $context['scan_profile'],
				'job_id'       => $context['job_id'],
			),
			10
		);

		self::run_queued_scan();
		return self::get_scan_state();
	}

	private static function get_default_scan_state() {
		return array(
			'status'              => 'idle',
			'message'             => __( 'No scan has been run yet.', 'aegisify-audit-agent' ),
			'requested_at'        => '',
			'started_at'          => '',
			'completed_at'        => '',
			'last_error'          => '',
			'findings_count'      => 0,
			'selected_plugins'    => array(),
			'selected_severities' => self::get_default_selected_severities(),
			'scan_profile'        => '',
			'remote_job_id'       => 0,
			'request_domain'      => '',
		);
	}

	private static function get_scan_state() {
		$state = get_option( 'asa_scan_state', array() );
		return wp_parse_args( is_array( $state ) ? $state : array(), self::get_default_scan_state() );
	}

	private static function update_scan_state( array $state ) {
		$current = self::get_scan_state();
		update_option( 'asa_scan_state', wp_parse_args( $state, $current ), false );
	}

	public static function get_scan_state_for_rest() {
		return self::get_scan_state();
	}

	private static function get_default_vulnerability_scan_state() {
		return array(
			'status'         => 'idle',
			'message'        => __( 'No vulnerability scan has been run yet.', 'aegisify-audit-agent' ),
			'requested_at'   => '',
			'started_at'     => '',
			'completed_at'   => '',
			'last_error'     => '',
			'findings_count' => 0,
			'scan_profile'   => '',
			'remote_job_id'  => 0,
			'request_domain' => '',
			'selected_plugins' => array(),
		);
	}

	private static function get_vulnerability_scan_state() {
		$state = get_option( 'asa_vulnerability_scan_state', array() );
		return wp_parse_args( is_array( $state ) ? $state : array(), self::get_default_vulnerability_scan_state() );
	}

	private static function update_vulnerability_scan_state( array $state ) {
		$current = self::get_vulnerability_scan_state();
		update_option( 'asa_vulnerability_scan_state', wp_parse_args( $state, $current ), false );
	}

	public static function get_vulnerability_scan_state_for_rest() {
		return self::get_vulnerability_scan_state();
	}

	private static function get_default_static_scan_state() {
		return array(
			'status'         => 'idle',
			'message'        => __( 'No static analysis scan has been run yet.', 'aegisify-audit-agent' ),
			'requested_at'   => '',
			'started_at'     => '',
			'completed_at'   => '',
			'last_error'     => '',
			'findings_count' => 0,
			'scan_profile'   => '',
			'remote_job_id'  => 0,
			'request_domain' => '',
		);
	}

	private static function get_static_scan_state() {
		$state = get_option( 'asa_static_scan_state', array() );
		return wp_parse_args( is_array( $state ) ? $state : array(), self::get_default_static_scan_state() );
	}

	private static function update_static_scan_state( array $state ) {
		$current = self::get_static_scan_state();
		update_option( 'asa_static_scan_state', wp_parse_args( $state, $current ), false );
	}

	public static function get_static_scan_state_for_rest() {
		return self::get_static_scan_state();
	}

	public static function queue_remote_vulnerability_scan( array $request_context = array() ) {
		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			self::update_vulnerability_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Vulnerability scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			return self::get_vulnerability_scan_state();
		}

		$queue_hook = 'asa_run_manual_vulnerability_scan_event';
		$state      = self::get_vulnerability_scan_state();
		if ( in_array( $state['status'], array( 'queued', 'running' ), true ) ) {
			if ( ! self::is_scan_queue_state_stale( $state, $queue_hook ) ) {
				return $state;
			}

			ASA_Logger::log(
				'scan',
				'warning',
				'rest',
				'queue_remote_vulnerability_scan_stale_recovery',
				__( 'A stale vulnerability scan queue state was detected and is being re-queued.', 'aegisify-audit-agent' ),
				array(
					'status'        => $state['status'],
					'remote_job_id' => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				),
				10
			);
		}

		$context = self::normalize_scan_request_context( $request_context );
		update_option(
			'asa_cached_vulnerability_report',
			wp_parse_args(
				array(
					'remote_job_id'  => $context['job_id'],
					'scan_profile'   => $context['scan_profile'],
					'request_domain' => $context['domain'],
				),
				self::get_empty_vulnerability_report_data()
			),
			false
		);

		self::update_vulnerability_scan_state( array(
			'status'         => 'queued',
			'message'        => __( 'Vulnerability scan queued from SaaS. Results will be fetched after the agent completes the local scan.', 'aegisify-audit-agent' ),
			'requested_at'   => current_time( 'mysql' ),
			'last_error'     => '',
			'scan_profile'   => $context['scan_profile'],
			'remote_job_id'  => $context['job_id'],
			'request_domain' => $context['domain'],
		) );

		$queue_hook = 'asa_run_manual_vulnerability_scan_event';
		$state      = self::get_vulnerability_scan_state();
		if ( in_array( $state['status'], array( 'queued', 'running' ), true ) ) {
			if ( ! self::is_scan_queue_state_stale( $state, $queue_hook ) ) {
				return $state;
			}

			ASA_Logger::log(
				'scan',
				'warning',
				'rest',
				'queue_remote_vulnerability_scan_stale_recovery',
				__( 'A stale vulnerability scan queue state was detected and is being re-queued.', 'aegisify-audit-agent' ),
				array(
					'status'        => $state['status'],
					'remote_job_id' => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				),
				10
			);
		}

		$context = self::normalize_scan_request_context( $request_context );

		ASA_Logger::log(
			'scan',
			'info',
			'rest',
			'queue_remote_vulnerability_scan',
			__( 'A remote vulnerability scan was queued from SaaS.', 'aegisify-audit-agent' ),
			array(
				'scan_profile' => $context['scan_profile'],
				'job_id'       => $context['job_id'],
			),
			10
		);

		self::run_queued_vulnerability_scan();
		return self::get_vulnerability_scan_state();
	}

	public static function queue_remote_static_scan( array $request_context = array() ) {
		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			self::update_static_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Static analysis scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			return self::get_static_scan_state();
		}

		$queue_hook = 'asa_run_manual_static_scan_event';
		$state      = self::get_static_scan_state();
		if ( in_array( $state['status'], array( 'queued', 'running' ), true ) ) {
			if ( ! self::is_scan_queue_state_stale( $state, $queue_hook ) ) {
				return $state;
			}

			ASA_Logger::log(
				'scan',
				'warning',
				'rest',
				'queue_remote_static_scan_stale_recovery',
				__( 'A stale static analysis queue state was detected and is being re-queued.', 'aegisify-audit-agent' ),
				array(
					'status'        => $state['status'],
					'remote_job_id' => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				),
				10
			);
		}

		$context = self::normalize_scan_request_context( $request_context );
		update_option(
			'asa_cached_static_report',
			wp_parse_args(
				array(
					'remote_job_id'  => $context['job_id'],
					'scan_profile'   => $context['scan_profile'],
					'request_domain' => $context['domain'],
					'selected_plugin_files' => ! empty( $context['selected_plugins'] ) ? array_values( array_unique( array_map( 'plugin_basename', array_map( 'strval', $context['selected_plugins'] ) ) ) ) : array(),
				),
				self::get_empty_static_report_data()
			),
			false
		);

		self::update_static_scan_state( array(
			'status'         => 'queued',
			'message'        => __( 'Static analysis scan queued from SaaS. Results will be fetched after the agent completes the local scan.', 'aegisify-audit-agent' ),
			'requested_at'   => current_time( 'mysql' ),
			'last_error'     => '',
			'scan_profile'   => $context['scan_profile'],
			'remote_job_id'  => $context['job_id'],
			'request_domain' => $context['domain'],
			'selected_plugins' => ! empty( $context['selected_plugins'] ) ? self::sanitize_static_selected_plugins( $context['selected_plugins'] ) : array(),
		) );

		$queue_hook = 'asa_run_manual_static_scan_event';
		$state      = self::get_static_scan_state();
		if ( in_array( $state['status'], array( 'queued', 'running' ), true ) ) {
			if ( ! self::is_scan_queue_state_stale( $state, $queue_hook ) ) {
				return $state;
			}

			ASA_Logger::log(
				'scan',
				'warning',
				'rest',
				'queue_remote_static_scan_stale_recovery',
				__( 'A stale static analysis queue state was detected and is being re-queued.', 'aegisify-audit-agent' ),
				array(
					'status'        => $state['status'],
					'remote_job_id' => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				),
				10
			);
		}

		$context = self::normalize_scan_request_context( $request_context );

		ASA_Logger::log(
			'scan',
			'info',
			'rest',
			'queue_remote_static_scan',
			__( 'A remote static analysis scan was queued from SaaS.', 'aegisify-audit-agent' ),
			array(
				'scan_profile' => $context['scan_profile'],
				'job_id'       => $context['job_id'],
			),
			10
		);

		self::run_queued_static_scan();
		return self::get_static_scan_state();
	}


	private static function get_default_cached_vulnerability_filters() {
		return array(
			'component_filter'    => '',
			'selected_severities' => self::get_default_selected_severities(),
		);
	}

	private static function get_cached_vulnerability_filters() {
		$filters = get_option( 'asa_cached_vulnerability_filters', array() );
		return wp_parse_args( is_array( $filters ) ? $filters : array(), self::get_default_cached_vulnerability_filters() );
	}

	private static function update_cached_vulnerability_filters( array $filters ) {
		$current = self::get_cached_vulnerability_filters();
		$updated = wp_parse_args( $filters, $current );
		update_option( 'asa_cached_vulnerability_filters', $updated, false );
		return $updated;
	}

	private static function get_default_cached_finding_filters() {
		return array(
			'plugin_filter'       => '',
			'selected_severities' => self::get_default_selected_severities(),
		);
	}

	private static function get_cached_finding_filters() {
		$filters = get_option( 'asa_cached_finding_filters', array() );
		return wp_parse_args( is_array( $filters ) ? $filters : array(), self::get_default_cached_finding_filters() );
	}

	private static function update_cached_finding_filters( array $filters ) {
		$current = self::get_cached_finding_filters();
		$updated = wp_parse_args( $filters, $current );
		update_option( 'asa_cached_finding_filters', $updated, false );
		return $updated;
	}

	private function get_actionable_findings( array $findings ) {
		$actionable = array();
		foreach ( $findings as $finding ) {
			$severity = isset( $finding['severity'] ) ? strtolower( (string) $finding['severity'] ) : '';
			if ( in_array( $severity, array( 'passed', 'info', '' ), true ) ) {
				continue;
			}
			$actionable[] = $finding;
		}
		return $actionable;
	}

	private function get_installed_plugins_list() {
		if ( ! function_exists( 'get_plugins' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}
		$plugins = function_exists( 'get_plugins' ) ? (array) get_plugins() : array();
		$list    = array();
		foreach ( $plugins as $plugin_file => $plugin_data ) {
			$plugin_file = plugin_basename( (string) $plugin_file );
			$list[ $plugin_file ] = ! empty( $plugin_data['Name'] ) ? sanitize_text_field( (string) $plugin_data['Name'] ) : sanitize_text_field( $plugin_file );
		}
		asort( $list, SORT_NATURAL | SORT_FLAG_CASE );
		return $list;
	}

	private function sanitize_selected_plugins( array $selected_plugins ) {
		$allowed   = array_keys( $this->get_installed_plugins_list() );
		$sanitized = array();
		foreach ( $selected_plugins as $plugin_file ) {
			$plugin_file = plugin_basename( sanitize_text_field( (string) $plugin_file ) );
			if ( in_array( $plugin_file, $allowed, true ) ) {
				$sanitized[] = $plugin_file;
			}
		}
		return array_values( array_unique( $sanitized ) );
	}

	private static function sanitize_static_selected_plugins( array $selected_plugins ) {
		$sanitized = array();
		foreach ( $selected_plugins as $plugin_file ) {
			$plugin_file = plugin_basename( sanitize_text_field( (string) $plugin_file ) );
			if ( '' !== $plugin_file ) {
				$sanitized[] = $plugin_file;
			}
		}
		return array_values( array_unique( $sanitized ) );
	}

	private static function get_default_selected_severities() {
		return array( 'critical', 'high', 'medium', 'low' );
	}

	private function sanitize_selected_severities( array $selected_severities ) {
		$allowed = array( 'critical' => true, 'high' => true, 'medium' => true, 'low' => true, 'passed' => true );
		$clean   = array();
		foreach ( $selected_severities as $severity ) {
			$severity = sanitize_key( (string) $severity );
			if ( 'pass' === $severity ) {
				$severity = 'passed';
			}
			if ( isset( $allowed[ $severity ] ) ) {
				$clean[] = $severity;
			}
		}
		$clean = array_values( array_unique( $clean ) );
		return ! empty( $clean ) ? $clean : self::get_default_selected_severities();
	}

	private function get_finding_plugin_label( $finding ) {
		if ( ! empty( $finding['plugin_name'] ) ) {
			return sanitize_text_field( (string) $finding['plugin_name'] );
		}
		if ( ! empty( $finding['plugin_slug'] ) ) {
			return sanitize_text_field( ucwords( str_replace( array( '-', '_' ), ' ', (string) $finding['plugin_slug'] ) ) );
		}
		if ( ! empty( $finding['file_path'] ) ) {
			$file_path = wp_normalize_path( (string) $finding['file_path'] );
			if ( preg_match( '#wp-content/plugins/([^/]+)#', $file_path, $matches ) ) {
				return sanitize_text_field( ucwords( str_replace( array( '-', '_' ), ' ', $matches[1] ) ) );
			}
		}
		return __( 'WordPress / Site', 'aegisify-audit-agent' );
	}

	private function get_finding_plugin_key( $finding ) {
		if ( ! empty( $finding['plugin_slug'] ) ) {
			return sanitize_key( (string) $finding['plugin_slug'] );
		}
		$label = $this->get_finding_plugin_label( $finding );
		return sanitize_key( strtolower( str_replace( ' ', '-', (string) $label ) ) );
	}

	private function get_finding_file_name( $finding ) {
		if ( ! empty( $finding['file_path'] ) ) {
			return sanitize_text_field( (string) $finding['file_path'] );
		}
		if ( ! empty( $finding['file_name'] ) ) {
			return sanitize_text_field( (string) $finding['file_name'] );
		}
		return '—';
	}

	private function get_finding_type_label( $finding ) {
		$type = ! empty( $finding['type'] ) ? strtolower( (string) $finding['type'] ) : '';
		if ( 'error' === $type ) {
			return __( 'Error', 'aegisify-audit-agent' );
		}
		if ( 'warning' === $type ) {
			return __( 'Warning', 'aegisify-audit-agent' );
		}
		$type_map = array(
			'core'         => __( 'Core', 'aegisify-audit-agent' ),
			'plugin'       => __( 'Plugin', 'aegisify-audit-agent' ),
			'theme'        => __( 'Theme', 'aegisify-audit-agent' ),
			'php'          => __( 'PHP', 'aegisify-audit-agent' ),
			'apache'       => __( 'Apache', 'aegisify-audit-agent' ),
			'nginx'        => __( 'Nginx', 'aegisify-audit-agent' ),
			'mariadb'      => __( 'MariaDB', 'aegisify-audit-agent' ),
			'mysql'        => __( 'MySQL', 'aegisify-audit-agent' ),
			'imagemagick'  => __( 'ImageMagick', 'aegisify-audit-agent' ),
			'curl'         => __( 'cURL', 'aegisify-audit-agent' ),
			'memcached'    => __( 'Memcached', 'aegisify-audit-agent' ),
			'redis'        => __( 'Redis', 'aegisify-audit-agent' ),
			'sqlite'       => __( 'SQLite', 'aegisify-audit-agent' ),
			'wpvulnerability' => __( 'WPVulnerability', 'aegisify-audit-agent' ),
		);
		if ( ! empty( $type_map[ $type ] ) ) {
			return $type_map[ $type ];
		}
		return '—';
	}

	private function filter_findings_by_plugin( array $findings, $plugin_filter ) {
		$plugin_filter = sanitize_key( (string) $plugin_filter );
		if ( '' === $plugin_filter ) {
			return $findings;
		}
		return array_values( array_filter(
			$findings,
			function ( $finding ) use ( $plugin_filter ) {
				return $plugin_filter === $this->get_finding_plugin_key( $finding );
			}
		) );
	}

	private function filter_findings_by_severity( array $findings, array $selected_severities ) {
		$selected_severities = $this->sanitize_selected_severities( $selected_severities );
		return array_values( array_filter(
			$findings,
			function ( $finding ) use ( $selected_severities ) {
				$severity = isset( $finding['severity'] ) ? sanitize_key( (string) $finding['severity'] ) : 'info';
				if ( 'pass' === $severity ) {
					$severity = 'passed';
				}
				if ( 'info' === $severity ) {
					return in_array( 'passed', $selected_severities, true );
				}
				return in_array( $severity, $selected_severities, true );
			}
		) );
	}

	public function handle_run_scan() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		check_admin_referer( 'asa_run_scan_action', 'asa_run_scan_nonce' );

		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			ASA_Logger::log(
				'scan',
				'error',
				'admin',
				'queue_manual_scan',
				__( 'A manual scan request was blocked because the agent connection is not verified.', 'aegisify-audit-agent' ),
				array( 'message' => ! empty( $connection_status['message'] ) ? (string) $connection_status['message'] : '' ),
				15
			);
			self::update_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Manual scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			wp_safe_redirect( add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_msg' => 'scan_connection_required' ), admin_url( 'admin.php' ) ) );
			exit;
		}

		$queue_hook = 'asa_run_manual_scan_event';
		$state      = self::get_scan_state();
		if ( in_array( $state['status'], array( 'queued', 'running' ), true ) ) {
			if ( ! self::is_scan_queue_state_stale( $state, $queue_hook ) ) {
				ASA_Logger::log(
					'scan',
					'warning',
					'admin',
					'queue_manual_scan',
					__( 'A manual scan request was ignored because another scan is already queued or running.', 'aegisify-audit-agent' ),
					array( 'status' => $state['status'] ),
					15
				);
				wp_safe_redirect( add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_msg' => 'scan_busy' ), admin_url( 'admin.php' ) ) );
				exit;
			}

			ASA_Logger::log(
				'scan',
				'warning',
				'admin',
				'queue_manual_scan_stale_recovery',
				__( 'A stale manual scan queue state was detected from wp-admin and will be re-queued.', 'aegisify-audit-agent' ),
				array( 'status' => $state['status'] ),
				10
			);
		}

		$requested_plugins = isset( $_POST['asa_scan_plugins'] ) && is_array( $_POST['asa_scan_plugins'] )
			? $this->sanitize_selected_plugins( array_map( 'sanitize_text_field', wp_unslash( $_POST['asa_scan_plugins'] ) ) )
			: array();
		$selected_plugins = array();
		$selected_severities = isset( $_POST['asa_scan_severities'] ) && is_array( $_POST['asa_scan_severities'] )
			? $this->sanitize_selected_severities( array_map( 'sanitize_text_field', wp_unslash( $_POST['asa_scan_severities'] ) ) )
			: self::get_default_selected_severities();

		ASA_Logger::log(
			'scan',
			'info',
			'admin',
			'queue_manual_scan',
			__( 'A manual scan was queued from wp-admin and will run as a full-scope compliance scan.', 'aegisify-audit-agent' ),
			array(
				'requested_plugin_count' => count( $requested_plugins ),
				'full_scope'             => true,
				'selected_severities'    => $selected_severities,
			),
			10
		);

		self::reset_manual_scan_cached_reports();

		self::update_scan_state( array(
			'status'              => 'queued',
			'message'             => __( 'Manual scan queued. A fresh full-scope scan will run in the background.', 'aegisify-audit-agent' ),
			'requested_at'        => current_time( 'mysql' ),
			'last_error'          => '',
			'selected_plugins'    => $selected_plugins,
			'selected_severities' => $selected_severities,
		) );

		self::schedule_scan_queue_event( $queue_hook, 1 );

		wp_safe_redirect( add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_msg' => 'scan_queued' ), admin_url( 'admin.php' ) ) );
		exit;
	}

	public function handle_run_vulnerability_scan() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		check_admin_referer( 'asa_run_vulnerability_scan_action', 'asa_run_vulnerability_scan_nonce' );

		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			ASA_Logger::log(
				'scan',
				'error',
				'admin',
				'queue_manual_vulnerability_scan',
				__( 'A manual vulnerability scan request was blocked because the agent connection is not verified.', 'aegisify-audit-agent' ),
				array( 'message' => ! empty( $connection_status['message'] ) ? (string) $connection_status['message'] : '' ),
				15
			);
			self::update_vulnerability_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Vulnerability scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			wp_safe_redirect( add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_msg' => 'vulnerability_scan_connection_required' ), admin_url( 'admin.php' ) ) );
			exit;
		}

		$queue_hook = 'asa_run_manual_vulnerability_scan_event';
		$state      = self::get_vulnerability_scan_state();
		if ( in_array( $state['status'], array( 'queued', 'running' ), true ) ) {
			if ( ! self::is_scan_queue_state_stale( $state, $queue_hook ) ) {
				ASA_Logger::log(
					'scan',
					'warning',
					'admin',
					'queue_manual_vulnerability_scan',
					__( 'A manual vulnerability scan request was ignored because another vulnerability scan is already queued or running.', 'aegisify-audit-agent' ),
					array( 'status' => $state['status'] ),
					15
				);
				wp_safe_redirect( add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_msg' => 'vulnerability_scan_busy' ), admin_url( 'admin.php' ) ) );
				exit;
			}

			ASA_Logger::log(
				'scan',
				'warning',
				'admin',
				'queue_manual_vulnerability_scan_stale_recovery',
				__( 'A stale vulnerability scan queue state was detected from wp-admin and will be re-queued.', 'aegisify-audit-agent' ),
				array( 'status' => $state['status'] ),
				10
			);
		}

		ASA_Logger::log(
			'scan',
			'info',
			'admin',
			'queue_manual_vulnerability_scan',
			__( 'A manual vulnerability scan was queued from wp-admin.', 'aegisify-audit-agent' ),
			array(),
			10
		);

		self::update_vulnerability_scan_state( array(
			'status'       => 'queued',
			'message'      => __( 'Vulnerability scan queued. Refresh this page in a moment for updated status.', 'aegisify-audit-agent' ),
			'requested_at' => current_time( 'mysql' ),
			'last_error'   => '',
		) );

		self::schedule_scan_queue_event( $queue_hook, 1 );

		self::run_queued_vulnerability_scan();
		$final_state = self::get_vulnerability_scan_state();
		$redirect_msg = 'vulnerability_scan_queued';
		if ( 'completed' === $final_state['status'] ) {
			$redirect_msg = 'vulnerability_scan_completed';
		} elseif ( 'failed' === $final_state['status'] ) {
			$redirect_msg = 'vulnerability_scan_failed';
		}

		wp_safe_redirect( add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_msg' => $redirect_msg ), admin_url( 'admin.php' ) ) );
		exit;
	}

	public static function run_queued_vulnerability_scan() {
		self::clear_scan_queue_events( 'asa_run_manual_vulnerability_scan_event', false );
		$state = self::get_vulnerability_scan_state();
		if ( 'running' === $state['status'] ) {
			ASA_Logger::log(
				'scan',
				'warning',
				'cron',
				'run_queued_vulnerability_scan',
				__( 'A queued vulnerability scan event was skipped because a vulnerability scan is already running.', 'aegisify-audit-agent' ),
				array( 'status' => $state['status'] ),
				30
			);
			return;
		}

		if ( 'queued' !== $state['status'] ) {
			ASA_Logger::log(
				'scan',
				'info',
				'cron',
				'run_queued_vulnerability_scan',
				__( 'A queued vulnerability scan event was ignored because there is no queued vulnerability scan to execute.', 'aegisify-audit-agent' ),
				array( 'status' => $state['status'] ),
				30
			);
			return;
		}

		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			ASA_Logger::log(
				'scan',
				'error',
				'cron',
				'run_queued_vulnerability_scan',
				__( 'A queued vulnerability scan could not start because the agent connection is not verified.', 'aegisify-audit-agent' ),
				array( 'message' => ! empty( $connection_status['message'] ) ? (string) $connection_status['message'] : '' ),
				15
			);
			self::update_vulnerability_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Vulnerability scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'requested_at' => $state['requested_at'],
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			return;
		}

		$started_at = current_time( 'mysql' );
		self::update_vulnerability_scan_state( array(
			'status'       => 'running',
			'message'      => __( 'Vulnerability scan is running in the background.', 'aegisify-audit-agent' ),
			'requested_at' => $state['requested_at'],
			'started_at'   => $started_at,
			'last_error'   => '',
		) );

		try {
			$payload = ( new ASA_Vulnerability_Scan() )->build_payload( ! empty( $state['scan_profile'] ) ? sanitize_key( (string) $state['scan_profile'] ) : 'wpvulnerability_local' );
			$report  = array(
				'generated_at_gmt'         => ! empty( $payload['generated_at_gmt'] ) ? sanitize_text_field( (string) $payload['generated_at_gmt'] ) : gmdate( 'Y-m-d H:i:s' ),
				'summary'                  => ! empty( $payload['summary'] ) && is_array( $payload['summary'] ) ? $payload['summary'] : array(),
				'provider_status'          => ! empty( $payload['provider_status'] ) && is_array( $payload['provider_status'] ) ? $payload['provider_status'] : array(),
				'advisories'               => ! empty( $payload['local_wordpress_advisories'] ) && is_array( $payload['local_wordpress_advisories'] ) ? $payload['local_wordpress_advisories'] : array(),
				'local_wordpress_findings' => ! empty( $payload['local_wordpress_findings'] ) && is_array( $payload['local_wordpress_findings'] ) ? $payload['local_wordpress_findings'] : array(),
				'results'                  => ! empty( $payload['local_wordpress_results'] ) && is_array( $payload['local_wordpress_results'] ) ? $payload['local_wordpress_results'] : array(),
				'inventory'                => ! empty( $payload['inventory'] ) && is_array( $payload['inventory'] ) ? $payload['inventory'] : array(),
				'scan_details'             => ! empty( $payload['scan_details'] ) && is_array( $payload['scan_details'] ) ? $payload['scan_details'] : array(),
				'remote_job_id'            => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				'scan_profile'             => ! empty( $state['scan_profile'] ) ? sanitize_key( (string) $state['scan_profile'] ) : '',
				'request_domain'           => ! empty( $state['request_domain'] ) ? sanitize_text_field( (string) $state['request_domain'] ) : '',
			);
			update_option( 'asa_cached_vulnerability_report', $report, false );
			$advisory_count = ! empty( $report['advisories'] ) && is_array( $report['advisories'] ) ? count( $report['advisories'] ) : 0;
			ASA_Logger::log(
				'scan',
				'success',
				'cron',
				'run_queued_vulnerability_scan',
				__( 'The queued vulnerability scan completed successfully.', 'aegisify-audit-agent' ),
				array(
					'completed_at'   => current_time( 'mysql' ),
					'findings_count' => $advisory_count,
				),
				10
			);
			self::update_vulnerability_scan_state( array(
				'status'         => 'completed',
				'message'        => __( 'Vulnerability scan completed successfully.', 'aegisify-audit-agent' ),
				'requested_at'   => $state['requested_at'],
				'started_at'     => $started_at,
				'completed_at'   => current_time( 'mysql' ),
				'last_error'     => '',
				'findings_count' => $advisory_count,
			) );
		} catch ( Throwable $throwable ) {
			ASA_Logger::log(
				'scan',
				'error',
				'cron',
				'run_queued_vulnerability_scan',
				__( 'The queued vulnerability scan failed with a runtime exception.', 'aegisify-audit-agent' ),
				array( 'message' => $throwable->getMessage() ),
				10
			);
			self::update_vulnerability_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Vulnerability scan failed. Review the last error and try again.', 'aegisify-audit-agent' ),
				'requested_at' => $state['requested_at'],
				'started_at'   => $started_at,
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => sanitize_text_field( $throwable->getMessage() ),
			) );
		}
	}

	public static function run_queued_static_scan() {
		self::clear_scan_queue_events( 'asa_run_manual_static_scan_event', false );
		$state = self::get_static_scan_state();
		if ( 'running' === $state['status'] ) {
			ASA_Logger::log(
				'scan',
				'warning',
				'cron',
				'run_queued_static_scan',
				__( 'A queued static analysis scan event was skipped because a static analysis scan is already running.', 'aegisify-audit-agent' ),
				array( 'status' => $state['status'] ),
				30
			);
			return;
		}

		if ( 'queued' !== $state['status'] ) {
			ASA_Logger::log(
				'scan',
				'info',
				'cron',
				'run_queued_static_scan',
				__( 'A queued static analysis scan event was ignored because there is no queued static analysis scan to execute.', 'aegisify-audit-agent' ),
				array( 'status' => $state['status'] ),
				30
			);
			return;
		}

		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			ASA_Logger::log(
				'scan',
				'error',
				'cron',
				'run_queued_static_scan',
				__( 'A queued static analysis scan could not start because the agent connection is not verified.', 'aegisify-audit-agent' ),
				array( 'message' => ! empty( $connection_status['message'] ) ? (string) $connection_status['message'] : '' ),
				15
			);
			self::update_static_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Static analysis scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'requested_at' => $state['requested_at'],
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			return;
		}

		$started_at = current_time( 'mysql' );
		self::update_static_scan_state( array(
			'status'       => 'running',
			'message'      => __( 'Static analysis scan is running in the background.', 'aegisify-audit-agent' ),
			'requested_at' => $state['requested_at'],
			'started_at'   => $started_at,
			'last_error'   => '',
		) );

		try {
			$payload = ( new ASA_Static_Scan( ! empty( $state['selected_plugins'] ) && is_array( $state['selected_plugins'] ) ? self::sanitize_static_selected_plugins( $state['selected_plugins'] ) : array() ) )->build_payload( ! empty( $state['scan_profile'] ) ? sanitize_key( (string) $state['scan_profile'] ) : '' );
			$report  = array(
				'generated_at_gmt'      => ! empty( $payload['generated_at_gmt'] ) ? sanitize_text_field( (string) $payload['generated_at_gmt'] ) : gmdate( 'Y-m-d H:i:s' ),
				'results'               => ! empty( $payload['results'] ) && is_array( $payload['results'] ) ? $payload['results'] : array(),
				'findings'              => ! empty( $payload['findings'] ) && is_array( $payload['findings'] ) ? $payload['findings'] : array(),
				'summary'               => ! empty( $payload['summary'] ) && is_array( $payload['summary'] ) ? $payload['summary'] : array(),
				'privacy'               => ! empty( $payload['privacy'] ) && is_array( $payload['privacy'] ) ? $payload['privacy'] : array(),
				'selected_plugins'      => ! empty( $state['selected_plugins'] ) && is_array( $state['selected_plugins'] ) ? self::sanitize_static_selected_plugins( $state['selected_plugins'] ) : array(),
				'selected_plugin_files' => ! empty( $state['selected_plugins'] ) && is_array( $state['selected_plugins'] ) ? array_values( array_unique( array_map( 'plugin_basename', array_map( 'strval', $state['selected_plugins'] ) ) ) ) : array(),
				'remote_job_id'         => ! empty( $state['remote_job_id'] ) ? absint( $state['remote_job_id'] ) : 0,
				'scan_profile'          => ! empty( $state['scan_profile'] ) ? sanitize_key( (string) $state['scan_profile'] ) : '',
				'request_domain'        => ! empty( $state['request_domain'] ) ? sanitize_text_field( (string) $state['request_domain'] ) : '',
			);
			update_option( 'asa_cached_static_report', $report, false );
			$findings_count = ! empty( $report['findings'] ) && is_array( $report['findings'] ) ? count( $report['findings'] ) : 0;
			ASA_Logger::log(
				'scan',
				'success',
				'cron',
				'run_queued_static_scan',
				__( 'The queued static analysis scan completed successfully.', 'aegisify-audit-agent' ),
				array(
					'completed_at'   => current_time( 'mysql' ),
					'findings_count' => $findings_count,
				),
				10
			);
			self::update_static_scan_state( array(
				'status'         => 'completed',
				'message'        => __( 'Static analysis scan completed successfully.', 'aegisify-audit-agent' ),
				'requested_at'   => $state['requested_at'],
				'started_at'     => $started_at,
				'completed_at'   => current_time( 'mysql' ),
				'last_error'     => '',
				'findings_count' => $findings_count,
			) );
		} catch ( Throwable $throwable ) {
			ASA_Logger::log(
				'scan',
				'error',
				'cron',
				'run_queued_static_scan',
				__( 'The queued static analysis scan failed with a runtime exception.', 'aegisify-audit-agent' ),
				array( 'message' => $throwable->getMessage() ),
				10
			);
			self::update_static_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Static analysis scan failed. Review the last error and try again.', 'aegisify-audit-agent' ),
				'requested_at' => $state['requested_at'],
				'started_at'   => $started_at,
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => sanitize_text_field( $throwable->getMessage() ),
			) );
		}
	}

	public static function run_queued_scan() {
		self::clear_scan_queue_events( 'asa_run_manual_scan_event', false );
		$state = self::get_scan_state();
		if ( 'running' === $state['status'] ) {
			ASA_Logger::log(
				'scan',
				'warning',
				'cron',
				'run_queued_scan',
				__( 'A queued scan event was skipped because a scan is already running.', 'aegisify-audit-agent' ),
				array( 'status' => $state['status'] ),
				30
			);
			return;
		}

		$connection_status = ASA_Auth::refresh_connection_status();
		if ( empty( $connection_status['verified'] ) ) {
			ASA_Logger::log(
				'scan',
				'error',
				'cron',
				'run_queued_scan',
				__( 'A queued scan could not start because the agent connection is not verified.', 'aegisify-audit-agent' ),
				array( 'message' => ! empty( $connection_status['message'] ) ? (string) $connection_status['message'] : '' ),
				15
			);
			self::update_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Manual scan blocked. An active encrypted and verified SaaS connection is required before scanning can run.', 'aegisify-audit-agent' ),
				'requested_at' => $state['requested_at'],
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => ! empty( $connection_status['message'] ) ? sanitize_text_field( (string) $connection_status['message'] ) : __( 'Aegisify Audit SaaS connection is not active.', 'aegisify-audit-agent' ),
			) );
			self::update_static_state_from_manual_scan( self::get_scan_state(), 'failed' );
			return;
		}

		$started_at = current_time( 'mysql' );
		ASA_Logger::log(
			'scan',
			'info',
			'cron',
			'run_queued_scan',
			__( 'The queued agent scan started running in the background.', 'aegisify-audit-agent' ),
			array(
				'requested_at' => $state['requested_at'],
				'started_at'   => $started_at,
			),
			10
		);

		self::update_scan_state( array(
			'status'       => 'running',
			'message'      => __( 'Manual scan is running in the background.', 'aegisify-audit-agent' ),
			'requested_at' => $state['requested_at'],
			'started_at'   => $started_at,
			'last_error'   => '',
		) );
		self::update_static_state_from_manual_scan( self::get_scan_state(), 'running' );

		if ( ! class_exists( 'ASA_Report_Builder' ) || ! is_callable( array( 'ASA_Report_Builder', 'build' ) ) || ! is_callable( array( 'ASA_Report_Builder', 'cache_report' ) ) ) {
			ASA_Logger::log(
				'scan',
				'error',
				'cron',
				'run_queued_scan',
				__( 'The queued agent scan failed because the report builder is unavailable.', 'aegisify-audit-agent' ),
				array(),
				15
			);
			self::update_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Manual scan failed because the report builder is unavailable.', 'aegisify-audit-agent' ),
				'requested_at' => $state['requested_at'],
				'started_at'   => $started_at,
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => __( 'Report builder unavailable.', 'aegisify-audit-agent' ),
			) );
			self::update_static_state_from_manual_scan( self::get_scan_state(), 'failed' );
			return;
		}

		try {
			$scan_plugins     = ! empty( $state['selected_plugins'] ) && is_array( $state['selected_plugins'] ) ? $state['selected_plugins'] : array();
			$scan_severities  = ! empty( $state['selected_severities'] ) && is_array( $state['selected_severities'] ) ? $state['selected_severities'] : self::get_default_selected_severities();
			$report           = ASA_Report_Builder::build( $scan_plugins, $scan_severities );
			ASA_Report_Builder::cache_report( $report );
			self::cache_static_report_from_full_report( $report, $state );
			self::cache_compliance_report_from_scan_state( $state );
			ASA_Logger::log(
				'scan',
				'success',
				'cron',
				'run_queued_scan',
				__( 'The queued agent scan completed successfully.', 'aegisify-audit-agent' ),
				array(
					'completed_at'   => current_time( 'mysql' ),
					'findings_count' => ! empty( $report['findings'] ) && is_array( $report['findings'] ) ? count( $report['findings'] ) : 0,
				),
				10
			);
			self::update_scan_state( array(
				'status'         => 'completed',
				'message'        => __( 'Manual scan completed successfully.', 'aegisify-audit-agent' ),
				'requested_at'   => $state['requested_at'],
				'started_at'     => $started_at,
				'completed_at'   => current_time( 'mysql' ),
				'last_error'     => '',
				'findings_count' => ! empty( $report['findings'] ) && is_array( $report['findings'] ) ? count( $report['findings'] ) : 0,
			) );
			self::update_static_state_from_manual_scan( self::get_scan_state(), 'completed' );
		} catch ( Throwable $throwable ) {
			ASA_Logger::log(
				'scan',
				'error',
				'cron',
				'run_queued_scan',
				__( 'The queued agent scan failed with a runtime exception.', 'aegisify-audit-agent' ),
				array( 'message' => $throwable->getMessage() ),
				10
			);
			self::update_scan_state( array(
				'status'       => 'failed',
				'message'      => __( 'Manual scan failed. Review the last error and try again.', 'aegisify-audit-agent' ),
				'requested_at' => $state['requested_at'],
				'started_at'   => $started_at,
				'completed_at' => current_time( 'mysql' ),
				'last_error'   => sanitize_text_field( $throwable->getMessage() ),
			) );
			self::update_static_state_from_manual_scan( self::get_scan_state(), 'failed' );
		}
	}

	public function render_page() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		$report             = self::get_cached_report_safe();
		$key                = ASA_Auth::get_security_key();
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only admin UI state for notices, sorting, paging, and filtering.
		$msg                = isset( $_GET['asa_msg'] ) ? sanitize_key( wp_unslash( $_GET['asa_msg'] ) ) : '';
		$connection_status  = ASA_Auth::get_connection_status();
		if ( ! is_array( $connection_status ) || empty( $connection_status ) ) {
			$connection_status = array(
				'verified'   => false,
				'message'    => ! empty( $key ) ? __( 'Encryption key has not been validated yet. Use Connect to verify it against Aegisify Audit SaaS.', 'aegisify-audit-agent' ) : __( 'Encryption key is empty.', 'aegisify-audit-agent' ),
				'checked_at' => current_time( 'mysql' ),
				'remote'     => ASA_Auth::get_remote_host(),
			);
		}
		$telemetry_policy   = ASA_Telemetry::get_policy();
		$telemetry_labels   = ASA_Telemetry::get_category_labels();
		$telemetry_caps     = ASA_Telemetry::get_capabilities();
		$finding_actions    = get_option( 'asa_finding_actions', array() );
		$sort_by            = isset( $_GET['asa_sort'] ) ? sanitize_key( wp_unslash( $_GET['asa_sort'] ) ) : 'severity';
		$sort_order         = isset( $_GET['asa_order'] ) ? sanitize_key( wp_unslash( $_GET['asa_order'] ) ) : 'asc';
		$per_page           = isset( $_GET['asa_per_page'] ) ? absint( wp_unslash( $_GET['asa_per_page'] ) ) : 25;
		$paged              = isset( $_GET['asa_paged'] ) ? max( 1, absint( wp_unslash( $_GET['asa_paged'] ) ) ) : 1;
		$cached_filters     = self::get_cached_finding_filters();
		if ( isset( $_GET['asa_apply_filters'] ) ) {
			$cached_filters = self::update_cached_finding_filters( array(
				'plugin_filter'       => isset( $_GET['asa_plugin_filter'] ) ? sanitize_key( wp_unslash( $_GET['asa_plugin_filter'] ) ) : '',
				'selected_severities' => isset( $_GET['asa_filter_severity'] ) && is_array( $_GET['asa_filter_severity'] )
					? $this->sanitize_selected_severities( array_map( 'sanitize_text_field', wp_unslash( $_GET['asa_filter_severity'] ) ) )
					: self::get_default_selected_severities(),
			) );
		}
		$plugin_filter         = ! empty( $cached_filters['plugin_filter'] ) ? sanitize_key( (string) $cached_filters['plugin_filter'] ) : '';
		$selected_filter_severities = ! empty( $cached_filters['selected_severities'] ) && is_array( $cached_filters['selected_severities'] )
			? $this->sanitize_selected_severities( $cached_filters['selected_severities'] )
			: self::get_default_selected_severities();
		$scan_state            = self::get_scan_state();
		$installed_plugins     = $this->get_installed_plugins_list();
		$selected_scan_plugins = ! empty( $scan_state['selected_plugins'] ) && is_array( $scan_state['selected_plugins'] )
			? $this->sanitize_selected_plugins( $scan_state['selected_plugins'] )
			: array_keys( $installed_plugins );
		$vulnerability_report = self::get_cached_vulnerability_report_safe();
		$vulnerability_scan_state = self::get_vulnerability_scan_state();
		$vulnerability_sort_by = isset( $_GET['asa_vuln_sort'] ) ? sanitize_key( wp_unslash( $_GET['asa_vuln_sort'] ) ) : 'severity';
		$vulnerability_sort_order = isset( $_GET['asa_vuln_order'] ) ? sanitize_key( wp_unslash( $_GET['asa_vuln_order'] ) ) : 'asc';
		$vulnerability_per_page = isset( $_GET['asa_vuln_per_page'] ) ? absint( wp_unslash( $_GET['asa_vuln_per_page'] ) ) : 25;
		$vulnerability_paged = isset( $_GET['asa_vuln_paged'] ) ? max( 1, absint( wp_unslash( $_GET['asa_vuln_paged'] ) ) ) : 1;
		$vulnerability_cached_filters = self::get_cached_vulnerability_filters();
		if ( isset( $_GET['asa_vuln_apply_filters'] ) ) {
			$vulnerability_cached_filters = self::update_cached_vulnerability_filters( array(
				'component_filter'    => isset( $_GET['asa_vuln_component_filter'] ) ? sanitize_key( wp_unslash( $_GET['asa_vuln_component_filter'] ) ) : '',
				'selected_severities' => isset( $_GET['asa_vuln_filter_severity'] ) && is_array( $_GET['asa_vuln_filter_severity'] )
					? $this->sanitize_selected_severities( array_map( 'sanitize_text_field', wp_unslash( $_GET['asa_vuln_filter_severity'] ) ) )
					: self::get_default_selected_severities(),
			) );
		}
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		$vulnerability_component_filter = ! empty( $vulnerability_cached_filters['component_filter'] ) ? sanitize_key( (string) $vulnerability_cached_filters['component_filter'] ) : '';
		$vulnerability_selected_filter_severities = ! empty( $vulnerability_cached_filters['selected_severities'] ) && is_array( $vulnerability_cached_filters['selected_severities'] )
			? $this->sanitize_selected_severities( $vulnerability_cached_filters['selected_severities'] )
			: self::get_default_selected_severities();

		if ( ! in_array( $sort_by, array( 'severity', 'plugin', 'category', 'title', 'file_name', 'line', 'type', 'code' ), true ) ) {
			$sort_by = 'severity';
		}
		if ( ! in_array( $sort_order, array( 'asc', 'desc' ), true ) ) {
			$sort_order = 'asc';
		}
		if ( ! in_array( $per_page, array( 25, 50, 100 ), true ) ) {
			$per_page = 25;
		}
		if ( ! in_array( $vulnerability_sort_by, array( 'severity', 'plugin', 'category', 'title', 'file_name', 'line', 'type', 'code' ), true ) ) {
			$vulnerability_sort_by = 'severity';
		}
		if ( ! in_array( $vulnerability_sort_order, array( 'asc', 'desc' ), true ) ) {
			$vulnerability_sort_order = 'asc';
		}
		if ( ! in_array( $vulnerability_per_page, array( 25, 50, 100 ), true ) ) {
			$vulnerability_per_page = 25;
		}

		$findings = $this->filter_findings_by_severity( is_array( $report['findings'] ) ? $report['findings'] : array(), $selected_filter_severities );
		$findings = $this->filter_findings_by_plugin( $findings, $plugin_filter );
		$findings = $this->sort_findings( $findings, $sort_by, $sort_order, $finding_actions );

		$detailed_findings   = array();
		$escalated_findings  = array();
		$remediated_findings = array();
		foreach ( $findings as $finding ) {
			$stored_action = $this->get_action_for_finding( $finding, $finding_actions );
			if ( 'escalate' === $stored_action ) {
				$escalated_findings[] = $finding;
			} elseif ( 'remediated' === $stored_action ) {
				$remediated_findings[] = $finding;
			} else {
				$detailed_findings[] = $finding;
			}
		}

		$total_items   = count( $detailed_findings );
		$total_pages   = max( 1, (int) ceil( $total_items / $per_page ) );
		$paged         = min( $paged, $total_pages );
		$offset        = ( $paged - 1 ) * $per_page;
		$current_items = array_slice( $detailed_findings, $offset, $per_page );
		$all_vulnerability_findings = $this->build_vulnerability_table_findings( $vulnerability_report );
		$vulnerability_filter_options = $this->get_findings_filter_options( $all_vulnerability_findings );
		$vulnerability_findings = $this->filter_findings_by_severity( $all_vulnerability_findings, $vulnerability_selected_filter_severities );
		$vulnerability_findings = $this->filter_findings_by_plugin( $vulnerability_findings, $vulnerability_component_filter );
		$vulnerability_findings = $this->sort_findings( $vulnerability_findings, $vulnerability_sort_by, $vulnerability_sort_order, $finding_actions );
		$vulnerability_total_items = count( $vulnerability_findings );
		$vulnerability_total_pages = max( 1, (int) ceil( $vulnerability_total_items / $vulnerability_per_page ) );
		$vulnerability_paged = min( $vulnerability_paged, $vulnerability_total_pages );
		$vulnerability_offset = ( $vulnerability_paged - 1 ) * $vulnerability_per_page;
		$current_vulnerability_items = array_slice( $vulnerability_findings, $vulnerability_offset, $vulnerability_per_page );
		?>
		<div class="wrap asa-wrap">
			<h1 class="asa-title asa-title-top">
				<img class="asa-title-logo" src="<?php echo esc_url( ASA_URL . 'assets/aegisifyaudit.png' ); ?>" alt="<?php esc_attr_e( 'Aegisify Audit Agent', 'aegisify-audit-agent' ); ?>" />
				<span class="asa-title-text"><?php esc_html_e( 'Aegisify Audit Agent', 'aegisify-audit-agent' ); ?></span>
			</h1>
			<style>
			.asa-title-logo{height:120px !important;width:auto !important;max-width:100%;vertical-align:middle;margin-right:12px}.asa-wrap h1,.asa-wrap h2,.asa-wrap h3,.asa-wrap h4,.asa-wrap .asa-title-text,.asa-wrap .asa-sort-link{color:#7A0099 !important}.asa-title{margin:0 0 14px;font-size:24px;line-height:1.2;display:flex;align-items:center;gap:12px;flex-wrap:wrap}.asa-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:16px;margin-top:16px}.asa-card{background:#fff;border:1px solid #dcdcde;border-radius:16px;padding:18px;box-shadow:0 8px 24px rgba(0,0,0,.05)}.asa-hero{background:linear-gradient(135deg,#4a005f,#7A0099);color:#fff}.asa-stat{font-size:28px;font-weight:700;margin:6px 0}.asa-pill{display:inline-block;border-radius:999px;padding:4px 10px;background:#eef4ff;margin-right:6px;margin-bottom:6px}.asa-table{width:100%;max-width:100%;border-collapse:collapse;table-layout:fixed}.asa-table th,.asa-table td{padding:10px 12px;border-bottom:1px solid #e5e5e5;text-align:left;vertical-align:top;word-wrap:break-word;overflow-wrap:anywhere}.asa-findings-card{margin-top:28px;padding-top:28px;overflow:hidden}.asa-findings-scroll{width:100%;max-width:100%;overflow-x:hidden}.asa-sort-link{text-decoration:none}.asa-controls{display:flex;justify-content:space-between;align-items:center;gap:12px;flex-wrap:wrap;margin-bottom:16px}.asa-status{display:flex;align-items:center;gap:8px;font-weight:600;margin:10px 0 0}.asa-light{width:12px;height:12px;border-radius:50%;display:inline-block}.asa-light--green{background:#16a34a;box-shadow:0 0 0 3px rgba(22,163,74,.15)}.asa-light--red{background:#dc2626;box-shadow:0 0 0 3px rgba(220,38,38,.15)}.asa-subtle{color:#50575e}.asa-action-wrap{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;align-items:center;width:100%}.asa-action-wrap select{width:100%;min-width:0;max-width:100%}.asa-action-wrap .button{white-space:nowrap}.asa-pagination{display:flex;gap:6px;align-items:center;flex-wrap:wrap;margin-top:16px}.asa-pagination .button.disabled{pointer-events:none;opacity:.55}.asa-escalated-card{margin-top:28px;border-left:4px solid #dc2626}.asa-remediated-card{margin-top:28px;border-left:4px solid #16a34a}.asa-inline-actions{display:flex;gap:10px;align-items:center;flex-wrap:wrap}.asa-inline-actions form{display:inline;margin:0}.asa-text-button{background:none;border:none;padding:0;color:#7A0099;text-decoration:underline;cursor:pointer;font:inherit}.asa-text-separator{color:#7a7a7a}.asa-severity--critical{color:#800020;font-weight:700}.asa-severity--high{color:#dc2626;font-weight:700}.asa-severity--medium{color:#f97316;font-weight:700}.asa-severity--low{color:#eab308;font-weight:700}.asa-severity--passed,.asa-severity--info{color:#16a34a;font-weight:700}.asa-plugin-selector{margin:0 0 14px;padding:12px;border:1px solid #e5e5e5;border-radius:12px;background:#fafafa}.asa-plugin-checkbox-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:8px;max-height:220px;overflow:auto;margin-top:10px}.asa-plugin-checkbox{display:flex;align-items:center;gap:8px}.asa-severity-checkbox-grid{display:flex;flex-wrap:wrap;gap:14px;margin-top:10px}.asa-severity-checkbox{display:flex;align-items:center;gap:8px}.asa-filter-form{display:flex;align-items:center;gap:8px;flex-wrap:wrap}.asa-filter-form select{min-width:220px}.asa-findings-table{width:100%;max-width:100%;table-layout:fixed}.asa-findings-table th,.asa-findings-table td{font-size:12px;padding:8px 10px}.asa-findings-table th:nth-child(1){width:7%}.asa-findings-table th:nth-child(2){width:11%}.asa-findings-table th:nth-child(3){width:9%}.asa-findings-table th:nth-child(4){width:13%}.asa-findings-table th:nth-child(5){width:16%}.asa-findings-table th:nth-child(6){width:5%}.asa-findings-table th:nth-child(7){width:6%}.asa-findings-table th:nth-child(8){width:11%}.asa-findings-table th:nth-child(9){width:14%}.asa-findings-table th:nth-child(10){width:8%}.asa-findings-table td code{font-size:11px;word-break:break-word}@media (max-width:1200px){.asa-action-wrap{grid-template-columns:1fr}.asa-action-wrap .button{width:100%}}
			</style>
			<?php if ( 'saved' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Encryption key saved.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'connected' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Agent connected to Aegisify Audit SaaS successfully.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'connect_failed' === $msg ) : ?><div class="notice notice-warning"><p><?php esc_html_e( 'Connection attempt completed, but the agent could not be verified yet.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'disconnected' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Agent disconnected from Aegisify Audit SaaS.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'finding_saved' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Finding action updated.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'telemetry_saved' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Telemetry access policy saved.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'scan_queued' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Manual scan queued and moved to the background.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'scan_busy' === $msg ) : ?><div class="notice notice-warning"><p><?php esc_html_e( 'A manual scan is already queued or running.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'scan_connection_required' === $msg ) : ?><div class="notice notice-warning"><p><?php esc_html_e( 'An active encrypted and verified SaaS connection is required before Scan Now can run.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'vulnerability_scan_queued' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Vulnerability scan queued and moved to the background.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'vulnerability_scan_completed' === $msg ) : ?><div class="notice notice-success"><p><?php esc_html_e( 'Vulnerability scan completed successfully and the latest results were cached on the agent.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'vulnerability_scan_failed' === $msg ) : ?><div class="notice notice-warning"><p><?php esc_html_e( 'Vulnerability scan failed. Review the last error shown in the Vulnerabilities card.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'vulnerability_scan_busy' === $msg ) : ?><div class="notice notice-warning"><p><?php esc_html_e( 'A vulnerability scan is already queued or running.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<?php if ( 'vulnerability_scan_connection_required' === $msg ) : ?><div class="notice notice-warning"><p><?php esc_html_e( 'An active encrypted and verified SaaS connection is required before the vulnerability scan can run.', 'aegisify-audit-agent' ); ?></p></div><?php endif; ?>
			<div class="asa-card asa-hero">
				<h2 style="color:#fff !important;margin-top:0"><?php esc_html_e( 'Secure this agent before connecting it to Aegisify Audit SaaS', 'aegisify-audit-agent' ); ?></h2>
				<p><?php esc_html_e( 'Enter the long encryption / security key from the Aegisify Audit dashboard Agent Details panel. This agent only validates SaaS connections for aegisify.com over SSL, and the local domain must already be verified in the Aegisify Audit dashboard before remote access is allowed.', 'aegisify-audit-agent' ); ?></p>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
					<input type="hidden" name="action" value="asa_save_key" />
					<?php wp_nonce_field( 'asa_save_key_action', 'asa_save_key_nonce' ); ?>
					<textarea name="asa_security_key" rows="4" class="large-text code" placeholder="Paste the encryption key from Aegisify Audit" required><?php echo esc_textarea( $key ); ?></textarea>
					<p class="asa-action-wrap">
						<button class="button button-primary" type="submit" name="asa_key_submit_action" value="save"><?php esc_html_e( 'Save Encryption Key', 'aegisify-audit-agent' ); ?></button>
						<button class="button" type="submit" name="asa_key_submit_action" value="<?php echo ! empty( $connection_status['verified'] ) ? 'disconnect' : 'connect'; ?>"><?php echo ! empty( $connection_status['verified'] ) ? esc_html__( 'Disconnect', 'aegisify-audit-agent' ) : esc_html__( 'Connect', 'aegisify-audit-agent' ); ?></button>
					</p>
				</form>
				<div class="asa-status">
					<span class="asa-light <?php echo ! empty( $connection_status['verified'] ) ? 'asa-light--green' : 'asa-light--red'; ?>"></span>
					<span><?php echo esc_html( ! empty( $connection_status['message'] ) ? $connection_status['message'] : __( 'Awaiting connection validation.', 'aegisify-audit-agent' ) ); ?></span>
				</div>
				<p class="asa-subtle" style="margin:8px 0 0;">
					<?php
					/* translators: %s: locally saved agent key fingerprint. */
					echo esc_html( sprintf( __( 'Saved key fingerprint: %s', 'aegisify-audit-agent' ), ASA_Auth::get_security_key_fingerprint() ) );
					?>
				</p>
				<p class="asa-subtle" style="color:#dbeafe;margin-bottom:0;">
					<?php
					/* translators: 1: Remote SaaS destination URL, 2: Current site home URL. */
					echo esc_html( sprintf( __( 'Destination: %1$s | Domain: %2$s', 'aegisify-audit-agent' ), ASA_Auth::get_remote_host(), home_url() ) );
					?>
				</p>
			</div>
			<div class="asa-card" style="margin-top:16px;">
				<h2 style="margin-top:0;"><?php esc_html_e( 'Telemetry Access Control', 'aegisify-audit-agent' ); ?></h2>
				<p><?php esc_html_e( 'This agent can expose metadata-only defensive telemetry to Aegisify Audit SaaS, and the optional authenticated log-fetch routes you allow below. Metadata categories do not transmit customer content. Optional log-fetch routes can return sanitized log data already recorded by this site. Raw database row content, secrets, tokens, and API keys are not included.', 'aegisify-audit-agent' ); ?></p>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
					<input type="hidden" name="action" value="asa_save_telemetry_policy" />
					<?php wp_nonce_field( 'asa_save_telemetry_policy', 'asa_save_telemetry_policy_nonce' ); ?>
					<p>
						<label>
							<input type="checkbox" name="asa_telemetry_push_enabled" value="1" <?php checked( ! empty( $telemetry_policy['push_enabled'] ) ); ?> />
							<strong><?php esc_html_e( 'Allow metadata-only telemetry push to Aegisify Audit SaaS', 'aegisify-audit-agent' ); ?></strong>
						</label>
					</p>
					<table class="asa-table"><thead><tr><th style="width:35%;"><?php esc_html_e( 'Telemetry Category', 'aegisify-audit-agent' ); ?></th><th style="width:15%;"><?php esc_html_e( 'Allow', 'aegisify-audit-agent' ); ?></th><th style="width:50%;"><?php esc_html_e( 'Notes', 'aegisify-audit-agent' ); ?></th></tr></thead><tbody>
						<?php foreach ( $telemetry_labels as $telemetry_key => $telemetry_label ) : ?>
						<tr>
							<td><?php echo esc_html( $telemetry_label ); ?></td>
							<td><label><input type="checkbox" name="asa_telemetry_categories[]" value="<?php echo esc_attr( $telemetry_key ); ?>" <?php checked( ! empty( $telemetry_policy['categories'][ $telemetry_key ] ) ); ?> /></label></td>
							<td>
								<?php
								switch ( $telemetry_key ) {
									case 'plugin_theme_core_versions':
										esc_html_e( 'Returns installed plugin, theme, and core version metadata plus update state only.', 'aegisify-audit-agent' );
										break;
									case 'integrity_hashes':
										esc_html_e( 'Returns SHA-256 hashes of core landmark files, plugin entry files, and theme style.css files only.', 'aegisify-audit-agent' );
										break;
									case 'admin_user_inventory':
										esc_html_e( 'Returns counts by role and privileged account inventory only. No usernames or emails are sent.', 'aegisify-audit-agent' );
										break;
									case 'cron_event_inventory':
										esc_html_e( 'Returns scheduled hook names, recurrence, next run time, and argument count only. No argument values are sent.', 'aegisify-audit-agent' );
										break;
									case 'backup_restore_telemetry':
										esc_html_e( 'Returns backup plugin detection, artifact counts, latest backup time, and restore markers only.', 'aegisify-audit-agent' );
										break;
									case 'snapshot_diffs':
										esc_html_e( 'Returns metadata-only diffs of plugin versions, theme versions, role counts, privileged states, and cron counts over time.', 'aegisify-audit-agent' );
										break;
									case 'file_drift_timeline':
										esc_html_e( 'Returns file add/change/remove timeline entries with relative paths and hashes only.', 'aegisify-audit-agent' );
										break;
									case 'privileged_config_states':
										esc_html_e( 'Returns booleans and safe option states for privileged security-related configuration only.', 'aegisify-audit-agent' );
										break;
									case 'debug_log_fetch':
										esc_html_e( 'Allows the authenticated SaaS to fetch wp-content/debug.log on demand through the Agent REST route, and optionally delete it after a successful fetch so WordPress can regenerate a fresh log.', 'aegisify-audit-agent' );
										break;
									case 'file_log_fetch':
										esc_html_e( 'Allows the authenticated SaaS to fetch readable log-like files from inside wp-content, including Aegisify flat files under wp-content/aegisify-logs. Requests outside wp-content are blocked.', 'aegisify-audit-agent' );
										break;
									case 'wp_activity_log_fetch':
										esc_html_e( 'Allows the authenticated SaaS to fetch the Agent WordPress Activity Log events and sensor definitions through the activity-log route. The response is limited to the sanitized activity entries already recorded by this Agent.', 'aegisify-audit-agent' );
										break;
								}
								?>
							</td>
						</tr>
						<?php endforeach; ?>
					</tbody></table>
					<p class="asa-action-wrap">
						<button class="button button-primary" type="submit"><?php esc_html_e( 'Save Telemetry Policy', 'aegisify-audit-agent' ); ?></button>
					</p>
				</form>
				<?php /* translators: 1: Whether telemetry push is enabled, 2: Number of allowed categories, 3: Number of blocked categories. */ ?>
				<p class="asa-subtle" style="margin-bottom:0;"><?php echo esc_html( sprintf( __( 'Push Enabled: %1$s | Allowed Categories: %2$d | Blocked Categories: %3$d', 'aegisify-audit-agent' ), ! empty( $telemetry_caps['push_enabled'] ) ? esc_html__( 'Yes', 'aegisify-audit-agent' ) : esc_html__( 'No', 'aegisify-audit-agent' ), count( $telemetry_caps['allowed_categories'] ), count( $telemetry_caps['blocked_categories'] ) ) ); ?></p>
			</div>
			<div class="asa-grid">
				<div class="asa-card"><h3><?php esc_html_e( 'WordPress Installed', 'aegisify-audit-agent' ); ?></h3><div class="asa-stat"><?php echo esc_html( $report['site']['wp_version'] ); ?></div><p><?php echo esc_html( $report['site']['home_url'] ); ?></p><span class="asa-pill"><?php echo esc_html( $report['site']['php_version'] ); ?></span><span class="asa-pill"><?php echo esc_html( $report['site']['server_software'] ); ?></span></div>
				<div class="asa-card">
					<h3><?php esc_html_e( 'Security Overview', 'aegisify-audit-agent' ); ?></h3>
					<div class="asa-stat"><?php echo esc_html( $report['summary']['critical'] ); ?></div>
					<p><?php esc_html_e( 'Critical findings currently detected.', 'aegisify-audit-agent' ); ?></p>
					<p>
						<?php /* translators: 1: High findings count, 2: Medium findings count, 3: Low findings count, 4: Passed or informational findings count. */ ?>
						<?php echo esc_html( sprintf( __( 'High: %1$d | Medium: %2$d | Low: %3$d | Passed/Info: %4$d', 'aegisify-audit-agent' ), $report['summary']['high'], $report['summary']['medium'], $report['summary']['low'], $report['summary']['passed_info'] ) ); ?>
					</p>
				</div>
				<div class="asa-card">
					<h3><?php esc_html_e( 'Site Health / Events / News', 'aegisify-audit-agent' ); ?></h3>
					<div class="asa-stat"><?php echo esc_html( $report['events']['cron_event_count'] ); ?></div>
					<p><?php esc_html_e( 'Scheduled WordPress events detected.', 'aegisify-audit-agent' ); ?></p>
					<p>
						<?php /* translators: 1: Site Health direct checks count, 2: News items count. */ ?>
						<?php echo esc_html( sprintf( __( 'Site Health direct checks: %1$d | News items: %2$d', 'aegisify-audit-agent' ), $report['site_health']['count'], $report['news']['count'] ) ); ?>
					</p>
				</div>
			</div>
			<div class="asa-grid">
				<div class="asa-card"><h3><?php esc_html_e( 'Current Settings', 'aegisify-audit-agent' ); ?></h3><table class="asa-table"><tbody>
					<tr><th>SSL</th><td><?php echo esc_html( $report['site']['is_ssl'] ? 'Enabled' : 'Disabled' ); ?></td></tr>
					<tr><th>Multisite</th><td><?php echo esc_html( is_multisite() ? 'Yes' : 'No' ); ?></td></tr>
					<tr><th>Timezone</th><td><?php echo esc_html( $report['site']['timezone'] ); ?></td></tr>
					<tr><th>Uploads writable</th><td><?php echo esc_html( $report['site']['uploads_writable'] ? 'Yes' : 'No' ); ?></td></tr>
					<tr><th>Last seen</th><td><?php echo esc_html( (string) get_option( 'asa_last_seen_at', 'Never' ) ); ?></td></tr>
				</tbody></table></div>
				<div class="asa-card"><h3><?php esc_html_e( 'Plugins / Themes', 'aegisify-audit-agent' ); ?></h3><table class="asa-table"><tbody><tr><th>Active plugins</th><td><?php echo esc_html( $report['inventory']['active_plugins'] ); ?></td></tr><tr><th>Installed plugins</th><td><?php echo esc_html( $report['inventory']['installed_plugins'] ); ?></td></tr><tr><th>Installed themes</th><td><?php echo esc_html( $report['inventory']['installed_themes'] ); ?></td></tr><tr><th>Plugins needing updates</th><td><?php echo esc_html( $report['inventory']['plugin_updates'] ); ?></td></tr></tbody></table></div>
			</div>

			<?php if ( ! empty( $escalated_findings ) ) : ?>
			<div class="asa-card asa-escalated-card">
				<h3><?php esc_html_e( 'Escalated Findings', 'aegisify-audit-agent' ); ?></h3>
				<?php /* translators: %d: Number of escalated findings. */ ?>
				<p class="asa-subtle"><?php echo esc_html( sprintf( __( '%d findings have been escalated for follow-up remediation.', 'aegisify-audit-agent' ), count( $escalated_findings ) ) ); ?></p>
				<table class="asa-table">
					<thead>
						<tr>
							<th style="width:10%;"><?php esc_html_e( 'Severity', 'aegisify-audit-agent' ); ?></th>
							<th style="width:10%;"><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></th>
							<th style="width:20%;"><?php esc_html_e( 'Title', 'aegisify-audit-agent' ); ?></th>
							<th style="width:40%;"><?php esc_html_e( 'Details', 'aegisify-audit-agent' ); ?></th>
							<th style="width:20%;"><?php esc_html_e( 'Actions', 'aegisify-audit-agent' ); ?></th>
						</tr>
					</thead>
					<tbody>
						<?php foreach ( $escalated_findings as $escalated_finding ) : ?>
							<?php $escalated_finding_id = $this->get_finding_id( $escalated_finding ); ?>
							<tr>
								<td><span class="<?php echo esc_attr( $this->get_severity_class( $this->get_effective_severity( $escalated_finding, $finding_actions ) ) ); ?>"><?php echo esc_html( ucfirst( $this->get_effective_severity( $escalated_finding, $finding_actions ) ) ); ?></span></td>
								<td><?php echo esc_html( $escalated_finding['category'] ); ?></td>
								<td><?php echo esc_html( $escalated_finding['title'] ); ?></td>
								<td><?php echo esc_html( wp_strip_all_tags( $escalated_finding['details'] ) ); ?></td>
								<td>
									<div class="asa-inline-actions">
										<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent' ) ); ?>">
											<input type="hidden" name="asa_form_action" value="save_finding_action" />
											<input type="hidden" name="asa_finding_id" value="<?php echo esc_attr( $escalated_finding_id ); ?>" />
											<input type="hidden" name="asa_finding_action" value="" />
											<input type="hidden" name="asa_sort" value="<?php echo esc_attr( $sort_by ); ?>" />
											<input type="hidden" name="asa_order" value="<?php echo esc_attr( $sort_order ); ?>" />
											<input type="hidden" name="asa_per_page" value="<?php echo esc_attr( $per_page ); ?>" />
											<input type="hidden" name="asa_paged" value="<?php echo esc_attr( $paged ); ?>" />
											<?php wp_nonce_field( 'asa_save_finding_action', 'asa_save_finding_action_nonce' ); ?>
											<button type="submit" class="asa-text-button"><?php esc_html_e( 'Back to Compliance Findings', 'aegisify-audit-agent' ); ?></button>
										</form>
										<span class="asa-text-separator">|</span>
										<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent' ) ); ?>">
											<input type="hidden" name="asa_form_action" value="save_finding_action" />
											<input type="hidden" name="asa_finding_id" value="<?php echo esc_attr( $escalated_finding_id ); ?>" />
											<input type="hidden" name="asa_finding_action" value="delete" />
											<input type="hidden" name="asa_sort" value="<?php echo esc_attr( $sort_by ); ?>" />
											<input type="hidden" name="asa_order" value="<?php echo esc_attr( $sort_order ); ?>" />
											<input type="hidden" name="asa_per_page" value="<?php echo esc_attr( $per_page ); ?>" />
											<input type="hidden" name="asa_paged" value="<?php echo esc_attr( $paged ); ?>" />
											<?php wp_nonce_field( 'asa_save_finding_action', 'asa_save_finding_action_nonce' ); ?>
											<button type="submit" class="asa-text-button"><?php esc_html_e( 'Delete', 'aegisify-audit-agent' ); ?></button>
										</form>
									</div>
								</td>
							</tr>
						<?php endforeach; ?>
					</tbody>
				</table>
			</div>
			<?php endif; ?>

			<div class="asa-card asa-findings-card">
				<h3><?php esc_html_e( 'Compliance Findings', 'aegisify-audit-agent' ); ?></h3>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0 0 14px;">
					<div class="asa-plugin-selector">
						<strong><?php esc_html_e( 'Plugins to include in static code analysis:', 'aegisify-audit-agent' ); ?></strong>
						<div class="asa-plugin-checkbox-grid">
							<?php foreach ( $installed_plugins as $plugin_file => $plugin_name ) : ?>
								<label class="asa-plugin-checkbox">
									<input type="checkbox" name="asa_scan_plugins[]" value="<?php echo esc_attr( $plugin_file ); ?>" <?php checked( in_array( $plugin_file, $selected_scan_plugins, true ) ); ?> />
									<span><?php echo esc_html( $plugin_name ); ?></span>
								</label>
							<?php endforeach; ?>
						</div>
					</div>
					<input type="hidden" name="action" value="asa_run_scan" />
					<?php wp_nonce_field( 'asa_run_scan_action', 'asa_run_scan_nonce' ); ?>
					<button type="submit" class="button button-primary" <?php disabled( in_array( $scan_state['status'], array( 'queued', 'running' ), true ) || empty( $connection_status['verified'] ) ); ?>><?php esc_html_e( 'Scan Now', 'aegisify-audit-agent' ); ?></button>
					<?php if ( empty( $connection_status['verified'] ) ) : ?>
						<p class="asa-subtle" style="margin:10px 0 0;color:#b91c1c;"><?php esc_html_e( 'Scan Now is disabled until this agent has an active encrypted and verified connection to Aegisify Audit SaaS.', 'aegisify-audit-agent' ); ?></p>
					<?php endif; ?>
				</form>
				<p class="asa-subtle" style="margin-top:0;">
					<?php
					echo esc_html( $scan_state['message'] );
					if ( ! empty( $scan_state['completed_at'] ) ) {
						/* translators: %s: Local date/time when the last scan completed. */
						echo ' ' . esc_html( sprintf( __( 'Last completed: %s.', 'aegisify-audit-agent' ), $scan_state['completed_at'] ) );
					} elseif ( ! empty( $scan_state['requested_at'] ) ) {
						/* translators: %s: Local date/time when the last scan was requested. */
						echo ' ' . esc_html( sprintf( __( 'Last requested: %s.', 'aegisify-audit-agent' ), $scan_state['requested_at'] ) );
					}
					if ( ! empty( $report['generated_at_gmt'] ) ) {
						/* translators: %s: GMT timestamp for the cached report. */
						echo ' ' . esc_html( sprintf( __( 'Cached report generated (GMT): %s.', 'aegisify-audit-agent' ), $report['generated_at_gmt'] ) );
					}
					?>
				</p>
				<?php if ( ! empty( $scan_state['last_error'] ) ) : ?>
					<?php /* translators: %s: Most recent scan error message. */ ?>
					<p class="asa-subtle" style="color:#b91c1c;"><?php echo esc_html( sprintf( __( 'Last error: %s', 'aegisify-audit-agent' ), $scan_state['last_error'] ) ); ?></p>
				<?php endif; ?>
				<form method="get" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>" class="asa-card" style="margin:14px 0;padding:14px 16px;">
					<input type="hidden" name="page" value="aegisify-audit-agent" />
					<input type="hidden" name="asa_sort" value="<?php echo esc_attr( $sort_by ); ?>" />
					<input type="hidden" name="asa_order" value="<?php echo esc_attr( $sort_order ); ?>" />
					<input type="hidden" name="asa_per_page" value="<?php echo esc_attr( $per_page ); ?>" />
					<input type="hidden" name="asa_paged" value="1" />
					<input type="hidden" name="asa_apply_filters" value="1" />
					<div style="display:flex;flex-wrap:wrap;gap:18px;align-items:flex-end;justify-content:space-between;">
						<div style="flex:1 1 520px;min-width:320px;">
							<strong style="display:block;margin-bottom:8px;"><?php esc_html_e( 'Cached findings filters:', 'aegisify-audit-agent' ); ?></strong>
							<div class="asa-severity-checkbox-grid">
								<?php foreach ( array( 'critical' => 'Critical', 'high' => 'High', 'medium' => 'Medium', 'low' => 'Low', 'passed' => 'Pass' ) as $severity_key => $severity_label ) : ?>
									<label class="asa-severity-checkbox">
										<input type="checkbox" name="asa_filter_severity[]" value="<?php echo esc_attr( $severity_key ); ?>" <?php checked( in_array( $severity_key, $selected_filter_severities, true ) ); ?> />
										<span><?php echo esc_html( $severity_label ); ?></span>
									</label>
								<?php endforeach; ?>
							</div>
						</div>
						<div style="display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;">
							<div>
								<label for="asa-plugin-filter"><strong><?php esc_html_e( 'Plugin Filter:', 'aegisify-audit-agent' ); ?></strong></label><br />
								<select id="asa-plugin-filter" name="asa_plugin_filter">
									<option value=""><?php esc_html_e( 'All Plugins / Site', 'aegisify-audit-agent' ); ?></option>
									<?php foreach ( $installed_plugins as $plugin_file => $plugin_name ) : ?>
										<?php $plugin_option_key = sanitize_key( ( '.' !== dirname( $plugin_file ) && '' !== dirname( $plugin_file ) ) ? dirname( $plugin_file ) : basename( $plugin_file, '.php' ) ); ?>
										<option value="<?php echo esc_attr( $plugin_option_key ); ?>" <?php selected( $plugin_filter, $plugin_option_key ); ?>><?php echo esc_html( $plugin_name ); ?></option>
									<?php endforeach; ?>
								</select>
							</div>
							<div>
								<button type="submit" class="button button-secondary"><?php esc_html_e( 'Apply', 'aegisify-audit-agent' ); ?></button>
							</div>
						</div>
					</div>
				</form>
				<div class="asa-controls">
					<div>
						<strong><?php esc_html_e( 'Show:', 'aegisify-audit-agent' ); ?></strong>
						<?php foreach ( array( 25, 50, 100 ) as $per_page_option ) : ?>
							<?php
							$per_page_url = add_query_arg(
								array(
									'page'              => 'aegisify-audit-agent',
									'asa_sort'          => $sort_by,
									'asa_order'         => $sort_order,
									'asa_per_page'      => $per_page_option,
									'asa_paged'         => 1,
									'asa_plugin_filter' => $plugin_filter,
								),
								admin_url( 'admin.php' )
							);
							?>
							<a class="button <?php echo ( $per_page === $per_page_option ) ? 'button-primary' : ''; ?>" href="<?php echo esc_url( $per_page_url ); ?>"><?php echo esc_html( $per_page_option ); ?></a>
						<?php endforeach; ?>
					</div>
					<div class="asa-subtle">
						<?php /* translators: 1: First item number on the page, 2: Last item number on the page, 3: Total findings count. */ ?>
						<?php echo esc_html( sprintf( __( 'Showing %1$d-%2$d of %3$d findings', 'aegisify-audit-agent' ), $total_items ? ( $offset + 1 ) : 0, min( $offset + $per_page, $total_items ), $total_items ) ); ?>
					</div>
				</div>
				<div class="asa-findings-scroll">
				<table class="asa-table asa-findings-table">
					<thead>
						<tr>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'severity', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'Severity', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'plugin', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'Plugin', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'category', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'title', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'Title', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'file_name', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'File Name', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'line', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'Line', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'type', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'Type', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_sort_url( 'code', $sort_by, $sort_order, $per_page, 1, $plugin_filter ) ); ?>"><?php esc_html_e( 'Code', 'aegisify-audit-agent' ); ?></a></th>
							<th><?php esc_html_e( 'Details', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Actions', 'aegisify-audit-agent' ); ?></th>
						</tr>
					</thead>
					<tbody>
						<?php foreach ( $current_items as $finding ) : ?>
							<?php
							$finding_id       = $this->get_finding_id( $finding );
							$stored_action    = isset( $finding_actions[ $finding_id ]['action'] ) ? (string) $finding_actions[ $finding_id ]['action'] : '';
							$display_severity = $this->get_effective_severity( $finding, $finding_actions );
							?>
							<tr>
								<td><span class="<?php echo esc_attr( $this->get_severity_class( $display_severity ) ); ?>"><?php echo esc_html( ucfirst( $display_severity ) ); ?></span></td>
								<td><?php echo esc_html( $this->get_finding_plugin_label( $finding ) ); ?></td>
								<td><?php echo esc_html( isset( $finding['category'] ) ? (string) $finding['category'] : '—' ); ?></td>
								<td><?php echo esc_html( isset( $finding['title'] ) ? (string) $finding['title'] : '—' ); ?></td>
								<td><code><?php echo esc_html( $this->get_finding_file_name( $finding ) ); ?></code></td>
								<td><?php echo esc_html( ! empty( $finding['line'] ) ? absint( $finding['line'] ) : '—' ); ?></td>
								<td><?php echo esc_html( $this->get_finding_type_label( $finding ) ); ?></td>
								<td><code><?php echo esc_html( ! empty( $finding['code'] ) ? (string) $finding['code'] : '—' ); ?></code></td>
								<td><?php echo esc_html( isset( $finding['details'] ) ? wp_strip_all_tags( (string) $finding['details'] ) : '—' ); ?></td>
								<td>
									<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent' ) ); ?>" class="asa-action-wrap">
										<input type="hidden" name="asa_form_action" value="save_finding_action" />
										<input type="hidden" name="asa_finding_id" value="<?php echo esc_attr( $finding_id ); ?>" />
										<input type="hidden" name="asa_sort" value="<?php echo esc_attr( $sort_by ); ?>" />
										<input type="hidden" name="asa_order" value="<?php echo esc_attr( $sort_order ); ?>" />
										<input type="hidden" name="asa_per_page" value="<?php echo esc_attr( $per_page ); ?>" />
										<input type="hidden" name="asa_paged" value="<?php echo esc_attr( $paged ); ?>" />
										<input type="hidden" name="asa_plugin_filter" value="<?php echo esc_attr( $plugin_filter ); ?>" />
										<?php wp_nonce_field( 'asa_save_finding_action', 'asa_save_finding_action_nonce' ); ?>
										<select name="asa_finding_action">
											<option value=""><?php esc_html_e( 'Action', 'aegisify-audit-agent' ); ?></option>
											<option value="ignore" <?php selected( $stored_action, 'ignore' ); ?>><?php esc_html_e( 'Ignore', 'aegisify-audit-agent' ); ?></option>
											<option value="escalate" <?php selected( $stored_action, 'escalate' ); ?>><?php esc_html_e( 'Escalate', 'aegisify-audit-agent' ); ?></option>
											<option value="remediated" <?php selected( $stored_action, 'remediated' ); ?>><?php esc_html_e( 'Remediated', 'aegisify-audit-agent' ); ?></option>
										</select>
										<button type="submit" class="button button-secondary"><?php esc_html_e( 'Save', 'aegisify-audit-agent' ); ?></button>
									</form>
								</td>
							</tr>
						<?php endforeach; ?>
					</tbody>
				</table>
				</div>
				<div class="asa-pagination">
					<?php
					$prev_url = add_query_arg(
						array(
							'page'              => 'aegisify-audit-agent',
							'asa_sort'          => $sort_by,
							'asa_order'         => $sort_order,
							'asa_per_page'      => $per_page,
							'asa_paged'         => max( 1, $paged - 1 ),
							'asa_plugin_filter' => $plugin_filter,
						),
						admin_url( 'admin.php' )
					);
					$next_url = add_query_arg(
						array(
							'page'              => 'aegisify-audit-agent',
							'asa_sort'          => $sort_by,
							'asa_order'         => $sort_order,
							'asa_per_page'      => $per_page,
							'asa_paged'         => min( $total_pages, $paged + 1 ),
							'asa_plugin_filter' => $plugin_filter,
						),
						admin_url( 'admin.php' )
					);
					?>
					<a class="button <?php echo ( $paged <= 1 ) ? 'disabled' : ''; ?>" href="<?php echo esc_url( $prev_url ); ?>"><?php esc_html_e( 'Previous', 'aegisify-audit-agent' ); ?></a>
					<?php /* translators: 1: Current page number, 2: Total number of pages. */ ?>
					<span><?php echo esc_html( sprintf( __( 'Page %1$d of %2$d', 'aegisify-audit-agent' ), $paged, $total_pages ) ); ?></span>
					<a class="button <?php echo ( $paged >= $total_pages ) ? 'disabled' : ''; ?>" href="<?php echo esc_url( $next_url ); ?>"><?php esc_html_e( 'Next', 'aegisify-audit-agent' ); ?></a>
				</div>
			</div>

			<div class="asa-card asa-findings-card">
				<h3><?php esc_html_e( 'Vulnerabilities', 'aegisify-audit-agent' ); ?></h3>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="margin:0 0 14px;">
					<input type="hidden" name="action" value="asa_run_vulnerability_scan" />
					<?php wp_nonce_field( 'asa_run_vulnerability_scan_action', 'asa_run_vulnerability_scan_nonce' ); ?>
					<button type="submit" class="button button-primary" <?php disabled( in_array( $vulnerability_scan_state['status'], array( 'queued', 'running' ), true ) || empty( $connection_status['verified'] ) ); ?>><?php esc_html_e( 'Scan', 'aegisify-audit-agent' ); ?></button>
					<?php if ( empty( $connection_status['verified'] ) ) : ?>
						<p class="asa-subtle" style="margin:10px 0 0;color:#b91c1c;"><?php esc_html_e( 'Scan is disabled until this agent has an active encrypted and verified connection to Aegisify Audit SaaS.', 'aegisify-audit-agent' ); ?></p>
					<?php endif; ?>
				</form>
				<p class="asa-subtle" style="margin-top:0;">
					<?php
					echo esc_html( $vulnerability_scan_state['message'] );
					if ( ! empty( $vulnerability_scan_state['completed_at'] ) ) {
						/* translators: Dynamic values are inserted into the translated message. */
						echo ' ' . esc_html( sprintf( __( 'Last completed: %s.', 'aegisify-audit-agent' ), $vulnerability_scan_state['completed_at'] ) );
					} elseif ( ! empty( $vulnerability_scan_state['requested_at'] ) ) {
						/* translators: Dynamic values are inserted into the translated message. */
						echo ' ' . esc_html( sprintf( __( 'Last requested: %s.', 'aegisify-audit-agent' ), $vulnerability_scan_state['requested_at'] ) );
					}
					if ( ! empty( $vulnerability_report['generated_at_gmt'] ) ) {
						/* translators: Dynamic values are inserted into the translated message. */
						echo ' ' . esc_html( sprintf( __( 'Cached vulnerability report generated (GMT): %s.', 'aegisify-audit-agent' ), $vulnerability_report['generated_at_gmt'] ) );
					}
					?>
				</p>
				<?php if ( in_array( $vulnerability_scan_state['status'], array( 'queued', 'running' ), true ) ) : ?>
					<p class="asa-subtle" style="margin-top:-6px;"><a href="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent-logs' ) ); ?>"><?php esc_html_e( 'Open Logs → Queue Management to review, clear, or reset a stuck vulnerability scan queue.', 'aegisify-audit-agent' ); ?></a></p>
				<?php endif; ?>
				<?php if ( ! empty( $vulnerability_scan_state['last_error'] ) ) : ?>
					<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
					<p class="asa-subtle" style="color:#b91c1c;"><?php echo esc_html( sprintf( __( 'Last error: %s', 'aegisify-audit-agent' ), $vulnerability_scan_state['last_error'] ) ); ?></p>
				<?php endif; ?>
				<form method="get" action="<?php echo esc_url( admin_url( 'admin.php' ) ); ?>" class="asa-card" style="margin:14px 0;padding:14px 16px;">
					<input type="hidden" name="page" value="aegisify-audit-agent" />
					<input type="hidden" name="asa_vuln_sort" value="<?php echo esc_attr( $vulnerability_sort_by ); ?>" />
					<input type="hidden" name="asa_vuln_order" value="<?php echo esc_attr( $vulnerability_sort_order ); ?>" />
					<input type="hidden" name="asa_vuln_per_page" value="<?php echo esc_attr( $vulnerability_per_page ); ?>" />
					<input type="hidden" name="asa_vuln_paged" value="1" />
					<input type="hidden" name="asa_vuln_apply_filters" value="1" />
					<div style="display:flex;flex-wrap:wrap;gap:18px;align-items:flex-end;justify-content:space-between;">
						<div style="flex:1 1 520px;min-width:320px;">
							<strong style="display:block;margin-bottom:8px;"><?php esc_html_e( 'Cached vulnerability filters:', 'aegisify-audit-agent' ); ?></strong>
							<div class="asa-severity-checkbox-grid">
								<?php foreach ( array( 'critical' => 'Critical', 'high' => 'High', 'medium' => 'Medium', 'low' => 'Low', 'passed' => 'Pass' ) as $severity_key => $severity_label ) : ?>
									<label class="asa-severity-checkbox">
										<input type="checkbox" name="asa_vuln_filter_severity[]" value="<?php echo esc_attr( $severity_key ); ?>" <?php checked( in_array( $severity_key, $vulnerability_selected_filter_severities, true ) ); ?> />
										<span><?php echo esc_html( $severity_label ); ?></span>
									</label>
								<?php endforeach; ?>
							</div>
						</div>
						<div style="display:flex;flex-wrap:wrap;gap:10px;align-items:flex-end;">
							<div>
								<label for="asa-vuln-component-filter"><strong><?php esc_html_e( 'Component Filter:', 'aegisify-audit-agent' ); ?></strong></label><br />
								<select id="asa-vuln-component-filter" name="asa_vuln_component_filter">
									<option value=""><?php esc_html_e( 'All Components', 'aegisify-audit-agent' ); ?></option>
									<?php foreach ( $vulnerability_filter_options as $component_option_key => $component_option_label ) : ?>
										<option value="<?php echo esc_attr( $component_option_key ); ?>" <?php selected( $vulnerability_component_filter, $component_option_key ); ?>><?php echo esc_html( $component_option_label ); ?></option>
									<?php endforeach; ?>
								</select>
							</div>
							<div>
								<button type="submit" class="button button-secondary"><?php esc_html_e( 'Apply', 'aegisify-audit-agent' ); ?></button>
							</div>
						</div>
					</div>
				</form>
				<div class="asa-controls">
					<div>
						<strong><?php esc_html_e( 'Show:', 'aegisify-audit-agent' ); ?></strong>
						<?php foreach ( array( 25, 50, 100 ) as $per_page_option ) : ?>
							<?php $per_page_url = add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_vuln_sort' => $vulnerability_sort_by, 'asa_vuln_order' => $vulnerability_sort_order, 'asa_vuln_per_page' => $per_page_option, 'asa_vuln_paged' => 1, 'asa_vuln_component_filter' => $vulnerability_component_filter ), admin_url( 'admin.php' ) ); ?>
							<a class="button <?php echo ( $vulnerability_per_page === $per_page_option ) ? 'button-primary' : ''; ?>" href="<?php echo esc_url( $per_page_url ); ?>"><?php echo esc_html( $per_page_option ); ?></a>
						<?php endforeach; ?>
					</div>
					<div class="asa-subtle">
						<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
						<?php echo esc_html( sprintf( __( 'Showing %1$d-%2$d of %3$d findings', 'aegisify-audit-agent' ), $vulnerability_total_items ? ( $vulnerability_offset + 1 ) : 0, min( $vulnerability_offset + $vulnerability_per_page, $vulnerability_total_items ), $vulnerability_total_items ) ); ?>
					</div>
				</div>
				<div class="asa-findings-scroll">
				<table class="asa-table asa-findings-table">
					<thead>
						<tr>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'severity', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'Severity', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'plugin', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'Plugin', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'category', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'title', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'Title', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'file_name', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'File Name', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'line', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'Line', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'type', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'Type', 'aegisify-audit-agent' ); ?></a></th>
							<th><a class="asa-sort-link" href="<?php echo esc_url( $this->get_prefixed_sort_url( 'asa_vuln', 'code', $vulnerability_sort_by, $vulnerability_sort_order, $vulnerability_per_page, 1, $vulnerability_component_filter ) ); ?>"><?php esc_html_e( 'Code', 'aegisify-audit-agent' ); ?></a></th>
							<th><?php esc_html_e( 'Details', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Actions', 'aegisify-audit-agent' ); ?></th>
						</tr>
					</thead>
					<tbody>
						<?php foreach ( $current_vulnerability_items as $finding ) : ?>
							<?php $finding_id = $this->get_finding_id( $finding ); $stored_action = isset( $finding_actions[ $finding_id ]['action'] ) ? (string) $finding_actions[ $finding_id ]['action'] : ''; $display_severity = $this->get_effective_severity( $finding, $finding_actions ); ?>
							<tr>
								<td><span class="<?php echo esc_attr( $this->get_severity_class( $display_severity ) ); ?>"><?php echo esc_html( ucfirst( $display_severity ) ); ?></span></td>
								<td><?php echo esc_html( $this->get_finding_plugin_label( $finding ) ); ?></td>
								<td><?php echo esc_html( isset( $finding['category'] ) ? (string) $finding['category'] : '—' ); ?></td>
								<td><?php echo esc_html( isset( $finding['title'] ) ? (string) $finding['title'] : '—' ); ?></td>
								<td><code><?php echo esc_html( $this->get_finding_file_name( $finding ) ); ?></code></td>
								<td><?php echo esc_html( ! empty( $finding['line'] ) ? absint( $finding['line'] ) : '—' ); ?></td>
								<td><?php echo esc_html( $this->get_finding_type_label( $finding ) ); ?></td>
								<td><code><?php echo esc_html( ! empty( $finding['code'] ) ? (string) $finding['code'] : '—' ); ?></code></td>
								<td><?php echo esc_html( isset( $finding['details'] ) ? wp_strip_all_tags( (string) $finding['details'] ) : '—' ); ?></td>
								<td>
									<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent' ) ); ?>" class="asa-action-wrap">
										<input type="hidden" name="asa_form_action" value="save_finding_action" />
										<input type="hidden" name="asa_finding_id" value="<?php echo esc_attr( $finding_id ); ?>" />
										<input type="hidden" name="asa_vuln_sort" value="<?php echo esc_attr( $vulnerability_sort_by ); ?>" />
										<input type="hidden" name="asa_vuln_order" value="<?php echo esc_attr( $vulnerability_sort_order ); ?>" />
										<input type="hidden" name="asa_vuln_per_page" value="<?php echo esc_attr( $vulnerability_per_page ); ?>" />
										<input type="hidden" name="asa_vuln_paged" value="<?php echo esc_attr( $vulnerability_paged ); ?>" />
										<input type="hidden" name="asa_vuln_component_filter" value="<?php echo esc_attr( $vulnerability_component_filter ); ?>" />
										<input type="hidden" name="asa_sort" value="<?php echo esc_attr( $sort_by ); ?>" />
										<input type="hidden" name="asa_order" value="<?php echo esc_attr( $sort_order ); ?>" />
										<input type="hidden" name="asa_per_page" value="<?php echo esc_attr( $per_page ); ?>" />
										<input type="hidden" name="asa_paged" value="<?php echo esc_attr( $paged ); ?>" />
										<input type="hidden" name="asa_plugin_filter" value="<?php echo esc_attr( $plugin_filter ); ?>" />
										<?php wp_nonce_field( 'asa_save_finding_action', 'asa_save_finding_action_nonce' ); ?>
										<select name="asa_finding_action">
											<option value=""><?php esc_html_e( 'Action', 'aegisify-audit-agent' ); ?></option>
											<option value="ignore" <?php selected( $stored_action, 'ignore' ); ?>><?php esc_html_e( 'Ignore', 'aegisify-audit-agent' ); ?></option>
											<option value="escalate" <?php selected( $stored_action, 'escalate' ); ?>><?php esc_html_e( 'Escalate', 'aegisify-audit-agent' ); ?></option>
											<option value="remediated" <?php selected( $stored_action, 'remediated' ); ?>><?php esc_html_e( 'Remediated', 'aegisify-audit-agent' ); ?></option>
										</select>
										<button type="submit" class="button button-secondary"><?php esc_html_e( 'Save', 'aegisify-audit-agent' ); ?></button>
									</form>
								</td>
							</tr>
						<?php endforeach; ?>
					</tbody>
				</table>
				</div>
				<div class="asa-pagination">
					<?php $vuln_prev_url = add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_vuln_sort' => $vulnerability_sort_by, 'asa_vuln_order' => $vulnerability_sort_order, 'asa_vuln_per_page' => $vulnerability_per_page, 'asa_vuln_paged' => max( 1, $vulnerability_paged - 1 ), 'asa_vuln_component_filter' => $vulnerability_component_filter ), admin_url( 'admin.php' ) ); ?>
					<?php $vuln_next_url = add_query_arg( array( 'page' => 'aegisify-audit-agent', 'asa_vuln_sort' => $vulnerability_sort_by, 'asa_vuln_order' => $vulnerability_sort_order, 'asa_vuln_per_page' => $vulnerability_per_page, 'asa_vuln_paged' => min( $vulnerability_total_pages, $vulnerability_paged + 1 ), 'asa_vuln_component_filter' => $vulnerability_component_filter ), admin_url( 'admin.php' ) ); ?>
					<a class="button <?php echo ( $vulnerability_paged <= 1 ) ? 'disabled' : ''; ?>" href="<?php echo esc_url( $vuln_prev_url ); ?>"><?php esc_html_e( 'Previous', 'aegisify-audit-agent' ); ?></a>
					<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
					<span><?php echo esc_html( sprintf( __( 'Page %1$d of %2$d', 'aegisify-audit-agent' ), $vulnerability_paged, $vulnerability_total_pages ) ); ?></span>
					<a class="button <?php echo ( $vulnerability_paged >= $vulnerability_total_pages ) ? 'disabled' : ''; ?>" href="<?php echo esc_url( $vuln_next_url ); ?>"><?php esc_html_e( 'Next', 'aegisify-audit-agent' ); ?></a>
				</div>
			</div>

			<?php if ( ! empty( $remediated_findings ) ) : ?>
			<div class="asa-card asa-remediated-card">
				<h3><?php esc_html_e( 'Remediated', 'aegisify-audit-agent' ); ?></h3>
				<?php /* translators: %d: Number of remediated findings. */ ?>
				<p class="asa-subtle"><?php echo esc_html( sprintf( __( '%d findings have been marked as remediated.', 'aegisify-audit-agent' ), count( $remediated_findings ) ) ); ?></p>
				<table class="asa-table">
					<thead>
						<tr>
							<th style="width:10%;"><?php esc_html_e( 'Severity', 'aegisify-audit-agent' ); ?></th>
							<th style="width:10%;"><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></th>
							<th style="width:20%;"><?php esc_html_e( 'Title', 'aegisify-audit-agent' ); ?></th>
							<th style="width:40%;"><?php esc_html_e( 'Details', 'aegisify-audit-agent' ); ?></th>
							<th style="width:20%;"><?php esc_html_e( 'Actions', 'aegisify-audit-agent' ); ?></th>
						</tr>
					</thead>
					<tbody>
						<?php foreach ( $remediated_findings as $remediated_finding ) : ?>
							<?php $remediated_finding_id = $this->get_finding_id( $remediated_finding ); ?>
							<tr>
								<td><span class="<?php echo esc_attr( $this->get_severity_class( $this->get_effective_severity( $remediated_finding, $finding_actions ) ) ); ?>"><?php echo esc_html( ucfirst( $this->get_effective_severity( $remediated_finding, $finding_actions ) ) ); ?></span></td>
								<td><?php echo esc_html( $remediated_finding['category'] ); ?></td>
								<td><?php echo esc_html( $remediated_finding['title'] ); ?></td>
								<td><?php echo esc_html( wp_strip_all_tags( $remediated_finding['details'] ) ); ?></td>
								<td>
									<div class="asa-inline-actions">
										<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent' ) ); ?>">
											<input type="hidden" name="asa_form_action" value="save_finding_action" />
											<input type="hidden" name="asa_finding_id" value="<?php echo esc_attr( $remediated_finding_id ); ?>" />
											<input type="hidden" name="asa_finding_action" value="" />
											<input type="hidden" name="asa_sort" value="<?php echo esc_attr( $sort_by ); ?>" />
											<input type="hidden" name="asa_order" value="<?php echo esc_attr( $sort_order ); ?>" />
											<input type="hidden" name="asa_per_page" value="<?php echo esc_attr( $per_page ); ?>" />
											<input type="hidden" name="asa_paged" value="<?php echo esc_attr( $paged ); ?>" />
											<?php wp_nonce_field( 'asa_save_finding_action', 'asa_save_finding_action_nonce' ); ?>
											<button type="submit" class="asa-text-button"><?php esc_html_e( 'Back to Compliance Findings', 'aegisify-audit-agent' ); ?></button>
										</form>
										<span class="asa-text-separator">|</span>
										<form method="post" action="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent' ) ); ?>">
											<input type="hidden" name="asa_form_action" value="save_finding_action" />
											<input type="hidden" name="asa_finding_id" value="<?php echo esc_attr( $remediated_finding_id ); ?>" />
											<input type="hidden" name="asa_finding_action" value="delete" />
											<input type="hidden" name="asa_sort" value="<?php echo esc_attr( $sort_by ); ?>" />
											<input type="hidden" name="asa_order" value="<?php echo esc_attr( $sort_order ); ?>" />
											<input type="hidden" name="asa_per_page" value="<?php echo esc_attr( $per_page ); ?>" />
											<input type="hidden" name="asa_paged" value="<?php echo esc_attr( $paged ); ?>" />
											<?php wp_nonce_field( 'asa_save_finding_action', 'asa_save_finding_action_nonce' ); ?>
											<button type="submit" class="asa-text-button"><?php esc_html_e( 'Delete', 'aegisify-audit-agent' ); ?></button>
										</form>
									</div>
								</td>
							</tr>
						<?php endforeach; ?>
					</tbody>
				</table>
			</div>
			<?php endif; ?>
		</div>
		<?php
	}


	public function handle_save_wp_activity_log_settings() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		check_admin_referer( 'asa_save_wp_activity_log_settings', 'asa_save_wp_activity_log_settings_nonce' );

		if ( ! class_exists( 'ASA_WP_Activity_Log' ) ) {
			wp_safe_redirect(
				add_query_arg(
					array(
						'page'            => 'aegisify-audit-agent-wp-activity-log',
						'asa_msg'         => 'wp_activity_unavailable',
						'wp_activity_tab' => 'sensors',
					),
					admin_url( 'admin.php' )
				)
			);
			exit;
		}

		$definitions = ASA_WP_Activity_Log::get_sensor_definitions();
		$raw_sensors = isset( $_POST['asa_wp_activity_sensors'] ) && is_array( $_POST['asa_wp_activity_sensors'] )
			? map_deep( wp_unslash( $_POST['asa_wp_activity_sensors'] ), 'sanitize_text_field' )
			: array();
		$sensors     = array();

		foreach ( $definitions as $sensor_key => $definition ) {
			$current = isset( $raw_sensors[ $sensor_key ] ) && is_array( $raw_sensors[ $sensor_key ] ) ? $raw_sensors[ $sensor_key ] : array();
			$sensors[ $sensor_key ] = array(
				'enabled'  => isset( $current['enabled'] ) ? 1 : 0,
				'severity' => isset( $current['severity'] ) ? sanitize_key( (string) $current['severity'] ) : ( isset( $definition['default_severity'] ) ? sanitize_key( (string) $definition['default_severity'] ) : 'low' ),
			);
		}

		ASA_WP_Activity_Log::save_settings(
			array(
				'sensors' => $sensors,
			)
		);

		$enabled_count = 0;
		foreach ( $sensors as $sensor_config ) {
			$enabled_count += ! empty( $sensor_config['enabled'] ) ? 1 : 0;
		}

		ASA_Logger::log(
			'configuration',
			'success',
			'admin',
			'save_wp_activity_log_settings',
			__( 'WordPress activity log sensor settings were updated from wp-admin.', 'aegisify-audit-agent' ),
			array(
				'enabled_sensors' => $enabled_count,
				'total_sensors'   => count( $sensors ),
			),
			10
		);

		ASA_WP_Activity_Log::log_event(
			'sensor_update',
			__( 'WordPress activity log sensor settings were updated.', 'aegisify-audit-agent' ),
			array(
				'enabled_sensors' => $enabled_count,
				'total_sensors'   => count( $sensors ),
			),
			array()
		);

		wp_safe_redirect(
			add_query_arg(
				array(
					'page'            => 'aegisify-audit-agent-wp-activity-log',
					'asa_msg'         => 'wp_activity_saved',
					'wp_activity_tab' => 'sensors',
				),
				admin_url( 'admin.php' )
			)
		);
		exit;
	}

	public function render_wp_activity_log_page() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		if ( ! class_exists( 'ASA_WP_Activity_Log' ) ) {
			echo '<div class="wrap"><h1>' . esc_html__( 'WordPress Activity Log', 'aegisify-audit-agent' ) . '</h1><p>' . esc_html__( 'The WordPress activity log collector is not available.', 'aegisify-audit-agent' ) . '</p></div>';
			return;
		}

		$definitions      = ASA_WP_Activity_Log::get_sensor_definitions_for_display();
		$settings         = ASA_WP_Activity_Log::get_settings();
		$all_events       = ASA_WP_Activity_Log::get_events( 500 );
		$severity_levels  = ASA_WP_Activity_Log::get_severity_levels();
		$enabled_sensors  = 0;
		foreach ( $settings['sensors'] as $sensor_config ) {
			$enabled_sensors += ! empty( $sensor_config['enabled'] ) ? 1 : 0;
		}

		$event_categories = array();
		foreach ( $definitions as $definition ) {
			$category_label = isset( $definition['category'] ) ? sanitize_text_field( (string) $definition['category'] ) : '';
			if ( '' === $category_label ) {
				continue;
			}
			$event_categories[ sanitize_key( $category_label ) ] = $category_label;
		}
		asort( $event_categories, SORT_NATURAL | SORT_FLAG_CASE );

		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only admin notice state and filter state.
		$msg                     = isset( $_GET['asa_msg'] ) ? sanitize_key( wp_unslash( $_GET['asa_msg'] ) ) : '';
		$tab                     = isset( $_GET['wp_activity_tab'] ) ? sanitize_key( wp_unslash( $_GET['wp_activity_tab'] ) ) : 'events';
		$selected_category       = isset( $_GET['asa_wp_activity_category'] ) ? sanitize_key( wp_unslash( $_GET['asa_wp_activity_category'] ) ) : '';
		$selected_severity       = isset( $_GET['asa_wp_activity_severity'] ) ? sanitize_key( wp_unslash( $_GET['asa_wp_activity_severity'] ) ) : '';
		$search_term             = isset( $_GET['asa_wp_activity_search'] ) ? sanitize_text_field( wp_unslash( $_GET['asa_wp_activity_search'] ) ) : '';
		$events_per_page         = isset( $_GET['asa_wp_activity_per_page'] ) ? absint( wp_unslash( $_GET['asa_wp_activity_per_page'] ) ) : 25;
		$events_paged            = isset( $_GET['asa_wp_activity_paged'] ) ? max( 1, absint( wp_unslash( $_GET['asa_wp_activity_paged'] ) ) ) : 1;
		// phpcs:enable WordPress.Security.NonceVerification.Recommended
		if ( ! in_array( $tab, array( 'events', 'sensors' ), true ) ) {
			$tab = 'events';
		}
		if ( ! in_array( $events_per_page, array( 25, 50 ), true ) ) {
			$events_per_page = 25;
		}
		if ( '' !== $selected_category && ! isset( $event_categories[ $selected_category ] ) ) {
			$selected_category = '';
		}
		if ( '' !== $selected_severity && ! isset( $severity_levels[ $selected_severity ] ) ) {
			$selected_severity = '';
		}

		$filtered_events = array_values(
			array_filter(
				$all_events,
				function ( $event ) use ( $selected_category, $selected_severity, $search_term ) {
					$event_category = ! empty( $event['category'] ) ? sanitize_key( (string) $event['category'] ) : '';
					$event_severity = ! empty( $event['severity'] ) ? sanitize_key( (string) $event['severity'] ) : '';

					if ( '' !== $selected_category && $selected_category !== $event_category ) {
						return false;
					}

					if ( '' !== $selected_severity && $selected_severity !== $event_severity ) {
						return false;
					}

					if ( '' === $search_term ) {
						return true;
					}

					$haystack = strtolower(
						implode(
							' ',
							array(
								isset( $event['category'] ) ? (string) $event['category'] : '',
								isset( $event['sensor_label'] ) ? (string) $event['sensor_label'] : '',
								isset( $event['sensor_key'] ) ? (string) $event['sensor_key'] : '',
								isset( $event['severity'] ) ? (string) $event['severity'] : '',
								isset( $event['summary'] ) ? (string) $event['summary'] : '',
								! empty( $event['actor']['label'] ) ? (string) $event['actor']['label'] : '',
								wp_json_encode( isset( $event['details'] ) ? $event['details'] : array() ),
							)
						)
					);

					return false !== strpos( $haystack, strtolower( $search_term ) );
				}
			)
		);

		$total_events       = count( $filtered_events );
		$total_event_pages  = max( 1, (int) ceil( $total_events / $events_per_page ) );
		$events_paged       = min( $events_paged, $total_event_pages );
		$events_offset      = ( $events_paged - 1 ) * $events_per_page;
		$page_events        = array_slice( $filtered_events, $events_offset, $events_per_page );

		$events_tab_url  = add_query_arg(
			array(
				'page'            => 'aegisify-audit-agent-wp-activity-log',
				'wp_activity_tab' => 'events',
			),
			admin_url( 'admin.php' )
		);
		$sensors_tab_url = add_query_arg(
			array(
				'page'            => 'aegisify-audit-agent-wp-activity-log',
				'wp_activity_tab' => 'sensors',
			),
			admin_url( 'admin.php' )
		);
		?>
		<div class="wrap asa-wrap">
			<h1 class="asa-title"><?php esc_html_e( 'WordPress Activity Log', 'aegisify-audit-agent' ); ?></h1>
			<?php if ( 'wp_activity_saved' === $msg ) : ?>
				<div class="notice notice-success is-dismissible"><p><?php esc_html_e( 'WordPress activity log sensor settings were saved.', 'aegisify-audit-agent' ); ?></p></div>
			<?php elseif ( 'wp_activity_unavailable' === $msg ) : ?>
				<div class="notice notice-error is-dismissible"><p><?php esc_html_e( 'The WordPress activity log collector is not available on this Agent.', 'aegisify-audit-agent' ); ?></p></div>
			<?php endif; ?>
			<style>
				.asa-wrap .asa-title,.asa-wrap h2,.asa-wrap h3{color:#7A0099 !important}.asa-activity-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:16px 0}.asa-activity-card{background:#fff;border:1px solid #dcdcde;border-radius:16px;padding:18px;box-shadow:0 8px 24px rgba(0,0,0,.05)}.asa-activity-stat{font-size:28px;font-weight:700;margin:0 0 6px}.asa-activity-filters{display:flex;gap:10px;align-items:end;flex-wrap:wrap;margin:0 0 16px}.asa-activity-filters label{display:flex;flex-direction:column;gap:6px;font-weight:600}.asa-activity-filters input,.asa-activity-filters select{min-width:180px}.asa-activity-table{width:100%;border-collapse:collapse;table-layout:fixed}.asa-activity-table th,.asa-activity-table td{padding:10px 12px;border-bottom:1px solid #e5e5e5;vertical-align:top;text-align:left;word-break:break-word}.asa-activity-table th:nth-child(1){width:13%}.asa-activity-table th:nth-child(2){width:11%}.asa-activity-table th:nth-child(3){width:23%}.asa-activity-table th:nth-child(4){width:10%}.asa-activity-table th:nth-child(5){width:23%}.asa-activity-table th:nth-child(6){width:20%}.asa-activity-badge{display:inline-block;border-radius:999px;padding:3px 9px;font-size:11px;font-weight:700;line-height:1.2;background:#f4f4f5;color:#27272a}.asa-activity-note{margin:12px 0 0;color:#50575e}.asa-activity-settings-table{width:100%;border-collapse:collapse;table-layout:fixed}.asa-activity-settings-table th,.asa-activity-settings-table td{padding:10px 12px;border-bottom:1px solid #e5e5e5;vertical-align:top;text-align:left}.asa-activity-settings-table th:nth-child(1){width:12%}.asa-activity-settings-table th:nth-child(2){width:24%}.asa-activity-settings-table th:nth-child(3){width:10%}.asa-activity-settings-table th:nth-child(4){width:16%}.asa-activity-settings-table th:nth-child(5){width:38%}.asa-activity-settings-table select{min-width:150px}.asa-activity-muted{color:#50575e;font-size:12px}.asa-activity-context{max-height:220px;overflow:auto;white-space:pre-wrap;background:#fafafa;border:1px solid #e5e5e5;border-radius:12px;padding:10px;font-size:12px}.asa-activity-pagination{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:16px}@media (max-width:1100px){.asa-activity-table,.asa-activity-settings-table{table-layout:auto}}
			</style>

			<div class="asa-activity-grid">
				<div class="asa-activity-card"><div class="asa-activity-stat"><?php echo esc_html( (string) count( $definitions ) ); ?></div><div><?php esc_html_e( 'Available sensors', 'aegisify-audit-agent' ); ?></div></div>
				<div class="asa-activity-card"><div class="asa-activity-stat"><?php echo esc_html( (string) $enabled_sensors ); ?></div><div><?php esc_html_e( 'Enabled sensors', 'aegisify-audit-agent' ); ?></div></div>
				<div class="asa-activity-card"><div class="asa-activity-stat"><?php echo esc_html( (string) count( $all_events ) ); ?></div><div><?php esc_html_e( 'Recent retained events available', 'aegisify-audit-agent' ); ?></div></div>
			</div>

			<h2 class="nav-tab-wrapper" style="margin-bottom:16px;">
				<a href="<?php echo esc_url( $events_tab_url ); ?>" class="nav-tab <?php echo 'events' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'WordPress Activity Events', 'aegisify-audit-agent' ); ?></a>
				<a href="<?php echo esc_url( $sensors_tab_url ); ?>" class="nav-tab <?php echo 'sensors' === $tab ? 'nav-tab-active' : ''; ?>"><?php esc_html_e( 'Sensors', 'aegisify-audit-agent' ); ?></a>
			</h2>

			<?php if ( 'sensors' === $tab ) : ?>
				<div class="asa-activity-card">
					<h2 style="margin-top:0;"><?php esc_html_e( 'Sensor Settings', 'aegisify-audit-agent' ); ?></h2>
					<p class="asa-activity-note"><?php esc_html_e( 'Each sensor can be enabled or disabled, and each event type can be assigned its own severity level. The Agent stores the recent retained events locally so they can be reviewed here or fetched later when needed.', 'aegisify-audit-agent' ); ?></p>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
						<?php wp_nonce_field( 'asa_save_wp_activity_log_settings', 'asa_save_wp_activity_log_settings_nonce' ); ?>
						<input type="hidden" name="action" value="asa_save_wp_activity_log_settings" />
						<table class="asa-activity-settings-table">
							<thead>
								<tr>
									<th><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Sensor', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Enabled', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Severity', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Description', 'aegisify-audit-agent' ); ?></th>
								</tr>
							</thead>
							<tbody>
								<?php foreach ( $definitions as $sensor_key => $definition ) : ?>
									<?php $sensor_settings = isset( $settings['sensors'][ $sensor_key ] ) ? $settings['sensors'][ $sensor_key ] : array(); ?>
									<tr>
										<td><?php echo esc_html( isset( $definition['category'] ) ? (string) $definition['category'] : '' ); ?></td>
										<td><strong><?php echo esc_html( isset( $definition['label'] ) ? (string) $definition['label'] : '' ); ?></strong><div class="asa-activity-muted"><code><?php echo esc_html( $sensor_key ); ?></code></div></td>
										<td><label><input type="checkbox" name="asa_wp_activity_sensors[<?php echo esc_attr( $sensor_key ); ?>][enabled]" value="1" <?php checked( ! empty( $sensor_settings['enabled'] ) ); ?> /></label></td>
										<td>
											<select name="asa_wp_activity_sensors[<?php echo esc_attr( $sensor_key ); ?>][severity]">
												<?php foreach ( $severity_levels as $severity_key => $severity_label ) : ?>
													<option value="<?php echo esc_attr( $severity_key ); ?>" <?php selected( isset( $sensor_settings['severity'] ) ? $sensor_settings['severity'] : '', $severity_key ); ?>><?php echo esc_html( $severity_label ); ?></option>
												<?php endforeach; ?>
											</select>
										</td>
										<td><?php echo esc_html( isset( $definition['remarks'] ) ? (string) $definition['remarks'] : '' ); ?></td>
									</tr>
								<?php endforeach; ?>
							</tbody>
						</table>
						<p><button type="submit" class="button button-primary"><?php esc_html_e( 'Save Sensor Settings', 'aegisify-audit-agent' ); ?></button></p>
					</form>
				</div>
			<?php else : ?>
				<div class="asa-activity-card">
					<h2 style="margin-top:0;"><?php esc_html_e( 'Recent WordPress Activity Events', 'aegisify-audit-agent' ); ?></h2>
					<form method="get" class="asa-activity-filters">
						<input type="hidden" name="page" value="aegisify-audit-agent-wp-activity-log" />
						<input type="hidden" name="wp_activity_tab" value="events" />
						<label>
							<span><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></span>
							<select name="asa_wp_activity_category">
								<option value=""><?php esc_html_e( 'All categories', 'aegisify-audit-agent' ); ?></option>
								<?php foreach ( $event_categories as $category_key => $category_label ) : ?>
									<option value="<?php echo esc_attr( $category_key ); ?>" <?php selected( $selected_category, $category_key ); ?>><?php echo esc_html( $category_label ); ?></option>
								<?php endforeach; ?>
							</select>
						</label>
						<label>
							<span><?php esc_html_e( 'Severity', 'aegisify-audit-agent' ); ?></span>
							<select name="asa_wp_activity_severity">
								<option value=""><?php esc_html_e( 'All severities', 'aegisify-audit-agent' ); ?></option>
								<?php foreach ( $severity_levels as $severity_key => $severity_label ) : ?>
									<option value="<?php echo esc_attr( $severity_key ); ?>" <?php selected( $selected_severity, $severity_key ); ?>><?php echo esc_html( $severity_label ); ?></option>
								<?php endforeach; ?>
							</select>
						</label>
						<label>
							<span><?php esc_html_e( 'Search', 'aegisify-audit-agent' ); ?></span>
							<input type="search" name="asa_wp_activity_search" value="<?php echo esc_attr( $search_term ); ?>" />
						</label>
						<label>
							<span><?php esc_html_e( 'Show', 'aegisify-audit-agent' ); ?></span>
							<select name="asa_wp_activity_per_page">
								<?php foreach ( array( 25, 50 ) as $row_count ) : ?>
									<option value="<?php echo esc_attr( (string) $row_count ); ?>" <?php selected( $events_per_page, $row_count ); ?>><?php echo esc_html( (string) $row_count ); ?></option>
								<?php endforeach; ?>
							</select>
						</label>
						<button type="submit" class="button button-primary"><?php esc_html_e( 'Apply Filters', 'aegisify-audit-agent' ); ?></button>
						<a class="button" href="<?php echo esc_url( $events_tab_url ); ?>"><?php esc_html_e( 'Reset', 'aegisify-audit-agent' ); ?></a>
					</form>

					<p class="asa-activity-note">
						<?php
						printf(
							/* translators: Dynamic values are inserted into the translated message. */
							esc_html__( 'Showing %1$d filtered WordPress activity events out of %2$d retained events.', 'aegisify-audit-agent' ),
							(int) $total_events,
							(int) count( $all_events )
						);
						?>
					</p>

					<?php if ( empty( $page_events ) ) : ?>
						<p><?php esc_html_e( 'No retained WordPress activity events matched the current filters yet.', 'aegisify-audit-agent' ); ?></p>
					<?php else : ?>
						<table class="asa-activity-table">
							<thead>
								<tr>
									<th><?php esc_html_e( 'Time', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Sensor', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Severity', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Summary', 'aegisify-audit-agent' ); ?></th>
									<th><?php esc_html_e( 'Actor / Details', 'aegisify-audit-agent' ); ?></th>
								</tr>
							</thead>
							<tbody>
								<?php foreach ( $page_events as $event ) : ?>
									<tr>
										<td><?php echo esc_html( isset( $event['recorded_at'] ) ? (string) $event['recorded_at'] : '' ); ?></td>
										<td><?php echo esc_html( isset( $event['category'] ) ? (string) $event['category'] : '' ); ?></td>
										<td><strong><?php echo esc_html( isset( $event['sensor_label'] ) ? (string) $event['sensor_label'] : '' ); ?></strong><div class="asa-activity-muted"><code><?php echo esc_html( isset( $event['sensor_key'] ) ? (string) $event['sensor_key'] : '' ); ?></code></div></td>
										<td><span class="asa-activity-badge"><?php echo esc_html( isset( $event['severity'] ) ? (string) $event['severity'] : '' ); ?></span></td>
										<td><?php echo esc_html( isset( $event['summary'] ) ? (string) $event['summary'] : '' ); ?></td>
										<td>
											<div class="asa-activity-muted"><?php echo esc_html( ! empty( $event['actor']['label'] ) ? (string) $event['actor']['label'] : __( 'System', 'aegisify-audit-agent' ) ); ?></div>
											<div class="asa-activity-context"><?php echo esc_html( wp_json_encode( isset( $event['details'] ) ? $event['details'] : array(), JSON_PRETTY_PRINT ) ); ?></div>
										</td>
									</tr>
								<?php endforeach; ?>
							</tbody>
						</table>

						<?php if ( $total_event_pages > 1 ) : ?>
							<div class="asa-activity-pagination">
								<?php
								$event_base_args = array(
									'page'                     => 'aegisify-audit-agent-wp-activity-log',
									'wp_activity_tab'          => 'events',
									'asa_wp_activity_category' => $selected_category,
									'asa_wp_activity_severity' => $selected_severity,
									'asa_wp_activity_search'   => $search_term,
									'asa_wp_activity_per_page' => $events_per_page,
								);
								?>
								<?php if ( $events_paged > 1 ) : ?>
									<a class="button" href="<?php echo esc_url( add_query_arg( array_merge( $event_base_args, array( 'asa_wp_activity_paged' => $events_paged - 1 ) ), admin_url( 'admin.php' ) ) ); ?>"><?php esc_html_e( 'Previous', 'aegisify-audit-agent' ); ?></a>
								<?php endif; ?>
								<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
								<span><?php echo esc_html( sprintf( __( 'Page %1$d of %2$d', 'aegisify-audit-agent' ), $events_paged, $total_event_pages ) ); ?></span>
								<?php if ( $events_paged < $total_event_pages ) : ?>
									<a class="button" href="<?php echo esc_url( add_query_arg( array_merge( $event_base_args, array( 'asa_wp_activity_paged' => $events_paged + 1 ) ), admin_url( 'admin.php' ) ) ); ?>"><?php esc_html_e( 'Next', 'aegisify-audit-agent' ); ?></a>
								<?php endif; ?>
							</div>
						<?php endif; ?>
					<?php endif; ?>
				</div>
			<?php endif; ?>
		</div>
		<?php
	}

	public function render_logs_page() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'aegisify-audit-agent' ) );
		}

		$categories      = ASA_Logger::get_categories();
		$statuses        = ASA_Logger::get_statuses();
		$retained_logs   = ASA_Logger::get_logs();
		$all_logs        = array_reverse( $retained_logs );
		$summary         = ASA_Logger::get_summary( $retained_logs );
		$retention_days  = ASA_Logger::get_retention_days();
		$queue_rows      = self::get_scan_queue_rows();
		$queue_summary   = array(
			'total_events'   => 0,
			'overdue_events' => 0,
			'stale_states'   => 0,
		);
		foreach ( $queue_rows as $queue_row ) {
			$queue_summary['total_events'] += ! empty( $queue_row['scheduled_count'] ) ? absint( $queue_row['scheduled_count'] ) : 0;
			$queue_summary['overdue_events'] += ! empty( $queue_row['overdue_count'] ) ? absint( $queue_row['overdue_count'] ) : 0;
			if ( ! empty( $queue_row['is_state_stale'] ) ) {
				$queue_summary['stale_states']++;
			}
		}
		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Read-only filters for an admin log viewer.
		$log_message       = isset( $_GET['asa_log_msg'] ) ? sanitize_key( wp_unslash( $_GET['asa_log_msg'] ) ) : '';
		$queue_notice_key  = isset( $_GET['asa_queue_key'] ) ? sanitize_key( wp_unslash( $_GET['asa_queue_key'] ) ) : '';
		$selected_category = isset( $_GET['asa_log_category'] ) ? sanitize_key( wp_unslash( $_GET['asa_log_category'] ) ) : '';
		$selected_status   = isset( $_GET['asa_log_status'] ) ? sanitize_key( wp_unslash( $_GET['asa_log_status'] ) ) : '';
		$search_term       = isset( $_GET['asa_log_search'] ) ? sanitize_text_field( wp_unslash( $_GET['asa_log_search'] ) ) : '';
		$per_page          = isset( $_GET['asa_log_per_page'] ) ? absint( wp_unslash( $_GET['asa_log_per_page'] ) ) : 25;
		$paged             = isset( $_GET['asa_log_paged'] ) ? max( 1, absint( wp_unslash( $_GET['asa_log_paged'] ) ) ) : 1;
		// phpcs:enable WordPress.Security.NonceVerification.Recommended

		if ( ! in_array( $per_page, array( 25, 50 ), true ) ) {
			$per_page = 25;
		}

		$filtered_logs = array_values(
			array_filter(
				$all_logs,
				function ( $log ) use ( $selected_category, $selected_status, $search_term ) {
					if ( '' !== $selected_category && ( empty( $log['category'] ) || $selected_category !== sanitize_key( (string) $log['category'] ) ) ) {
						return false;
					}
					if ( '' !== $selected_status && ( empty( $log['status'] ) || $selected_status !== sanitize_key( (string) $log['status'] ) ) ) {
						return false;
					}
					if ( '' === $search_term ) {
						return true;
					}

					$haystack = strtolower(
						implode(
							' ',
							array(
								isset( $log['message'] ) ? (string) $log['message'] : '',
								isset( $log['source'] ) ? (string) $log['source'] : '',
								isset( $log['action'] ) ? (string) $log['action'] : '',
								wp_json_encode( isset( $log['context'] ) ? $log['context'] : array() ),
							)
						)
					);

					return false !== strpos( $haystack, strtolower( $search_term ) );
				}
			)
		);

		$total_logs  = count( $filtered_logs );
		$total_pages = max( 1, (int) ceil( $total_logs / $per_page ) );
		$paged       = min( $paged, $total_pages );
		$offset      = ( $paged - 1 ) * $per_page;
		$page_logs   = array_slice( $filtered_logs, $offset, $per_page );
		?>
		<div class="wrap asa-wrap">
			<h1 class="asa-title"><?php esc_html_e( 'Aegisify Audit Agent Settings and Logs', 'aegisify-audit-agent' ); ?></h1>
			<?php if ( 'settings_saved' === $log_message ) : ?>
				<div class="notice notice-success is-dismissible"><p><?php esc_html_e( 'Log settings were saved and the retention policy was applied immediately.', 'aegisify-audit-agent' ); ?></p></div>
			<?php endif; ?>
			<?php if ( in_array( $log_message, array( 'queue_cleared', 'queue_stale_cleared', 'queue_reset', 'queue_updated' ), true ) ) : ?>
				<div class="notice notice-success is-dismissible"><p>
					<?php
					$queue_notice_labels = self::get_scan_queue_definitions();
					$queue_notice_label  = ! empty( $queue_notice_labels[ $queue_notice_key ]['label'] ) ? $queue_notice_labels[ $queue_notice_key ]['label'] : __( 'Selected queue', 'aegisify-audit-agent' );
					if ( 'queue_cleared' === $log_message ) {
						/* translators: Dynamic values are inserted into the translated message. */
						echo esc_html( sprintf( __( '%s was cleared from the Logs page.', 'aegisify-audit-agent' ), $queue_notice_label ) );
					} elseif ( 'queue_stale_cleared' === $log_message ) {
						/* translators: Dynamic values are inserted into the translated message. */
						echo esc_html( sprintf( __( 'Stale scheduled events were cleared for %s.', 'aegisify-audit-agent' ), $queue_notice_label ) );
					} elseif ( 'queue_reset' === $log_message ) {
						/* translators: Dynamic values are inserted into the translated message. */
						echo esc_html( sprintf( __( '%s state was reset from the Logs page.', 'aegisify-audit-agent' ), $queue_notice_label ) );
					} else {
						echo esc_html( __( 'Queue management was updated.', 'aegisify-audit-agent' ) );
					}
					?>
				</p></div>
			<?php elseif ( 'queue_invalid' === $log_message ) : ?>
				<div class="notice notice-error is-dismissible"><p><?php esc_html_e( 'The requested queue action was invalid and no changes were made.', 'aegisify-audit-agent' ); ?></p></div>
			<?php endif; ?>
			<style>
				.asa-wrap .asa-title,.asa-wrap h2,.asa-wrap h3{color:#7A0099 !important}.asa-log-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:16px;margin:16px 0}.asa-log-card{background:#fff;border:1px solid #dcdcde;border-radius:16px;padding:18px;box-shadow:0 8px 24px rgba(0,0,0,.05)}.asa-log-stat{font-size:28px;font-weight:700;margin:0 0 6px}.asa-log-filters{display:flex;gap:10px;align-items:end;flex-wrap:wrap;margin:0 0 16px}.asa-log-filters label{display:flex;flex-direction:column;gap:6px;font-weight:600}.asa-log-filters input,.asa-log-filters select{min-width:180px}.asa-log-table{width:100%;border-collapse:collapse;table-layout:fixed}.asa-log-table th,.asa-log-table td{padding:10px 12px;border-bottom:1px solid #e5e5e5;vertical-align:top;text-align:left;word-break:break-word}.asa-log-table th:nth-child(1){width:14%}.asa-log-table th:nth-child(2){width:8%}.asa-log-table th:nth-child(3){width:8%}.asa-log-table th:nth-child(4){width:12%}.asa-log-table th:nth-child(5){width:12%}.asa-log-table th:nth-child(6){width:26%}.asa-log-table th:nth-child(7){width:20%}.asa-log-badge{display:inline-block;border-radius:999px;padding:3px 9px;font-size:11px;font-weight:700;line-height:1.2}.asa-log-badge--info{background:#eef2ff;color:#3730a3}.asa-log-badge--success{background:#ecfdf5;color:#166534}.asa-log-badge--warning{background:#fff7ed;color:#c2410c}.asa-log-badge--error{background:#fef2f2;color:#b91c1c}.asa-log-badge--idle{background:#f4f4f5;color:#3f3f46}.asa-log-badge--queued{background:#eff6ff;color:#1d4ed8}.asa-log-badge--running{background:#ecfeff;color:#0f766e}.asa-log-badge--completed{background:#ecfdf5;color:#166534}.asa-log-badge--failed{background:#fef2f2;color:#b91c1c}.asa-log-pill{display:inline-block;border-radius:999px;padding:4px 10px;background:#f4f4f5;margin:0 8px 8px 0}.asa-log-context{max-height:260px;overflow:auto;white-space:pre-wrap;background:#fafafa;border:1px solid #e5e5e5;border-radius:12px;padding:10px;font-size:12px}.asa-log-pagination{display:flex;gap:8px;align-items:center;flex-wrap:wrap;margin-top:16px}.asa-log-note{margin:12px 0 0;color:#50575e}.asa-queue-table{width:100%;border-collapse:collapse;table-layout:auto}.asa-queue-table th,.asa-queue-table td{padding:10px 12px;border-bottom:1px solid #e5e5e5;vertical-align:top;text-align:left}.asa-queue-actions{display:flex;gap:8px;flex-wrap:wrap}.asa-queue-actions form{margin:0}.asa-queue-meta{font-size:12px;color:#50575e;line-height:1.5}.asa-queue-warning{color:#b91c1c;font-weight:600}@media (max-width:1100px){.asa-log-table{table-layout:auto}}
			</style>

			<div class="asa-log-grid">
				<div class="asa-log-card"><div class="asa-log-stat"><?php echo esc_html( (string) $summary['total'] ); ?></div><div><?php esc_html_e( 'Total retained log entries', 'aegisify-audit-agent' ); ?></div></div>
				<div class="asa-log-card"><div class="asa-log-stat"><?php echo esc_html( (string) $summary['error'] ); ?></div><div><?php esc_html_e( 'Errors captured', 'aegisify-audit-agent' ); ?></div></div>
				<div class="asa-log-card"><div class="asa-log-stat"><?php echo esc_html( (string) $summary['warning'] ); ?></div><div><?php esc_html_e( 'Warnings captured', 'aegisify-audit-agent' ); ?></div></div>
				<div class="asa-log-card"><div class="asa-log-stat"><?php echo esc_html( (string) $summary['success'] ); ?></div><div><?php esc_html_e( 'Successful operations captured', 'aegisify-audit-agent' ); ?></div></div>
			</div>


			<div class="asa-log-card" style="margin-bottom:16px;">
				<h2 style="margin-top:0;"><?php esc_html_e( 'Queue Management', 'aegisify-audit-agent' ); ?></h2>
				<div class="asa-log-grid" style="margin-top:12px;">
					<div><strong><?php echo esc_html( (string) $queue_summary['total_events'] ); ?></strong><div class="asa-queue-meta"><?php esc_html_e( 'Scheduled queue events', 'aegisify-audit-agent' ); ?></div></div>
					<div><strong><?php echo esc_html( (string) $queue_summary['overdue_events'] ); ?></strong><div class="asa-queue-meta"><?php esc_html_e( 'Overdue queued events', 'aegisify-audit-agent' ); ?></div></div>
					<div><strong><?php echo esc_html( (string) $queue_summary['stale_states'] ); ?></strong><div class="asa-queue-meta"><?php esc_html_e( 'Stale queue states', 'aegisify-audit-agent' ); ?></div></div>
				</div>
				<p class="asa-log-note"><?php esc_html_e( 'Use this table to monitor queued vulnerability, static analysis, and agent scan events. Clear Queue removes scheduled cron items. Reset State is for stale disabled states where the queue is stuck but no cron event remains.', 'aegisify-audit-agent' ); ?></p>
				<table class="asa-queue-table">
					<thead>
						<tr>
							<th><?php esc_html_e( 'Queue', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'State', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Requested', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Next Cron Run', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Queued Events', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Context', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Actions', 'aegisify-audit-agent' ); ?></th>
						</tr>
					</thead>
					<tbody>
						<?php foreach ( $queue_rows as $queue_row ) : ?>
							<?php $queue_status = ! empty( $queue_row['status'] ) ? sanitize_key( (string) $queue_row['status'] ) : 'idle'; ?>
							<tr>
								<td>
									<strong><?php echo esc_html( $queue_row['label'] ); ?></strong>
									<div class="asa-queue-meta"><code><?php echo esc_html( $queue_row['hook'] ); ?></code></div>
								</td>
								<td>
									<span class="asa-log-badge asa-log-badge--<?php echo esc_attr( in_array( $queue_status, array( 'idle', 'queued', 'running', 'completed', 'failed' ), true ) ? $queue_status : 'info' ); ?>"><?php echo esc_html( ucfirst( $queue_status ) ); ?></span>
									<div class="asa-queue-meta"><?php echo esc_html( ! empty( $queue_row['state']['message'] ) ? (string) $queue_row['state']['message'] : '—' ); ?></div>
									<?php if ( ! empty( $queue_row['is_state_stale'] ) ) : ?>
										<div class="asa-queue-warning"><?php esc_html_e( 'Stale state detected: the queue is marked busy but no cron event is scheduled.', 'aegisify-audit-agent' ); ?></div>
									<?php endif; ?>
								</td>
								<td>
									<?php echo esc_html( ! empty( $queue_row['requested_at'] ) ? $queue_row['requested_at'] : '—' ); ?>
									<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
									<div class="asa-queue-meta"><?php echo esc_html( sprintf( __( 'Started: %1$s | Completed: %2$s', 'aegisify-audit-agent' ), ! empty( $queue_row['started_at'] ) ? $queue_row['started_at'] : '—', ! empty( $queue_row['completed_at'] ) ? $queue_row['completed_at'] : '—' ) ); ?></div>
								</td>
								<td>
									<?php echo esc_html( ! empty( $queue_row['next_run'] ) ? $queue_row['next_run'] : '—' ); ?>
									<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
									<div class="asa-queue-meta"><?php echo esc_html( sprintf( __( 'Overdue events: %d', 'aegisify-audit-agent' ), ! empty( $queue_row['overdue_count'] ) ? absint( $queue_row['overdue_count'] ) : 0 ) ); ?></div>
								</td>
								<td><?php echo esc_html( (string) ( ! empty( $queue_row['scheduled_count'] ) ? absint( $queue_row['scheduled_count'] ) : 0 ) ); ?></td>
								<td>
									<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
									<div class="asa-queue-meta"><?php echo esc_html( sprintf( __( 'Remote Job: %1$s', 'aegisify-audit-agent' ), ! empty( $queue_row['remote_job_id'] ) ? (string) absint( $queue_row['remote_job_id'] ) : '—' ) ); ?></div>
									<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
									<div class="asa-queue-meta"><?php echo esc_html( sprintf( __( 'Domain: %1$s', 'aegisify-audit-agent' ), ! empty( $queue_row['request_domain'] ) ? (string) $queue_row['request_domain'] : '—' ) ); ?></div>
									<?php if ( ! empty( $queue_row['state']['last_error'] ) ) : ?>
										<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
										<div class="asa-queue-warning"><?php echo esc_html( sprintf( __( 'Last error: %s', 'aegisify-audit-agent' ), (string) $queue_row['state']['last_error'] ) ); ?></div>
									<?php endif; ?>
								</td>
								<td>
									<div class="asa-queue-actions">
										<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
											<?php wp_nonce_field( 'asa_manage_scan_queue', 'asa_manage_scan_queue_nonce' ); ?>
											<input type="hidden" name="action" value="asa_manage_scan_queue" />
											<input type="hidden" name="asa_queue_key" value="<?php echo esc_attr( $queue_row['key'] ); ?>" />
											<input type="hidden" name="asa_queue_action" value="clear_queue" />
											<button type="submit" class="button button-secondary" <?php disabled( empty( $queue_row['scheduled_count'] ) ); ?>><?php esc_html_e( 'Clear Queue', 'aegisify-audit-agent' ); ?></button>
										</form>
										<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
											<?php wp_nonce_field( 'asa_manage_scan_queue', 'asa_manage_scan_queue_nonce' ); ?>
											<input type="hidden" name="action" value="asa_manage_scan_queue" />
											<input type="hidden" name="asa_queue_key" value="<?php echo esc_attr( $queue_row['key'] ); ?>" />
											<input type="hidden" name="asa_queue_action" value="clear_stale" />
											<button type="submit" class="button button-secondary" <?php disabled( empty( $queue_row['overdue_count'] ) ); ?>><?php esc_html_e( 'Clear Stale', 'aegisify-audit-agent' ); ?></button>
										</form>
										<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
											<?php wp_nonce_field( 'asa_manage_scan_queue', 'asa_manage_scan_queue_nonce' ); ?>
											<input type="hidden" name="action" value="asa_manage_scan_queue" />
											<input type="hidden" name="asa_queue_key" value="<?php echo esc_attr( $queue_row['key'] ); ?>" />
											<input type="hidden" name="asa_queue_action" value="reset_state" />
											<button type="submit" class="button" <?php disabled( ! empty( $queue_row['scheduled_count'] ) && empty( $queue_row['is_state_stale'] ) ); ?>><?php esc_html_e( 'Reset State', 'aegisify-audit-agent' ); ?></button>
										</form>
									</div>
								</td>
							</tr>
						<?php endforeach; ?>
					</tbody>
				</table>
			</div>

			<div class="asa-log-card" style="margin-bottom:16px;">
				<h2 style="margin-top:0;"><?php esc_html_e( 'Categories', 'aegisify-audit-agent' ); ?></h2>
				<?php foreach ( $categories as $category_key => $category_label ) : ?>
					<span class="asa-log-pill"><?php echo esc_html( $category_label . ': ' . ( isset( $summary['categories'][ $category_key ] ) ? (string) $summary['categories'][ $category_key ] : '0' ) ); ?></span>
				<?php endforeach; ?>
				<p class="asa-log-note"><?php esc_html_e( 'This viewer keeps the most recent retained agent events and redacts credential-like values before they are stored.', 'aegisify-audit-agent' ); ?></p>
			</div>

			<div class="asa-log-card" style="margin-bottom:16px;">
				<h2 style="margin-top:0;"><?php esc_html_e( 'Retention', 'aegisify-audit-agent' ); ?></h2>
				<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" class="asa-log-filters">
					<?php wp_nonce_field( 'asa_save_log_settings', 'asa_save_log_settings_nonce' ); ?>
					<input type="hidden" name="action" value="asa_save_log_settings" />
					<label>
						<span><?php esc_html_e( 'Delete logs older than', 'aegisify-audit-agent' ); ?></span>
						<input type="number" min="1" max="365" step="1" name="asa_log_retention_days" value="<?php echo esc_attr( (string) $retention_days ); ?>" />
					</label>
					<button type="submit" class="button button-primary"><?php esc_html_e( 'Save Retention', 'aegisify-audit-agent' ); ?></button>
				</form>
				<p class="asa-log-note"><?php esc_html_e( 'Default retention is 7 days. Saving a smaller value immediately removes older retained log entries, including when you change it to 1 day.', 'aegisify-audit-agent' ); ?></p>
			</div>

			<div class="asa-log-card">
				<form method="get" class="asa-log-filters">
					<input type="hidden" name="page" value="aegisify-audit-agent-logs" />
					<label>
						<span><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></span>
						<select name="asa_log_category">
							<option value=""><?php esc_html_e( 'All categories', 'aegisify-audit-agent' ); ?></option>
							<?php foreach ( $categories as $category_key => $category_label ) : ?>
								<option value="<?php echo esc_attr( $category_key ); ?>" <?php selected( $selected_category, $category_key ); ?>><?php echo esc_html( $category_label ); ?></option>
							<?php endforeach; ?>
						</select>
					</label>
					<label>
						<span><?php esc_html_e( 'Status', 'aegisify-audit-agent' ); ?></span>
						<select name="asa_log_status">
							<option value=""><?php esc_html_e( 'All statuses', 'aegisify-audit-agent' ); ?></option>
							<?php foreach ( $statuses as $status_key => $status_label ) : ?>
								<option value="<?php echo esc_attr( $status_key ); ?>" <?php selected( $selected_status, $status_key ); ?>><?php echo esc_html( $status_label ); ?></option>
							<?php endforeach; ?>
						</select>
					</label>
					<label>
						<span><?php esc_html_e( 'Search', 'aegisify-audit-agent' ); ?></span>
						<input type="search" name="asa_log_search" value="<?php echo esc_attr( $search_term ); ?>" />
					</label>
					<label>
						<span><?php esc_html_e( 'Show', 'aegisify-audit-agent' ); ?></span>
						<select name="asa_log_per_page">
							<?php foreach ( array( 25, 50 ) as $row_count ) : ?>
								<option value="<?php echo esc_attr( (string) $row_count ); ?>" <?php selected( $per_page, $row_count ); ?>><?php echo esc_html( (string) $row_count ); ?></option>
							<?php endforeach; ?>
						</select>
					</label>
					<button type="submit" class="button button-primary"><?php esc_html_e( 'Apply Filters', 'aegisify-audit-agent' ); ?></button>
					<a class="button" href="<?php echo esc_url( admin_url( 'admin.php?page=aegisify-audit-agent-logs' ) ); ?>"><?php esc_html_e( 'Reset', 'aegisify-audit-agent' ); ?></a>
				</form>

				<p class="asa-log-note">
					<?php
					printf(
						/* translators: Dynamic values are inserted into the translated message. */
						esc_html__( 'Showing %1$d filtered log entries out of %2$d retained entries.', 'aegisify-audit-agent' ),
						(int) $total_logs,
						(int) $summary['total']
					);
					?>
				</p>

				<table class="asa-log-table">
					<thead>
						<tr>
							<th><?php esc_html_e( 'Time', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Status', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Category', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Source', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Action', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Message', 'aegisify-audit-agent' ); ?></th>
							<th><?php esc_html_e( 'Context', 'aegisify-audit-agent' ); ?></th>
						</tr>
					</thead>
					<tbody>
						<?php if ( empty( $page_logs ) ) : ?>
							<tr><td colspan="7"><?php esc_html_e( 'No agent log entries matched the current filters yet.', 'aegisify-audit-agent' ); ?></td></tr>
						<?php else : ?>
							<?php foreach ( $page_logs as $log ) : ?>
								<?php
								$status_key   = ! empty( $log['status'] ) ? sanitize_key( (string) $log['status'] ) : 'info';
								$category_key = ! empty( $log['category'] ) ? sanitize_key( (string) $log['category'] ) : 'system';
								$repeat_count = ! empty( $log['repeat_count'] ) ? absint( $log['repeat_count'] ) : 1;
								?>
								<tr>
									<td>
										<?php echo esc_html( ! empty( $log['timestamp'] ) ? (string) $log['timestamp'] : '' ); ?>
										<?php if ( $repeat_count > 1 ) : ?>
											<br /><span class="asa-log-note"><?php echo esc_html( '×' . $repeat_count . ' | ' . ( ! empty( $log['last_seen_at'] ) ? (string) $log['last_seen_at'] : '' ) ); ?></span>
										<?php endif; ?>
									</td>
									<td><span class="asa-log-badge asa-log-badge--<?php echo esc_attr( $status_key ); ?>"><?php echo esc_html( isset( $statuses[ $status_key ] ) ? $statuses[ $status_key ] : ucfirst( $status_key ) ); ?></span></td>
									<td><?php echo esc_html( isset( $categories[ $category_key ] ) ? $categories[ $category_key ] : ucfirst( $category_key ) ); ?></td>
									<td><?php echo esc_html( ! empty( $log['source'] ) ? (string) $log['source'] : '—' ); ?></td>
									<td><?php echo esc_html( ! empty( $log['action'] ) ? (string) $log['action'] : '—' ); ?></td>
									<td><?php echo esc_html( ! empty( $log['message'] ) ? (string) $log['message'] : '' ); ?></td>
									<td>
										<?php if ( ! empty( $log['context'] ) && is_array( $log['context'] ) ) : ?>
											<details>
												<summary><?php esc_html_e( 'View Context', 'aegisify-audit-agent' ); ?></summary>
												<div class="asa-log-context"><?php echo esc_html( wp_json_encode( $log['context'], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ); ?></div>
											</details>
										<?php else : ?>
											<?php esc_html_e( '—', 'aegisify-audit-agent' ); ?>
										<?php endif; ?>
									</td>
								</tr>
							<?php endforeach; ?>
						<?php endif; ?>
					</tbody>
				</table>

				<?php if ( $total_pages > 1 ) : ?>
					<div class="asa-log-pagination">
						<?php
						$base_args = array(
							'page'             => 'aegisify-audit-agent-logs',
							'asa_log_category' => $selected_category,
							'asa_log_status'   => $selected_status,
							'asa_log_search'   => $search_term,
							'asa_log_per_page' => $per_page,
						);
						?>
						<?php if ( $paged > 1 ) : ?>
							<a class="button" href="<?php echo esc_url( add_query_arg( array_merge( $base_args, array( 'asa_log_paged' => $paged - 1 ) ), admin_url( 'admin.php' ) ) ); ?>"><?php esc_html_e( 'Previous', 'aegisify-audit-agent' ); ?></a>
						<?php endif; ?>
						<?php /* translators: Dynamic values are inserted into the translated message. */ ?>
						<span><?php echo esc_html( sprintf( __( 'Page %1$d of %2$d', 'aegisify-audit-agent' ), $paged, $total_pages ) ); ?></span>
						<?php if ( $paged < $total_pages ) : ?>
							<a class="button" href="<?php echo esc_url( add_query_arg( array_merge( $base_args, array( 'asa_log_paged' => $paged + 1 ) ), admin_url( 'admin.php' ) ) ); ?>"><?php esc_html_e( 'Next', 'aegisify-audit-agent' ); ?></a>
						<?php endif; ?>
					</div>
				<?php endif; ?>
			</div>
		</div>
		<?php
	}

}
