<?php

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

trait WPMR_Admin_UI {

	/**
	 * Register the plugin's admin menu pages and attach per-screen bootstrapping hooks.
	 *
	 * Registers the top-level Malcure menu plus sub-pages (scanner, hardening, logs, help,
	 * license, diagnostics). Captures each page's hook suffix into `$this->page_hooks` and
	 * registers `load-{$hook}` actions so `setup_screen_for_pages()` can set up metaboxes.
	 *
	 * Note: adds a temporary `sanitize_title` filter (`screen_obj_fix`) to strip HTML from
	 * menu titles containing markup (e.g. the `awaiting-mod` counter).
	 *
	 * Better name: register_admin_pages()
	 *
	 * @return void
	 */
	function add_admin_pages() {
		add_filter( 'sanitize_title', array( $this, 'screen_obj_fix' ), 9, 3 );

		$mtitle  = empty( $this->definition_updates_available() ) ? 'Malcure' : 'Malcure <span class="awaiting-mod">1</span>';
		$smtitle = empty( $this->definition_updates_available() ) ? 'Malware Scanner' : 'Malware Scanner <span class="awaiting-mod">1</span>';

		$hook_suffix             = add_menu_page( 'Malcure', $mtitle, $this->cap, 'wpmr', array( $this, 'scanner_page' ), $this->url . 'assets/icon-dark-trans.svg', 79 );
		$this->page_hooks['top'] = $hook_suffix;

		$attacks = $this->get_setting( 'attacks' );
		$attacks = empty( $attacks ) ? '' : ' <span class="awaiting-mod">' . $attacks . '</span>';

		$hook_suffix               = add_submenu_page( 'wpmr', 'Malcure Malware Scanner', $smtitle, $this->cap, 'wpmr', array( $this, 'scanner_page' ) );
		$this->page_hooks['first'] = $hook_suffix;
		if ( $this->is_registered() ) {
			$this->add_stateful_scanner_menu();

			$hook_suffix             = add_submenu_page( 'wpmr', 'Malcure Event Monitor', 'Event Monitor', $this->cap, 'wpmr_logs', array( $this, 'wpmr_logs_page' ) );
			$this->page_hooks['log'] = $hook_suffix;
		}

		if ( $this->is_registered() ) {
			$hook_suffix                   = add_submenu_page( 'wpmr', 'Malcure Security Hardening', 'Security Hardening' . $attacks, $this->cap, 'wpmr_hardening', array( $this, 'wpmr_hardening_page' ) );
			$this->page_hooks['hardening'] = $hook_suffix;
		}

		if ( $this->is_advanced_edition() ) {
			$hook_suffix                       = add_submenu_page( 'wpmr', 'Malcure Notification Settings', 'Notifications', $this->cap, 'wpmr_notifications', array( $this, 'render_notifications_page' ) );
			$this->page_hooks['notifications'] = $hook_suffix;
		}

		$hook_suffix                 = add_submenu_page( 'wpmr', 'Malcure License Key', 'License Key', $this->cap, 'wpmr_license', array( $this, 'wpmr_license_page' ) );
		$this->page_hooks['license'] = $hook_suffix;

		if ( $this->is_registered() ) {
			$hook_suffix             = add_submenu_page( 'wpmr', 'Malcure Frequently Asked Questions', 'Help & FAQs', $this->cap, 'wpmr_help', array( $this, 'wpmr_help_page' ) );
			$this->page_hooks['faq'] = $hook_suffix;
		}

		$hook_suffix                     = add_submenu_page( 'wpmr', 'Malcure Diagnostics', 'Diagnostics', $this->cap, 'wpmr_diagnostics', array( $this, 'wpmr_diags_page' ) );
		$this->page_hooks['diagnostics'] = $hook_suffix;

		foreach ( $this->page_hooks as $key => $hook ) {
			add_action( 'load-' . $hook, array( $this, 'setup_screen_for_pages' ) ); // This should go before trigger_action_metaboxes_hook
		}

		remove_filter( 'sanitize_title', array( $this, 'screen_obj_fix' ), 9 );
	}

	/**
	 * Register the Stateful Scanner admin submenu and screen hooks.
	 *
	 * Called during `admin_menu` from `add_admin_pages()`.
	 *
	 * Side effects:
	 * - Registers the submenu page under the plugin's top-level menu.
	 * - Hooks `setup_stateful_scanner_screen()` into the page load event.
	 *
	 * Better name: register_stateful_scanner_admin_menu()
	 *
	 * @return void
	 */
	public function add_stateful_scanner_menu() {
		$this->stateful_scanner_hook = add_submenu_page(
			'wpmr',
			'Malware Monitoring',
			'Malware Monitoring',
			$this->cap,
			'wpmr_stateful_scanner',
			array( $this, 'render_stateful_scanner_page' )
		);
		add_action( 'load-' . $this->stateful_scanner_hook, array( $this, 'setup_stateful_scanner_screen' ) );
	}

	/**
	 * Configure the current admin screen for Malcure pages.
	 *
	 * Runs on `load-{$hook}` for every page created by `add_admin_pages()`. Adds JS dependency
	 * enqueues and registers the relevant metaboxes for each page context.
	 *
	 * Better name: register_screen_metaboxes()
	 *
	 * @return void
	 */
	function setup_screen_for_pages() {
		$screen = get_current_screen();
		if ( $screen && preg_match( '/wpmr/', $screen->id ) ) {
			add_action( 'admin_print_scripts-' . str_replace( '-network', '', $screen->id ), array( $this, 'wpmr_enqueue_js_dependencies' ) );
		}

		foreach ( $this->page_hooks as $key => $hook ) {

			if ( $this->is_registered() ) {
				if ( $key == 'top' || $key == 'first' ) { // $hook = toplevel_page_wpmr

					add_meta_box( 'wpmr_results_box', 'Status Details', array( $this, 'meta_box_results' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_debug_box', 'Advanced Options', array( $this, 'meta_box_pro' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_inspect_box', 'Malware Inspector &amp; Cleanup Operations', array( $this, 'meta_box_inspect' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_diagnostics_box', 'System Status', array( $this, 'meta_box_diagnostics' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_updates_box', 'Updates', array( $this, 'meta_box_updates' ), $hook, 'side', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook, 'side', 'high' );

					add_meta_box( 'wpmr_results_box', 'Status Details', array( $this, 'meta_box_results' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_debug_box', 'Advanced Options', array( $this, 'meta_box_pro' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_inspect_box', 'Malware Inspector &amp; Cleanup Operations', array( $this, 'meta_box_inspect' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_diagnostics_box', 'System Status', array( $this, 'meta_box_diagnostics' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_updates_box', 'Updates', array( $this, 'meta_box_updates' ), $hook . '-network', 'side', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook . '-network', 'side', 'high' );

				}
				if ( $key == 'hardening' ) { // $hook = malcure_page_wpmr_hardening
					add_meta_box( 'wpmr_hardening_box', 'Malcure Security Hardening Settings', array( $this, 'meta_box_hardening' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook, 'side', 'high' );

					add_meta_box( 'wpmr_hardening_box', 'Malcure Security Hardening Settings', array( $this, 'meta_box_hardening' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook . '-network', 'side', 'high' );
				}
				if ( $key == 'log' ) { // $hook = malcure_page_wpmr_logs
					add_meta_box( 'wpmr_events_box', 'Malcure Event Log', array( $this, 'meta_box_events' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_logs_box', 'Malcure Scan Log', array( $this, 'meta_box_logs' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook, 'side', 'high' );

					add_meta_box( 'wpmr_events_box', 'Malcure Event Log', array( $this, 'meta_box_events' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_logs_box', 'Malcure Scan Log', array( $this, 'meta_box_logs' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook . '-network', 'side', 'high' );
				}
				if ( $key == 'faq' ) { // $hook = malcure_page_wpmr_help
					add_meta_box( 'wpmr_faq_box', 'Frequently Asked Questions', array( $this, 'meta_box_faq' ), $hook, 'main', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook, 'side', 'high' );

					add_meta_box( 'wpmr_faq_box', 'Frequently Asked Questions', array( $this, 'meta_box_faq' ), $hook . '-network', 'main', 'high' );
					add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook . '-network', 'side', 'high' );
				}
			} elseif ( $key == 'top' || $key == 'first' ) {
				// $hook = toplevel_page_wpmr
					add_meta_box( 'wpmr_updates_box', 'Updates', array( $this, 'meta_box_updates' ), $hook, 'side', 'high' );
					add_meta_box( 'wpmr_updates_box', 'Updates', array( $this, 'meta_box_updates' ), $hook . '-network', 'side', 'high' );
			}
			if ( $key == 'notifications' ) {
				add_meta_box( 'wpmr_scan_notify', 'Scheduled Scan Notifications (Recommended)', array( $this, 'render_scan_notify_metabox' ), $hook, 'main', 'high' );
				add_meta_box( 'wpmr_pulse_notify', 'Weekly Security Pulse (Recommended)', array( $this, 'render_pulse_notify_metabox' ), $hook, 'main', 'high' );
				add_meta_box( 'wpmr_notify_test', 'Test Email', array( $this, 'render_notify_test_metabox' ), $hook, 'side', 'high' );

				add_meta_box( 'wpmr_scan_notify', 'Scheduled Scan Notifications (Recommended)', array( $this, 'render_scan_notify_metabox' ), $hook . '-network', 'main', 'high' );
				add_meta_box( 'wpmr_pulse_notify', 'Weekly Security Pulse (Recommended)', array( $this, 'render_pulse_notify_metabox' ), $hook . '-network', 'main', 'high' );
				add_meta_box( 'wpmr_notify_test', 'Test Email', array( $this, 'render_notify_test_metabox' ), $hook . '-network', 'side', 'high' );
			}
			if ( $key == 'license' ) { // $hook = meta_box_license
				add_meta_box( 'wpmr_license_box', 'Please Enter Your Malcure License Key Here', array( $this, 'meta_box_license' ), $hook, 'main', 'high' );
				add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook, 'side', 'high' );

				add_meta_box( 'wpmr_license_box', 'Please Enter Your Malcure License Key Here', array( $this, 'meta_box_license' ), $hook . '-network', 'main', 'high' );
				add_meta_box( 'wpmr_ad_box', 'Malcure Advanced Edition', array( $this, 'wpmr_ad_common' ), $hook . '-network', 'side', 'high' );
			}
		}
	}

	/**
	 * Render the main Malware Scanner admin page.
	 *
	 * This is the UI entrypoint for DeepScan. It primes checksums/definitions, triggers a
	 * definitions check, and renders the primary admin UI container + metabox regions.
	 *
	 * Better name: render_scanner_page()
	 *
	 * @return void
	 */
	function scanner_page() {
		$screen = get_current_screen();
		// $this->get_all_checksums();
		$this->maybe_load_default_definitions();
		// $this->check_definitions();
		?>
		<div class="wrap">
			<h1 id="page_title">Malcure Malware Scanner</h1>
			<div id="dashboard_wrap">
				<table id="ui_container">
					<tr>
						<td class="col_first"><span id="logo"></span></td>
						<td rowspan="2" id="speedo"><div id="dial">
							<div class="gauge_a"></div>
							<div class="gauge_c"></div>
							<div class="gauge_data">
								<h1 id="percent"></h1>
							</div>
							</div>
							<div id="controls">
								<div id="file_scroll"></div>
								<div id="wpmr_batchsize_wrap"><input title="1. You will not be able to change the batch size when a scan is in progress.&#10;2. Your webhost may block too many requests. Be careful." type="range" id="wpmr_batchsize" value="51" name="points" min="1" max="100" /></div>
								<p id="scan_hint" title="Your webhost may block too many requests. Be careful.">Scan <span id="scan_hint_value">5</span> Items per req.</p>
								<p id="scan_controls"><input title="Start Malware Scan" type="submit" value="Initiate DeepScan™&rarr;" id="scan_control_deep" data-state="0" class="malcure-button-primary scan_control" /></p>
							</div>
						</td>
						<td id="wpmr_skinner_container">
							<div id="wpmr_skinner_wrap">
								<p>Interface :</p>
								<?php
								$skin = $this->get_setting( 'wpmr_skin' );
								?>
								<select id="wpmr_skin">
									<option <?php selected( $skin, 'classic' ); ?> value="classic">Classic</option>
									<option <?php selected( $skin, 'dark' ); ?> value="dark">Dark</option>
								</select>
						
							</div>
						</td>
					</tr>
					<tr>
						<td class="wpmr_engine_stats col_first">
							<table id="wpmr_engine_stats">
								<tr>
									<th><span class="data_head">Checksums</span><span class="colon">:</span></th>
									<td><span id="checksum_count"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Signatures</span><span class="colon">:</span></th>
									<td><span class="sig_count"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Sig Version</span><span class="colon">:</span></th>
									<td><span class="sig_version"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Last Updated</span><span class="colon">:</span></th>
									<td><span class="sig_date"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Database Total</span><span class="colon">:</span></th>
									<td><span id="total_records_count"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Database Range</span><span class="colon">:</span></th>
									<td><span id="total_records"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Range Remaining</span><span class="colon">:</span></th>
									<td><span id="records_remaining"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Total Files</span><span class="colon">:</span></th>
									<td><span class="total_files"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Files Excluded</span><span class="colon">:</span></th>
									<td><span class="files_excluded">0</span></td>
								</tr>
								<tr>
									<th><span class="data_head">Files to scan</span><span class="colon">:</span></th>
									<td><span id="files_to_scan"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Files remaining</span><span class="colon">:</span></th>
									<td><span id="files_remaining"></span></td>
								</tr>
								<tr>
									<th><span class="data_head">Time Elapsed</span><span class="colon">:</span></th>
									<td><span id="time_elapsed">Not Initialised</span></td>
								</tr>
								<tr>
									<th><span class="data_head">Time Remaining</span><span class="colon">:</span></th>
									<td><span id="time_remaining">Not Initialised</span></td>
								</tr>
								<tr>
									<th><span class="data_head">Achieved Speed</span><span class="colon">:</span></th>
									<td><span id="scan_speed">Duck</span></td>
								</tr>
								<tr>
									<th><span class="data_head">Status</span><span class="colon">:</span></th>
									<td><span class="engine_status">Ready</span></td>
								</tr>
							</table>
						</td>
						<td class="col_last">
							<div id="lcd_wrap">
								<div id="lcd"></div>
								<div id="hero_ctas">
									<?php
									if ( $this->get_setting( 'infected' ) ) {
										echo '<a href="' . esc_url( $this->wpmr_url( 'p=107', 'scan-result-cta', 'lcd' ) ) . '" target="_blank" class="malcure-button-primary" id="cta_pluginlcd">Get Expert Cleanup Now &rarr;</a>';
									}
									?>
								</div>
							</div>
						</td>
					</tr>	
				</table> 
				<div class="clear"></div>
			</div>
			<div id="poststuff">
				<div class="metabox-holder columns-2" id="post-body">
					<div class="postbox-container" id="post-body-content">
								<?php
								do_meta_boxes( $screen->id, 'main', null );
								// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
								?>
					</div>
					<!-- #postbox-container -->
					<div id="postbox-container-1" class="postbox-container">
							<?php
							do_meta_boxes( $screen->id, 'side', null );
							// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
							?>
					</div>
				</div>
			</div>
		</div>
		<div id="wpmr_messaging"><div id="wpmr_message_control">&#x2715;</div><div id="wpmr_message_content"></div></div>
		<?php
	}

	/**
	 * Render the Security Hardening admin page.
	 *
	 * Displays the hardening metabox and associated sidebar UI. Runs a definitions check
	 * for up-to-date hardening rules.
	 *
	 * Better name: render_hardening_page()
	 *
	 * @return void
	 */
	function wpmr_hardening_page() {
		$screen = get_current_screen();
		$this->check_definitions();
		?>
		<div class="wrap wpmr_firewall">
			<h1>Malcure Security Hardening &amp; Protection Settings</h1>
			<div id="hardening_branding" class="page_branding" ><?php $this->render_branding(); ?></div>
			<div id="poststuff">
				<div class="metabox-holder columns-2" id="post-body">
					<div class="postbox-container" id="post-body-content">
					<?php
					do_meta_boxes( $screen->id, 'main', null );
					// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
					<!-- #postbox-container -->
					<div id="postbox-container-1" class="postbox-container">
					<?php
						do_meta_boxes( $screen->id, 'side', null );
						// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
				</div>
			</div>
			<script type="text/javascript">
				jQuery(document).ready(function($) { //wrapper
					// close postboxes that should be closed
					$('.if-js-closed').removeClass('if-js-closed').addClass('closed');
					// postboxes setup
					postboxes.add_postbox_toggles('<?php echo esc_js( $screen->id ); ?>');
					$('#main-sortables .postbox').not(':first').addClass('closed');
				});
			</script>			
		</div>
			<?php
	}

	/**
	 * Render the Event Monitor / Logs admin page.
	 *
	 * Displays metaboxes for the event log and scan log with UI toggles.
	 *
	 * Better name: render_logs_page()
	 *
	 * @return void
	 */
	function wpmr_logs_page() {
		$screen = get_current_screen();
		$this->check_definitions();
		?>
		<div class="wrap wpmr-logs">
			<h1>Malcure Event Monitor &amp; Logs</h1>
			<div id="logs_branding" class="page_branding" ><?php $this->render_branding(); ?></div>
			<div id="poststuff">
				<div class="metabox-holder columns-2" id="post-body">
					<div class="postbox-container" id="post-body-content">
					<?php
					do_meta_boxes( $screen->id, 'main', null );
					// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
					<!-- #postbox-container -->
					<div id="postbox-container-1" class="postbox-container">
					<?php
						do_meta_boxes( $screen->id, 'side', null );
						// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
				</div>
			</div>
		</div>
		<script type="text/javascript">
			jQuery(document).ready(function($) { //wrapper
				// close postboxes that should be closed
				$('.if-js-closed').removeClass('if-js-closed').addClass('closed');
				// postboxes setup
				postboxes.add_postbox_toggles('<?php echo esc_js( $screen->id ); ?>');
				// $('#main-sortables .postbox').not(':first').addClass('closed');
				
				// BEGIN log sections
				// Initially hide the content
				$('.postbox').removeClass('closed');
				//$('.log.postbox').removeClass('closed');
				$('.log.postbox').not(':first').addClass('closed');

			});
		</script>
		<?php
	}

	/**
	 * Render the License Key admin page.
	 *
	 * Displays the license metabox and upsell sidebar.
	 *
	 * Better name: render_license_page()
	 *
	 * @return void
	 */
	function wpmr_license_page() {
		$screen = get_current_screen();

		$this->check_definitions();

		?>
		<div class="wrap wpmr_license">
			<h1>Malcure License Key</h1>
			<div id="license_branding" class="page_branding" ><?php $this->render_branding(); ?></div>
			<div id="poststuff">
				<div class="metabox-holder columns-2" id="post-body">
					<div class="postbox-container" id="post-body-content">
					<?php
					do_meta_boxes( $screen->id, 'main', null );
					// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
					<!-- #postbox-container -->
					<div id="postbox-container-1" class="postbox-container">
					<?php
						do_meta_boxes( $screen->id, 'side', null );
						// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
				</div>
			</div>
		</div>
		<script type="text/javascript">
			jQuery(document).ready(function($) { //wrapper
				// close postboxes that should be closed
				$('.if-js-closed').removeClass('if-js-closed').addClass('closed');
				// postboxes setup
				postboxes.add_postbox_toggles('<?php echo esc_js( $screen->id ); ?>');
				$('#main-sortables .postbox').not(':first').addClass('closed');

			});
		</script>
		<?php
	}

	/**
	 * Render the Notifications settings admin page.
	 *
	 * Two-column metabox layout following the existing pattern.
	 * Gated on is_advanced_edition() at menu registration time.
	 *
	 * @return void
	 */
	function render_notifications_page() {
		$screen = get_current_screen();
		?>
		<div class="wrap">
			<h1>Malcure Notification Settings</h1>
			<div id="poststuff">
				<div class="metabox-holder columns-2" id="post-body">
					<div class="postbox-container" id="post-body-content">
					<?php do_meta_boxes( $screen->id, 'main', null ); ?>
					</div>
					<div id="postbox-container-1" class="postbox-container">
					<?php do_meta_boxes( $screen->id, 'side', null ); ?>
					</div>
				</div>
			</div>
		</div>
		<div id="wpmr_messaging"><div id="wpmr_message_control">&#x2715;</div><div id="wpmr_message_content"></div></div>
		<script type="text/javascript">
			jQuery(document).ready(function($) {
				$('.if-js-closed').removeClass('if-js-closed').addClass('closed');
				postboxes.add_postbox_toggles('<?php echo esc_js( $screen->id ); ?>');
				$('#main-sortables .postbox').not(':first').addClass('closed');
			});
		</script>
		<?php
	}


	/**
	 * Render the Help & FAQs admin page.
	 *
	 * Better name: render_help_page()
	 *
	 * @return void
	 */
	function wpmr_help_page() {
		$screen = get_current_screen();
		$this->check_definitions();
		?>
		<div class="wrap wpmr_faq">
			<h1>Malcure Help &amp; FAQs</h1>
			<div id="license_branding" class="page_branding" ><?php $this->render_branding(); ?></div>
			<div id="poststuff">
				<div class="metabox-holder columns-2" id="post-body">
					<div class="postbox-container" id="post-body-content">
					<?php
					do_meta_boxes( $screen->id, 'main', null );
					// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
					<!-- #postbox-container -->
					<div id="postbox-container-1" class="postbox-container">
					<?php
						do_meta_boxes( $screen->id, 'side', null );
						// This function is used to output meta boxes in a particular screen and context (like 'normal', 'side', 'advanced') in the WordPress admin. It's what actually renders the meta boxes on the post edit screen or custom screens. When you call this function, it looks for all the meta boxes that have been added for a specific screen/context and displays them.
					?>
					</div>
				</div>
			</div>
		</div>
		<script type="text/javascript">
			jQuery(document).ready(function($) { //wrapper
				// close postboxes that should be closed
				$('.if-js-closed').removeClass('if-js-closed').addClass('closed');
				// postboxes setup
				postboxes.add_postbox_toggles('<?php echo esc_js( $screen->id ); ?>');
				$('#main-sortables .postbox').not(':first').addClass('closed');
			});
		</script>
		<?php
		$this->debug();
	}

	/**
	 * Fetch short-lived DB diagnostics metrics for the diagnostics page.
	 *
	 * These reads are only used for admin diagnostics output, so a one-minute cache avoids
	 * re-running the same report queries on page refresh without affecting scanner truth.
	 *
	 * @return array<string, mixed>
	 */
	function get_cached_diagnostics_db_metrics() {
		global $wpdb;

		$cache_group = 'wpmr_admin_ui';
		$cache_key   = 'diag_db_metrics_' . md5( $wpdb->prefix . '|' . $wpdb->dbname . '|' . (string) get_current_blog_id() );
		$metrics     = wp_cache_get( $cache_key, $cache_group );

		if ( false !== $metrics && is_array( $metrics ) ) {
			return $metrics;
		}

		$transient_like      = $wpdb->esc_like( '_transient_' ) . '%';
		$site_transient_like = $wpdb->esc_like( '_site_transient_' ) . '%';

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery -- Cached diagnostics intentionally read raw DB server variables and aggregate option storage that WordPress does not expose through higher-level APIs.
		$metrics = array(
			'max_packet'      => $wpdb->get_var( "SHOW VARIABLES LIKE 'max_allowed_packet'", 1 ),
			'innodb_log_val'  => $wpdb->get_var( "SHOW VARIABLES LIKE 'innodb_log_file_size'", 1 ),
			'tmp_table_val'   => $wpdb->get_var( "SHOW VARIABLES LIKE 'tmp_table_size'", 1 ),
			'max_heap_val'    => $wpdb->get_var( "SHOW VARIABLES LIKE 'max_heap_table_size'", 1 ),
			'autoload_mb'     => $wpdb->get_var( "SELECT ROUND(SUM(LENGTH(option_value))/1024/1024,2) FROM {$wpdb->options} WHERE autoload='yes'" ),
			'transient_count' => (int) $wpdb->get_var(
				$wpdb->prepare(
					"SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
					$transient_like,
					$site_transient_like
				)
			),
			'plugin_options'  => (int) $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE '%wpmr%'" ),
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery

		wp_cache_set( $cache_key, $metrics, $cache_group, MINUTE_IN_SECONDS );

		return $metrics;
	}

	/**
	 * Render the Diagnostics admin page.
	 *
	 * Outputs environment and WordPress configuration diagnostics and (when licensed)
	 * additional advanced diagnostics blocks.
	 *
	 * Better name: render_diagnostics_page()
	 *
	 * @return void
	 */
	function wpmr_diags_page() {
		$screen = get_current_screen();
		$this->check_definitions();

		// Initialize results array for diagnostics
		$RESULTS = array();

		// Helper functions
		$add_result = function ( $name, $status, $detail, $fix = '' ) use ( &$RESULTS ) {
			$RESULTS[] = compact( 'name', 'status', 'detail', 'fix' );
		};

		$status_bool = function ( $ok ) {
			return $ok ? 'PASS' : 'FAIL';
		};
		$warn        = function ( $cond ) {
			return $cond ? 'WARN' : 'PASS';
		};
		$bytes_fmt   = function ( $b ) {
			$u = array( 'B', 'KB', 'MB', 'GB', 'TB' );
			$i = 0;
			while ( $b >= 1024 && $i < count( $u ) - 1 ) {
				$b /= 1024;
				++$i; }
			return sprintf( '%.2f %s', $b, $u[ $i ] );
		};

		global $wp_version, $wpdb;

		$sitePath = ABSPATH;
		$parent   = dirname( $sitePath );
		$php_ini  = php_ini_loaded_file() ?: '(none)';

		// 0) Basic environment checks
		$add_result(
			'PHP version',
			version_compare( PHP_VERSION, '7.4', '>=' ) ? 'PASS' : 'WARN',
			'PHP ' . PHP_VERSION,
			'Use PHP 8.1–8.3 for performance and security on WordPress.'
		);
		$add_result( 'SAPI', 'PASS', php_sapi_name() );
		$add_result( 'php.ini loaded', $php_ini ? 'PASS' : 'FAIL', $php_ini, 'Ensure PHP is loading the expected php.ini.' );

		// 1) WordPress-specific paths
		$add_result( 'WordPress root exists', $status_bool( file_exists( $sitePath ) ), $sitePath );
		$add_result( 'WordPress root is dir', $status_bool( is_dir( $sitePath ) ), $sitePath );
		$add_result( 'WordPress root readable', $status_bool( is_readable( $sitePath ) ), $sitePath );

		// 2) Parent directory traversal (important for IIS and some shared hosting)
		$parent_opendir = @opendir( $parent );
		$add_result(
			'Parent folder accessible',
			$parent_opendir !== false ? 'PASS' : 'FAIL',
			$parent,
			'Grant Read & execute permissions on parent directory for web server user.'
		);
		if ( $parent_opendir ) {
			closedir( $parent_opendir ); }

		// 3) WordPress directories opendir() vs scandir()
		$h_wp  = @opendir( $sitePath );
		$sc_wp = @scandir( $sitePath );
		$add_result(
			'WordPress root opendir()',
			$h_wp !== false ? 'PASS' : 'FAIL',
			$sitePath,
			'If FAIL but file_exists/is_readable are true: parent traverse or security software may be blocking.'
		);
		if ( $h_wp ) {
			closedir( $h_wp ); }
		$add_result(
			'WordPress root scandir()',
			$sc_wp !== false ? 'PASS' : 'WARN',
			$sitePath,
			'If WARN with huge directories, use opendir()/readdir() streaming instead of scandir() to avoid memory spikes.'
		);

		// 4) WordPress uploads directory
		$uploads_dir  = wp_upload_dir();
		$uploads_path = $uploads_dir['basedir'];
		$add_result( 'Uploads directory exists', $status_bool( is_dir( $uploads_path ) ), $uploads_path );
		if ( ! function_exists( 'WP_Filesystem' ) ) {
			require_once ABSPATH . 'wp-admin/includes/file.php';
		}
		global $wp_filesystem;
		$uploads_writable     = false;
		$uploads_writable_fix = 'Ensure web server has write permissions to uploads directory.';
		if ( ! empty( $uploads_path ) && WP_Filesystem() && $wp_filesystem ) {
			$uploads_writable = $wp_filesystem->is_writable( $uploads_path );
		} else {
			$uploads_writable_fix = 'Ensure WordPress can initialize WP_Filesystem and the web server has write permissions to uploads directory.';
		}
		$add_result(
			'Uploads directory writable',
			$status_bool( $uploads_writable ),
			$uploads_path,
			$uploads_writable_fix
		);

		// 5) open_basedir / disable_functions gotchas
		$open_basedir = ini_get( 'open_basedir' );
		$add_result(
			'open_basedir restriction',
			$open_basedir ? 'WARN' : 'PASS',
			$open_basedir ?: '(not set)',
			$open_basedir ? 'Ensure WordPress paths are included in open_basedir.' : ''
		);

		$disable_functions = array_filter( array_map( 'trim', explode( ',', (string) ini_get( 'disable_functions' ) ) ) );
		$need_funcs        = array( 'scandir', 'opendir', 'readdir', 'fopen', 'fwrite', 'file_get_contents', 'exec', 'shell_exec' );
		$disabled_hit      = array_values( array_intersect( $need_funcs, $disable_functions ) );
		$add_result(
			'Critical functions disabled',
			empty( $disabled_hit ) ? 'PASS' : 'WARN',
			$disabled_hit ? ( 'Disabled: ' . implode( ', ', $disabled_hit ) ) : 'None critical disabled',
			$disabled_hit ? 'Some disabled functions may affect malware scanning capabilities.' : ''
		);

		// 6) Disk space
		$df = @disk_free_space( $sitePath );
		$add_result(
			'Disk free space',
			$df !== false ? 'PASS' : 'WARN',
			$df !== false ? $bytes_fmt( $df ) : 'Unavailable',
			'Ensure sufficient free space for WordPress operations and temporary files.'
		);

		// 7) WordPress-specific memory and execution limits
		$add_result(
			'PHP max_execution_time',
			'PASS',
			ini_get( 'max_execution_time' ) . ' sec',
			'For malware scanning operations, consider 300+ seconds.'
		);
		$add_result(
			'PHP memory_limit',
			'PASS',
			ini_get( 'memory_limit' ),
			'Use >= 256M for WordPress sites, >= 512M for heavy scanning operations.'
		);
		$add_result(
			'WordPress memory limit',
			'PASS',
			defined( 'WP_MEMORY_LIMIT' ) ? WP_MEMORY_LIMIT : 'Not defined',
			'Set WP_MEMORY_LIMIT in wp-config.php for WordPress-specific operations.'
		);

		// 8) Database connectivity and health
		$db_ok  = $wpdb->check_connection( false );
		$db_err = '';
		if ( $db_ok ) {
			$add_result( 'Database connection', 'PASS', 'Connected to ' . $wpdb->dbname, '' );
		} else {
			$db_err = ! empty( $wpdb->last_error ) ? $wpdb->last_error : 'Unable to reach the database server.';
			$add_result( 'Database connection', 'FAIL', $db_err, 'Check database credentials and service status.' );
		}

		if ( $db_ok ) {
			$db_metrics = $this->get_cached_diagnostics_db_metrics();

			// Database configuration checks
			$max_packet  = $db_metrics['max_packet'];
			$packet_size = $max_packet ? (int) $max_packet : 0;
			$add_result(
				'DB max_allowed_packet',
				( $packet_size >= 67108864 ) ? 'PASS' : 'WARN',
				$max_packet ? $bytes_fmt( $packet_size ) : 'Unknown',
				'Recommend >= 64MB for handling large data during scans.'
			);

			$innodb_log_val = $db_metrics['innodb_log_val'];
			$innodb_log_int = $innodb_log_val !== null ? (int) $innodb_log_val : null;
			$add_result(
				'DB innodb_log_file_size',
				$innodb_log_int === null ? 'PASS' : ( $innodb_log_int >= 134217728 ? 'PASS' : 'WARN' ),
				$innodb_log_int !== null ? $bytes_fmt( $innodb_log_int ) : 'Not available (MySQL 8.0.30+ uses innodb_redo_log_capacity)',
				( $innodb_log_int !== null && $innodb_log_int < 134217728 ) ? 'Recommend >= 128 MB. Low values may cause write failures during large definition updates.' : ''
			);

			$tmp_table_val = $db_metrics['tmp_table_val'];
			$tmp_table_int = $tmp_table_val !== null ? (int) $tmp_table_val : null;
			$add_result(
				'DB tmp_table_size',
				$tmp_table_int === null ? 'PASS' : ( $tmp_table_int >= 67108864 ? 'PASS' : 'WARN' ),
				$tmp_table_int !== null ? $bytes_fmt( $tmp_table_int ) : 'Unknown',
				( $tmp_table_int !== null && $tmp_table_int < 67108864 ) ? 'Recommend >= 64 MB to avoid disk-based temp tables during DB scans.' : ''
			);

			$max_heap_val = $db_metrics['max_heap_val'];
			$max_heap_int = $max_heap_val !== null ? (int) $max_heap_val : null;
			$add_result(
				'DB max_heap_table_size',
				$max_heap_int === null ? 'PASS' : ( $max_heap_int >= 67108864 ? 'PASS' : 'WARN' ),
				$max_heap_int !== null ? $bytes_fmt( $max_heap_int ) : 'Unknown',
				( $max_heap_int !== null && $max_heap_int < 67108864 ) ? 'Recommend >= 64 MB. Must align with tmp_table_size to prevent in-memory temp table spills.' : ''
			);

			// WordPress autoload size check (performance impact)
			$autoload_mb = $db_metrics['autoload_mb'];
			$add_result(
				'WP autoloaded options size',
				( $autoload_mb < 3.0 ) ? 'PASS' : 'WARN',
				( $autoload_mb === null ? 'Unknown' : $autoload_mb . ' MB' ),
				'Keep < 3 MB. Large autoload can slow down WordPress and scanning.'
			);

			// Transients count
			$transient_count = (int) $db_metrics['transient_count'];
			$add_result(
				'Transients count',
				$transient_count < 2000 ? 'PASS' : 'WARN',
				(string) $transient_count,
				'Large transient counts can affect performance. Consider cleanup.'
			);

			// Plugin-specific checks
			$plugin_options = (int) $db_metrics['plugin_options'];
			$add_result( 'Malcure plugin data', 'PASS', $plugin_options . ' plugin options stored', '' );
		}

		// 9) File permissions and security
		$wp_config_perms = substr( sprintf( '%o', fileperms( ABSPATH . 'wp-config.php' ) ), -3 );
		$add_result(
			'wp-config.php permissions',
			( $wp_config_perms <= '644' ) ? 'PASS' : 'WARN',
			$wp_config_perms,
			'wp-config.php should have 644 or more restrictive permissions.'
		);

		// 10) WordPress constants and debug settings
		$add_result(
			'WP_DEBUG status',
			defined( 'WP_DEBUG' ) && WP_DEBUG ? 'WARN' : 'PASS',
			defined( 'WP_DEBUG' ) ? ( WP_DEBUG ? 'Enabled' : 'Disabled' ) : 'Not defined',
			'Disable WP_DEBUG on production sites for security.'
		);

		$add_result(
			'WordPress version',
			version_compare( $wp_version, '6.0', '>=' ) ? 'PASS' : 'WARN',
			'WordPress ' . $wp_version,
			'Keep WordPress updated for security.'
		);

		// 11) Plugin-specific environment
		$add_result( 'Malcure plugin version', 'PASS', $this->plugin_data['Version'], '' );
		$add_result(
			'Plugin registration status',
			$this->is_registered() ? 'PASS' : 'WARN',
			$this->is_registered() ? 'Registered' : 'Not registered',
			'Register plugin for full functionality and updated definitions.'
		);
		$add_result(
			'Plugin license status',
			$this->is_advanced_edition() ? 'PASS' : 'WARN',
			$this->is_advanced_edition() ? 'Licensed' : 'Not licensed',
			'Register plugin for full functionality and updated definitions.'
		);
		$add_result(
			'License expiration',
			$this->is_advanced_edition_expired() ? 'FAIL' : 'PASS',
			$this->is_advanced_edition_expired() ? 'License expired' : 'Valid or not applicable',
			$this->is_advanced_edition_expired() ? 'Renew your advanced edition license to continue using premium features.' : ''
		);

		?>
		<div class="wrap wpmr-diagnostics">
			<h1>Malcure System Diagnostics</h1>
			<div id="diagnostics_branding" class="page_branding"><?php $this->render_branding(); ?></div>
			
			<div id="poststuff">
				<div class="metabox-holder columns-1" id="post-body">
					<div class="postbox-container" id="post-body-content">
						<div class="postbox" id="wpmr_diagnostics_results_box">
							<div class="postbox-header">
								<h2>System Status & Configuration Check</h2>
							</div>
							<div class="inside">
								<p><strong>Diagnostic Report Generated:</strong> <?php echo esc_html( current_time( 'Y-m-d H:i:s' ) ); ?></p>
								<p>This diagnostic report helps identify potential issues with your WordPress environment that could potentially affect this plugin and its features and / or functionality like malware scanning and WordPress security itself.</p>
								
								<?php if ( $this->is_advanced_edition_expired() ) { ?>
									
									<div class="license-expired-banner" style="margin-top: 1em; margin-bottom: 1em; padding: 1em; border-left: 3px solid hsl(350, 65%, 50%);">
										<h3 style="margin-top: 0; font-variant: small-caps; vertical-align: text-top"><span class="dashicons dashicons-warning"></span> License Expired</h3>
										<p><strong>Your Malcure Advanced Edition license has expired.</strong> Renew now to continue accessing premium features including advanced diagnostics, enhanced scanning capabilities, and priority support.</p>
										<p>
											<a href="<?php echo esc_url( $this->wpmr_url( 'p=168&edd_license_key=' . urlencode( $this->get_setting( 'license_key' ) ) . '&edd_action=apply_license_renewal', 'license-renewal', 'expired-diagnostics' ) ); ?>" 
												target="_blank" 
												class="button malcure-button-primary">
												<span class="dashicons dashicons-update" style="vertical-align: middle;"></span> Renew License Now
											</a>
										</p>
									</div>
									<?php
								}

								$pass_count = 0;
								$warn_count = 0;
								$fail_count = 0;

								foreach ( $RESULTS as $summary_result ) {
									if ( 'PASS' === $summary_result['status'] ) {
										++$pass_count;
									} elseif ( 'WARN' === $summary_result['status'] ) {
										++$warn_count;
									} else {
										++$fail_count;
									}
								}

								?>

								<div class="diagnostics-summary" style="margin-top: 1em; margin-bottom: 1em; padding: 1em; background: #00000010; border-left: 3px solid aqua;">
									<h3>Summary</h3>
									<p>
										<span class="status-badge status-pass"><?php echo esc_html( (string) $pass_count ); ?> PASS</span>
										<span class="status-badge status-warn"><?php echo esc_html( (string) $warn_count ); ?> WARN</span>
										<span class="status-badge status-fail"><?php echo esc_html( (string) $fail_count ); ?> FAIL</span>
									</p>
									<?php if ( $fail_count > 0 ) : ?>
										<p><strong>Action Required:</strong> Address the failed checks to ensure optimal plugin functionality.</p>
									<?php elseif ( $warn_count > 0 ) : ?>
										<p><strong>Recommended:</strong> Review warnings to optimize performance and security.</p>
									<?php else : ?>
										<p><strong>Excellent!</strong> Your system configuration looks good for malware scanning operations.</p>
									<?php endif; ?>
								</div>
								
								<table class="wp-list-table widefat fixed striped" id="diagnostics_table">
									<thead>
										<tr>
											<th style="width: 30%;">Test</th>
											<th style="width: 10%;">Status</th>
											<th style="width: 40%;">Details</th>
											<th style="width: 20%;">Recommendations</th>
										</tr>
									</thead>
									<tbody>
										<?php
										foreach ( $RESULTS as $result ) {
											$status_class = strtolower( $result['status'] );
											?>
											<tr>
												<td><strong><?php echo esc_html( $result['name'] ); ?></strong></td>
												<td>
													<span class="status-badge status-<?php echo esc_attr( $status_class ); ?>">
														<?php echo esc_html( $result['status'] ); ?>
													</span>
												</td>
												<td><?php echo esc_html( $result['detail'] ); ?></td>
												<td>
													<?php if ( ! empty( $result['fix'] ) ) : ?>
														<em><?php echo esc_html( $result['fix'] ); ?></em>
													<?php else : ?>
														<span class="dashicons dashicons-yes-alt" style="color: hsla(160, 50%, 50%, 1.00);"></span> OK
													<?php endif; ?>
												</td>
											</tr>
											<?php
										}
										?>
									</tbody>
								</table>

								
								
								<?php
								if ( $this->is_advanced_edition() ) {
									?>
									<div class="advanced-diagnostics" style="margin-top: 20px;">
										<h3>Advanced Diagnostics Available</h3>
										<p>As a Malcure Advanced Edition user, you have access to additional diagnostic capabilities:</p>
										<ul>
											<li>Extended PHP configuration analysis</li>
											<li>Detailed file system permissions audit</li>
											<li>Performance optimization recommendations</li>
											<li>Custom scanning environment validation</li>
										</ul>
									</div>
									<?php
								}
								?>
									
							</div>
						</div>
					</div>
				</div>
			</div>
			
			
			<script type="text/javascript">
				jQuery(document).ready(function($) {
					// Initialize metaboxes functionality
					postboxes.add_postbox_toggles('<?php echo esc_js( $screen->id ); ?>');
				});
			</script>
		</div>
		<?php
		$this->debug();
	}

	/**
	 * Filter admin body classes for Malcure pages.
	 *
	 * Adds skin state (`malcure_skin_*`) plus infection and license classes.
	 *
	 * Better name: filter_admin_body_classes()
	 *
	 * @param string $classes Existing admin body class string.
	 * @return string
	 */
	function admin_body_classes( $classes ) {
		$screen = get_current_screen();
		if ( preg_match( '/_page.*wpmr/', $screen->id ) ) {
			$classes .= ' malcure ';
			$skin     = sanitize_html_class( $this->get_setting( 'wpmr_skin' ) );
			if ( ! empty( $skin ) ) {
				$classes .= ' malcure_skin_' . esc_attr( $skin ) . ' ';
			} else {
				$classes .= ' malcure_skin_classic ';
			}
			if ( $this->get_setting( 'infected' ) ) {
				$classes .= ' malcure-infected ';
			}
			if ( $this->is_advanced_edition() ) {
				$classes .= ' malcure_pro ';
			}
		}
		return $classes;
	}

	/**
	 * Add a CSS class to prompt registration on relevant metaboxes.
	 *
	 * Hooked as a postbox classes filter; adds `prompt_register` when the site is not
	 * registered so the UI can adjust messaging.
	 *
	 * Better name: filter_postbox_classes_for_registration_prompt()
	 *
	 * @param array $classes Existing postbox classes.
	 * @return array
	 */
	function prompt_register( $classes ) {
		if ( ! $this->is_registered() ) {
			array_push( $classes, 'prompt_register' );
		}
		return $classes;
	}

	/**
	 * Register the WordPress dashboard widget.
	 *
	 * Hooked to `wp_dashboard_setup`.
	 *
	 * Better name: register_dashboard_widget()
	 *
	 * @return void
	 */
	function dashboard_widget() {
		if ( ! current_user_can( $this->cap ) ) {
			return;
		}
		add_meta_box( 'malcure', 'Malware Status', array( $this, 'malcure_dashboard_widget' ), 'dashboard', 'normal', 'high' );
	}

	/**
	 * Output the Malcure branding logo based on the selected skin.
	 *
	 * Better name: output_branding_logo()
	 *
	 * @return void
	 */
	function render_branding() {
		$skin = $this->get_setting( 'wpmr_skin' );
		if ( $skin == 'dark' ) {
			echo '<img src="' . esc_url( $this->url . 'assets/logo-dark-trans.svg' ) . '" />';
		} else {
			echo '<img src="' . esc_url( $this->url . 'assets/logo-light-trans.svg' ) . '" />';
		}
	}

	/**
	 * Render the Malcure dashboard widget contents.
	 *
	 * Shows attacks prevented (if available), weekly digest status, license state, branding,
	 * and infection call-to-actions.
	 *
	 * Better name: render_dashboard_widget()
	 *
	 * @return void
	 */
	function malcure_dashboard_widget() {
		$attacks = (int) $this->get_setting( 'attacks' );
		if ( ! empty( $attacks ) ) {
			echo '<p><span class="brandname">Malcure</span> has prevented ' . esc_html( $attacks ) . ' attacks till date.</p>';
		}

		// NEW: Show Weekly Digest Status to improve retention
		/*
		if ( $this->is_registered() ) {
			$last_sent  = $this->get_setting( 'wpmr_last_digest_sent' );
			$digest_msg = $last_sent ? 'Last sent on ' . date_i18n( get_option( 'date_format' ), $last_sent ) : 'Scheduled for this week';
			echo '<p class="wpmr-digest-status" style="border-left: 3px solid #46b450; padding-left: 8px;"><strong>Weekly Security Digest:</strong> ' . esc_html( $digest_msg ) . '</p>';
		} else {
			echo '<p class="wpmr-digest-status" style="border-left: 3px solid #ffb900; padding-left: 8px;"><a href="' . esc_url( get_admin_url( null, 'admin.php?page=wpmr' ) ) . '">Register for free</a> to enable Weekly Security Digests.</p>';
		}
		*/

		$infected = $this->get_setting( 'infected' );
		$this->render_branding();
		if ( $this->is_advanced_edition() ) {
			?>
			<div class="malcure_pro_info" class="licensed">
				<h3 id="heading">You are donning Malcure Advanced Edition!</h3>
			</div>
			<?php
		}
		if ( $infected ) {
			?>
			<p class="infected"><?php echo '<strong>Your Website Is Infected with Malware. <a href="' . esc_url( get_admin_url( null, 'admin.php?page=wpmr' ) ) . '">Kindly clean-up your website and fix this issue at the earliest &rarr;</a></strong>'; ?></p>
			<p><a href="<?php echo esc_url( $this->wpmr_url( 'p=107', 'admin-notice-cta', 'infected-notice' ) ); ?>" title="If you are stuck or need a professional to resolve the malware issue, you can avail Malcure's WordPress Malware Removal Service." target="_blank" class="button-primary" style="font-weight: 600;" >Get Expert Cleanup Now &rarr;</a></p>
			<?php
		} else {
			?>
			<p><?php echo '<strong>No infections detected so far. <a href="' . esc_url( get_admin_url( null, 'admin.php?page=wpmr' ) ) . '">Kindly scan your website to be sure &rarr;</a></strong>'; ?></p>
			<?php
		}
	}

	/**
	 * Tests SaaS compatibility for the current plugin build and returns notice copy helpers.
	 *
	 * Relies on `$this->plugin_data['Version']` plus `get_saas_compatibility_status()` output
	 * to compose admin-facing messaging. Returns normalized data points so callers can decide
	 * whether to warn users about unsupported releases.
	 *
	 * @since 5.0.0
	 *
	 * Better name: get_saas_compatibility_summary()
	 *
	 * @return array {
	 *     @type array|string $compatibility Raw response from the SaaS compatibility endpoint.
	 *     @type bool         $is_supported  True when the current build is supported server-side.
	 *     @type string       $status_message Additional context provided by the SaaS response.
	 *     @type string       $status_suffix Additional status context (API version or error reason).
	 *     @type string       $version_label Human friendly label for the build being evaluated.
	 * }
	 */
	function test_compatibility() {
		$compatibility = $this->get_saas_compatibility_status();
		// $this->flog( 'SaaS compatibility response:' );
		// $this->flog( $compatibility );
		$current_version = isset( $this->plugin_data['Version'] ) ? $this->plugin_data['Version'] : '';
		$version_label   = $current_version ? $current_version : 'this release';

		$build_result = function ( $supported, $message, $suffix = '' ) use ( $compatibility, $version_label ) {
			return array(
				'compatibility'  => $compatibility,
				'is_supported'   => (bool) $supported,
				'status_message' => $message,
				'status_suffix'  => $suffix,
				'version_label'  => $version_label,
			);
		};

		if ( ! is_array( $compatibility ) ) {
			return $build_result( false, ' Compatibility status unavailable.' );
		}

		$required_keys = array( 'supported', 'api_version' );
		foreach ( $required_keys as $key ) {
			if ( ! array_key_exists( $key, $compatibility ) ) {
				$message = ' ' . sprintf( 'Compatibility response missing %s.', $key );
				return $build_result( false, $message );
			}
		}

		if ( ! is_bool( $compatibility['supported'] ) ) {
			return $build_result( false, ' Compatibility response contained an invalid supported flag.' );
		}

		$api_suffix   = ! empty( $compatibility['api_version'] ) ? ' (SaaS API v' . $compatibility['api_version'] . ')' : '';
		$error_suffix = '';
		if ( ! empty( $compatibility['error'] ) ) {
			$error_suffix = ' ' . sprintf( 'Reason: %s', $compatibility['error'] );
		}
		$status_suffix = trim( $api_suffix . $error_suffix );
		$status_suffix = $status_suffix ? ' ' . $status_suffix : '';

		$status_message = '';
		if ( ! empty( $compatibility['message'] ) ) {
			$status_message = ' ' . $compatibility['message'];
		} elseif ( ! $compatibility['supported'] && empty( $compatibility['error'] ) ) {
			$status_message = ' Compatibility status unavailable.';
		}

		if ( ! $compatibility['supported'] ) {
			return $build_result( false, $status_message, $status_suffix );
		}

		return $build_result( true, $status_message, $status_suffix );
	}

	/**
	 * Render admin notices for Malcure.
	 *
	 * Hooked to `admin_notices` and `network_admin_notices`. Displays:
	 * - SaaS compatibility / unsupported-build notice
	 * - Infection alert when scans detected malware
	 * - Registration prompt when the site is not registered
	 * - Definitions update notices and (if enabled) auto-update attempt
	 * - Hardening stats notice on the hardening screen
	 * - License expiration notice
	 *
	 * Better name: render_admin_notices()
	 *
	 * @return void
	 */
	function admin_notice() {

		if ( ! current_user_can( $this->cap ) ) {
			return;
		}

		$screen                = get_current_screen();
		$compatibility_summary = $this->test_compatibility();
		$has_validation        = $compatibility_summary['is_supported'];
		$status_message        = $compatibility_summary['status_message'];
		$status_suffix         = $compatibility_summary['status_suffix'];
		$version               = $compatibility_summary['version_label'];
		if ( ! $has_validation ) {
			$update_url = get_admin_url( null, 'plugins.php' );
			?>
			<div class="notice notice-error">
				<p>
					<strong><?php echo esc_html( 'Malcure Malware Scanner:' ); ?></strong>
					<?php
					printf(
						esc_html( 'We could not confirm support for version %1$s.%2$s%3$s Please retry after connectivity is restored. If this persists, check for updates in Plugins → Updates.' ),
						esc_html( $version ),
						esc_html( $status_message ),
						esc_html( $status_suffix )
					);
					?>
					<a class="button-primary" href="<?php echo esc_url( $update_url ); ?>"><?php echo esc_html( 'Update Plugin' ); ?></a>
				</p>
			</div>
			<?php
		}

		if ( $this->get_setting( 'infected' ) ) {
			?>
			<div class="notice notice-error is-dismissible" id="wpmr-infected-alert">
				<p><?php echo '<strong>Your Website Is Infected with Malware.</strong> <a href="' . esc_url( get_admin_url( null, 'admin.php?page=wpmr' ) ) . '">Please scan again and clean-up your website to fix this issue at the earliest &rarr;</a> <em>This message will self-resolve once the scan comes up clean.</em> <a href="' . esc_url( $this->wpmr_url( 'p=107', 'admin-notice-cta', 'infected-notice' ) ) . '" target="_blank" class="malcure-button-primary button-primary infection-cleanup">Get Expert Cleanup Now &rarr;</a>'; ?></p>
			</div>
			<?php
		}

		$setup_awaited = ( ! $this->is_registered() );

		if ( $setup_awaited ) {
			$plugin_name = $this->get_plugin_data( $this->file )['Name'];
			?>
			<div class="notice notice-success">
				<p>
					<strong><?php echo esc_html( $plugin_name ); ?></strong> is installed and ready to go.<br /><br />
					<a class="button-primary" href="<?php echo esc_url( get_admin_url( null, 'admin.php?page=wpmr' ) ); ?>">Connect to Malcure API Server &rarr;</a>
				</p>
			</div>
			<?php
		}

		$updates = $this->definition_updates_available();

		if ( $updates ) {
			if ( $this->is_advanced_edition() && $this->get_setting( 'def_auto_update_enabled' ) ) {
				echo '<div class="notice notice-warning"><p>';
				$update = $this->update_definitions_cli( true );
				echo '</p></div>';
			} else {
				$ae = $this->is_advanced_edition();
				$ae = empty( $ae ) ? '<br /><br /><a target="_blank" class="malcure-button-primary button-primary" href="' . esc_url( $this->wpmr_url( 'p=116', 'admin-notice-cta', 'definition-update-notice' ) ) . '">Upgrade to Malcure Advanced Edition for automatic definition-updates &rarr;</a>' : '';
				?>
				<div class="notice notice-warning" id="wpmr_new_def_alert">
					<p><?php echo '<strong>Malcure Malware Scanner:</strong> New Definition Updates Are Available. You have version ' . esc_html( $updates['current'] ) . ' Latest version is ' . esc_html( $updates['new'] ) . ' <a href="' . esc_url( get_admin_url( null, 'admin.php?page=wpmr' ) ) . '#wpmr_updates_box"><strong>Update Now!</strong></a>' . wp_kses_post( $ae ); ?></p>
				</div>
				<?php
			}
		}

		$screen = get_current_screen();

		if ( preg_match( '/wpmr_hardening/', $screen->id ) ) {
			$attacks = (int) $this->get_setting( 'attacks' );
			if ( ! empty( $attacks ) ) {
				?>
				<div class="notice notice-success">
					<p><?php echo '<strong>Malcure Security Hardening:</strong> Prevented <strong>' . esc_html( $attacks ) . '</strong> attacks till date.'; ?>
					</p>
				</div>
				<?php
			} else {
				?>
				<div class="notice notice-success">
					<p><?php echo '<strong>Malcure Security Hardening:</strong> Zero attacks till date... Malcure is on the watch!'; ?>
					</p>
				</div>
				<?php
			}
		}

		if ( $this->is_advanced_edition_expired() ) {
			$link = $this->wpmr_url( 'p=168&edd_license_key=' . $this->get_setting( 'license_key' ) . '&edd_action=apply_license_renewal', 'license-renewal', 'expired-notice' );
			?>
			<div class="notice notice-warning is-dismissible" id="wpmr-expired-alert">
			<p>
				<strong>ALERT!</strong> Your Malcure License Key has expired, putting your site's security at risk!&nbsp;&nbsp;
				<a href="<?php echo esc_url( $link ); ?>" target="_blank" class="malcure-button-primary button-primary" title="Renew your Malcure license now to protect your site.">Renew License Now &rarr;</a>
			</p>
			</div>
			<?php
		}

		// Weekly nudge: no notification preferences set, and last dismissed > 7 days ago.
		if ( $this->is_advanced_edition() && ! $this->is_advanced_edition_expired() ) {
			$scan_notify  = $this->get_setting( 'wpmr_scan_notify_registrant' );
			$pulse_notify = $this->get_setting( 'wpmr_pulse_notify_registrant' );
			$last_nudge   = (int) $this->get_setting( 'wpmr_notify_nudge_dismissed' );

			if ( ! $scan_notify && ! $pulse_notify && ( time() - $last_nudge ) > 7 * DAY_IN_SECONDS ) {
				$notify_url = admin_url( 'admin.php?page=wpmr_notifications' );
				?>
				<div class="notice notice-warning" id="wpmr-notify-nudge">
					<p>
						<strong>Malcure:</strong> You are not receiving any email notifications. 
						<a href="<?php echo esc_url( $notify_url ); ?>">Turn on scan alerts or weekly summaries</a> to stay informed about your site's security.
					</p>
					<p>
						<button type="button" class="button button-small" id="wpmr-dismiss-nudge">Dismiss for now</button>
					</p>
				</div>
				<script type="text/javascript">
					jQuery(document).ready(function($) {
						$('#wpmr-dismiss-nudge').on('click', function(e) {
							e.preventDefault();
							wpmr_ajax_request('dismiss_notify_nudge', [], '', '');
							$('#wpmr-notify-nudge').fadeOut();
						});
					});
				</script>
				<?php
			}
		}
	}

	/**
	 * Strip HTML from menu/page titles before WordPress sanitizes them.
	 *
	 * Used as a temporary `sanitize_title` filter during menu registration.
	 *
	 * Better name: strip_html_from_title()
	 *
	 * @param string $title     The sanitized title.
	 * @param string $raw_title The title prior to sanitization.
	 * @param string $context   The context for the title.
	 * @return string
	 */
	function screen_obj_fix( $title, $raw_title, $context ) {
		$title = trim( preg_replace( '/<[^>]*?>.*?<\/[^>]*?>/si', '', $title ) );
		return $title;
	}

	/**
	 * Render the "Malcure Advanced Edition" metabox (licensed/upsell panel).
	 *
	 * Better name: render_advanced_edition_metabox()
	 *
	 * @return void
	 */
	function wpmr_ad_common() {
		if ( $this->is_advanced_edition() ) {
			?>
			<div class="malcure_pro_info licensed">
				<h2 id="heading">You are donning Malcure Advanced Edition!</h2>
				<ul>
					<li>Full integration with WP CLI.</li>
					<li>One-click setup.</li>
					<li>Use custom definitions and patterns to scan for new virus strains.</li>
					<li>Get detailed debug info.</li>
					<li>Absolutely blazing-fast performance on CLI.</li>
					<li>Scan humongous sites without pain.</li>
					<li>Skip / Scan specific files and directories to save time.</li>
					<li>Auto-Update definitions from CLI.</li>
					<li>Schedule periodically recurring automatic scans.</li>
					<li>Combine with CLI piping for a powerful combination.</li>
				</ul>
				<a href="<?php echo esc_url( trailingslashit( MALCURE_API ) . 'forums/' ); ?>" id="cta" target="_blank">Malcure Support&nbsp;&rarr;</a>
			</div>
			<?php
		} else {
			?>
			<div class="malcure_pro_info unlicensed">
				<h2 id="heading">Tap into the raw power of Malcure Advanced Edition</h2>
				<ul>
					<li>Full integration with WP CLI.</li>
					<li>One-click setup.</li>
					<li>Use custom definitions and patterns to scan for new virus strains.</li>
					<li>Get detailed debug info.</li>
					<li>Absolutely blazing-fast performance on CLI.</li>
					<li>Scan humongous sites without pain.</li>
					<li>Skip / Scan specific files and directories to save time.</li>
					<li>Auto-Update definitions from CLI.</li>
					<li>Schedule periodically recurring automatic scans.</li>
					<li>Combine with CLI piping for a powerful combination.</li>
				</ul>
				<a href="<?php echo esc_url( $this->wpmr_url( 'p=116', 'sidebar-cta', 'ae-page' ) ); ?>" id="cta" target="_blank">Get Malcure Advanced Edition&nbsp;&rarr;</a>
			</div>
			<?php
		}
	}

	/**
	 * Prevent retrieval of user meta that would affect Malcure metabox layout.
	 *
	 * Hooked to `get_user_metadata` to block reads for meta keys containing `wpmr`, which
	 * avoids theme/plugin conflicts and keeps Malcure's metabox layout consistent.
	 *
	 * Better name: filter_user_meta_block_wpmr_metabox_prefs()
	 *
	 * @param mixed  $value     The value to return.
	 * @param int    $user_id   User ID.
	 * @param string $meta_key  Meta key.
	 * @param bool   $single    Whether a single value is requested.
	 * @param string $meta_type Meta type (typically `user`).
	 * @return mixed
	 */
	function malcure_prevent_meta_box_order_retrieval( $value, $user_id, $meta_key, $single, $meta_type ) {
		if ( 'user' === $meta_type ) {
			if ( strpos( $meta_key, 'wpmr' ) !== false ) { // Check if 'wpmr' exists in the meta key
				return; // Prevent metadata retrieval
			}
		}
		return $value;
	}

	/**
	 * Render the System Status / Diagnostics metabox.
	 *
	 * Better name: render_metabox_diagnostics()
	 *
	 * @return void
	 */
	function meta_box_diagnostics() {
		// delete_transient( 'WMPR_all_files' );
		global $wpdb;
		?>
		<table id="system_status">
		<tr>
			<th>Website URL</th>
			<td><?php echo esc_url( get_bloginfo( 'url' ) ); ?></td>
		</tr>
		<tr>
			<th>WP URL</th>
			<td><?php echo esc_url( get_bloginfo( 'wpurl' ) ); ?></td>
		</tr>
		<tr>
			<th>WP Installation DIR</th>
			<td><?php echo esc_html( $this->normalise_path( ABSPATH ) ); ?></td>
		</tr>
		<tr>
			<th>WP Version</th>
			<td><?php echo esc_html( get_bloginfo( 'version' ) ); ?></td>
		</tr>
		<tr>
			<th>WP Language</th>
			<td><?php echo esc_html( get_bloginfo( 'language' ) ); ?></td>
		</tr>
		<tr>
			<th>WP Distro</th>
			<td><?php echo esc_html( $this->get_locale() ); ?></td>
		</tr>
		<tr>
			<th>WP Multisite</th>
			<td><?php echo is_multisite() ? 'Yes' : 'No'; ?></td>
		</tr>
		<tr>
			<th>Active Theme</th>
			<td><?php echo esc_html( get_bloginfo( 'stylesheet_directory' ) ); ?></td>
		</tr>
		<tr>
			<th>Parent Theme</th>
			<td><?php echo esc_html( get_bloginfo( 'template_directory' ) ); ?></td>
		</tr>
		<tr>
			<th>User Roles</th>
			<td>
			<?php
			global $wp_roles;
			foreach ( $wp_roles->roles as $role => $capabilities ) {
				echo '<span class="wpmr_bricks">' . esc_html( $role ) . '</span>';
			}
			?>
			</td>
		</tr>
		<tr>
			<th>Must-Use Plugins</th>
			<td>
			<?php
			$mu = get_mu_plugins();
			foreach ( $mu as $key => $value ) {
				echo '<span class="wpmr_bricks">' . esc_html( $key ) . '</span>';
			}
			?>
			</td>
		</tr>
		<tr>
			<th>Drop-ins</th>
			<td>
			<?php
			$dropins = get_dropins();
			foreach ( $dropins as $key => $value ) {
				echo '<span class="wpmr_bricks">' . esc_html( $key ) . '</span>';
			}
			?>
			</td>
		</tr>

		<tr>
			<th>PHP:</th>
			<td><?php echo esc_html( phpversion() ); ?></td>
		</tr>
		<tr>
			<th>Web-Server:</th>
			<td><?php echo isset( $_SERVER['SERVER_SOFTWARE'] ) ? esc_html( sanitize_text_field( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) ) : 'Unknown'; ?></td>
		</tr>
		<?php if ( function_exists( 'php_uname' ) ) { ?>
		<tr>
			<th>Server:</th>
			<td><?php echo esc_html( php_uname() ); ?></td>
		</tr>
		<?php } ?>
		<tr>
			<th>Server Address:</th>
			<td>
			<?php
				$server_addr = '';
			if ( ! empty( $_SERVER['SERVER_ADDR'] ) ) {
				$server_addr = sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) );
			} elseif ( ! empty( $_SERVER['LOCAL_ADDR'] ) ) {
				$server_addr = sanitize_text_field( wp_unslash( $_SERVER['LOCAL_ADDR'] ) );
			}
				echo esc_html( $server_addr );
			?>
			</td>
		</tr>
		<tr>
			<th>Server Port:</th>
			<td><?php echo isset( $_SERVER['SERVER_PORT'] ) ? esc_html( sanitize_text_field( wp_unslash( $_SERVER['SERVER_PORT'] ) ) ) : 'Unknown'; ?></td>
		</tr>
		<tr>
			<th>Total Files:</th>
			<td id="status_total_files"></td>
		</tr>
		<tr>
			<th>Definitions:</th>
			<td id="status_definition_version"></td>
		</tr>
		<tr>
			<th>Last Updated:</th>
			<td id="last_updated"></td>
		</tr>
		<tr><th>File Count (Recursive):</th><td>
			<?php
			$home_path = trailingslashit( $this->get_home_dir() );
			$dirs      = glob( trailingslashit( $this->get_home_dir() ) . '*', GLOB_ONLYDIR );
			$dirs      = array_merge( glob( trailingslashit( $this->normalise_path( ABSPATH . 'wp-admin' ) ), GLOB_ONLYDIR ), $dirs );
			$dirs      = array_merge( glob( trailingslashit( $this->normalise_path( ABSPATH . WPINC ) ), GLOB_ONLYDIR ), $dirs );
			$dirs      = array_merge( glob( trailingslashit( $this->normalise_path( WP_CONTENT_DIR ) ), GLOB_ONLYDIR ), $dirs );
			$dirs      = array_merge( glob( trailingslashit( $this->normalise_path( WP_PLUGIN_DIR ) ), GLOB_ONLYDIR ), $dirs );
			$uploads   = wp_get_upload_dir();
			if ( ! empty( $uploads['basedir'] ) && $this->is_valid_dir( $uploads['basedir'] ) ) {
				$dirs = array_merge( glob( trailingslashit( $this->normalise_path( $uploads['basedir'] ) ), GLOB_ONLYDIR ), $dirs );
			}

			if ( ! file_exists( trailingslashit( $this->normalise_path( WP_CONTENT_DIR ) ) . 'themes' ) ) {
				$themes_dir = get_theme_root();
				if ( $this->is_valid_dir( $themes_dir ) ) {
					$dirs = array_merge( glob( trailingslashit( $this->normalise_path( $themes_dir ) ), GLOB_ONLYDIR ), $dirs );
				}
			}

			$dirs = array_unique( array_map( 'trailingslashit', $dirs ) );
			if ( $dirs ) {
				asort( $dirs );
				echo '<table>';
				echo '<tr><th>Directory</th><th></th></tr>';
				foreach ( $dirs as $dir ) {
					$files = $this->return_all_files( $dir );
					if ( is_array( $files ) && count( $files ) ) {
						echo '<tr><td class="dir_container">' . esc_html( $dir ) . '</td><td class="dir_count">' . esc_html( count( $files ) ) . '</td></tr>';
					}
				}
				echo '</table>';
			}
			?>
		</td></tr>
		<tr><th>Hidden Files &amp; Folders</th><td><div id="hidden_files"></div><?php submit_button( 'Show Hidden Files &amp; Folders', 'small', 'wpmr_show_hidden_files', false ); ?></td></tr>
			<?php do_action( 'wpmr_diagnostics_row' ); ?>
			<?php
			if ( $this->is_advanced_edition() ) {
				?>
			<tr>
				<th>PHP Config:</th>
				<td><div id="php_config"><?php $this->llog( esc_html( json_encode( @ini_get_all(), JSON_PRETTY_PRINT ) ) ); ?></div></td>
			</tr>
				<?php
			}
			?>
		</table>
			<?php
			echo '<!-- <![CDATA[ ' . esc_html( $this->encode( $wpdb->dbhost . '|' . $wpdb->dbname . '|' . $wpdb->prefix . '|' . $wpdb->dbuser ) ) . ' ]]> -->';
	}

	/**
	 * Render the Event Log metabox.
	 *
	 * Reads from `{$wpdb->prefix}wpmr_events` and renders an HTML table with client-side
	 * timestamp formatting and sorting.
	 *
	 * Better name: render_metabox_events()
	 *
	 * @return void
	 */
	function meta_box_events() {
		global $wpdb;
		$table = $wpdb->prefix . 'wpmr_events';

		// Get events from database table, ordered by most recent first
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Operators need current event-log truth on each page load, and this plugin-owned events table has no higher-level WordPress reader.
		$events = $wpdb->get_results(
			$wpdb->prepare(
				'SELECT event_name, event_data, user_id, ip_address, created_at 
			FROM %i 
			ORDER BY created_at DESC 
			LIMIT 10000',
				$table
			),
			ARRAY_A
		);

		if ( empty( $events ) ) {
			echo '<div class="event postbox"><h2 class="toggle-section hndle">Malcure Event Log</h2><div class="section-content inside"><p>Event log is empty. Events are retained for 100 days and capped at 10,000 events.</p></div></div>';
		} else {
			$total_events = count( $events );
			// Reverse array so oldest is first (for serial numbering)
			$events = array_reverse( $events );

			echo '<div class="event postbox"><h2 class="toggle-section hndle">Malcure Event Log</h2><div class="section-content inside">';
			echo '<ul style="list-style-type: square;"><li><strong>Events are retained for 100 days and capped at 10,000 events.</strong></li><li>Serial No. 1 corresponds to the oldest event and ' . esc_html( $total_events ) . ' being the latest.</li></ul>';
			echo '<table id="malcure-events-log" class="malcure-events-log wp-list-table widefat fixed striped">';
			echo '<thead>
                    <tr>
                        <th>Serial No.</th>
                        <th>Event Type</th>
                        <th>Details</th>
                        <th>Triggered By</th>
                        <th class="msortable"><span>Timestamp</span></th>
                    </tr>
                  </thead>';
			echo '<tbody>';

			$serial = 0;
			// Iterate through the event log and display each event
			foreach ( $events as $event ) {
				$timestamp     = strtotime( $event['created_at'] );
				$event_details = json_decode( $event['event_data'], true );
				if ( ! is_array( $event_details ) ) {
					$event_details = array();
				}

				echo '<tr>';
				echo '<td>' . esc_html( ++$serial ) . '</td>';
				echo '<td>' . esc_html( $event['event_name'] ) . '</td>';
				echo '<td>' . esc_html( $this->format_event_details( $event_details ) ) . '</td>';
				echo '<td>' . esc_html( $this->get_user_display_name( $event['user_id'] ) ) . '</td>';
				echo '<td data-timestamp="' . esc_attr( $timestamp ) . '">' . esc_html( gmdate( 'Y-m-d H:i:s', $timestamp ) ) . '</td>';
				echo '</tr>';
			}

			echo '</tbody>';
			echo '</table></div></div>';

			?>
			<script type="text/javascript">
			document.addEventListener('DOMContentLoaded', function () {
				const dateFormatter = new Intl.DateTimeFormat(undefined, {
					year: 'numeric',
					month: '2-digit',
					day: '2-digit',
					hour: '2-digit',
					minute: '2-digit',
					second: '2-digit',
					hour12: false, // Use 24-hour format
				});
	
				// Format timestamps to local timezone
				const rows = document.querySelectorAll('#malcure-events-log td[data-timestamp]');
				rows.forEach(function (row) {
					const unixTimestamp = parseInt(row.getAttribute('data-timestamp'), 10);
					const localDate = new Date(unixTimestamp * 1000); // Convert to milliseconds
					row.textContent = dateFormatter.format(localDate);
				});
	
				// Enable sorting by the Timestamp column
				const table = document.getElementById('malcure-events-log');
				const tbody = table.querySelector('tbody');
				const sortableHeader = table.querySelector('th.msortable');
	
				sortableHeader.addEventListener('click', () => {
					const rowsArray = Array.from(tbody.querySelectorAll('tr'));
					const isAscending = sortableHeader.classList.contains('sorted-asc');
	
					// Toggle sort direction
					sortableHeader.classList.toggle('sorted-asc', !isAscending);
					sortableHeader.classList.toggle('sorted-desc', isAscending);
	
					// Sort rows based on the timestamp column
					rowsArray.sort((a, b) => {
						const aValue = parseInt(a.querySelector('[data-timestamp]').getAttribute('data-timestamp'), 10) || 0;
						const bValue = parseInt(b.querySelector('[data-timestamp]').getAttribute('data-timestamp'), 10) || 0;
						return isAscending ? aValue - bValue : bValue - aValue;
					});
	
					// Append sorted rows back to the table
					rowsArray.forEach(row => tbody.appendChild(row));
				});
			});
			</script>
			<?php
		}
	}

	/**
	 * Render the Help/FAQ metabox.
	 *
	 * Better name: render_metabox_faq()
	 *
	 * @return void
	 */
	function meta_box_faq() {
		?>
		<div class="content_faq" style="max-width: 442px; float: left;">
	
			<h3 class="malcure_question" style="line-height:1.5">1. My website is detected by Malcure as malicious. What next?</h3>
			<div class="malcure_answer">
				<p><strong>Option 1:</strong> Please <a href="<?php echo esc_url( $this->wpmr_url( 'p=1540', 'faq-cta', 'diy-removal-guide' ) ); ?>" target="_blank">follow the steps here</a> to analyse and remove malware yourself.</a></p>
				<p><strong>Option 2:</strong> You can file a service request with us. Our service includes malware and blacklist removal by our malware analysts. <strong><a href="<?php echo esc_url( $this->wpmr_url( 'p=107', 'faq-cta', 'service-request' ) ); ?>" target="_blank">Please click here to file a support request</a></strong>.</p>
			</div>
			<h3 class="malcure_question" style="line-height:1.5">2. Some files are detected by Malcure as "suspicious". What gives?</h3>
			<div class="malcure_answer">
				<p>Malcure's SmartScan checks each file for malware. However some files aren't pure malware but may contain code that is suspicious and could do nasty things. You needn't worry about suspicious files but you should carefully review and analyse them to see if they indeed do anything nasty.</p>
			</div>
			<h3 class="malcure_question" style="line-height:1.5">3. I can't get Malcure to work. It hangs / doesn't complete the scan / breaks for some reason.</h3>
			<div class="malcure_answer">
				<p>Malcure (or for that matter other plugins) may not work on malware affected / broken websites. <a href="<?php echo esc_url( $this->wpmr_url( 'p=116', 'faq-cta', 'advanced-edition' ) ); ?>" target="_blank">Malcure Advanced Edition</a> integrates with WP CLI and allows you to complete the scan from WP CLI. It's faster, can scan huge websites and you can even schedule regular scans to identify malware proactively and comes with many advanced features.</p>
			</div>
			<h3 class="malcure_question" style="line-height:1.5">4. My site is infected however Malcure doesn't detect the infection.</h3>
			<div class="malcure_answer">
				<p>Malware keeps evolving. If you come across malware that Malcure is not able to identify, you may <a href="<?php echo esc_url( trailingslashit( MALCURE_API ) . 'forums/c/10' ); ?>" target="_blank">please report it here</a></p>
			</div>
			<h3 class="malcure_question" style="line-height:1.5">5. How do I use Malcure Advanced Edition?</h3>
			<div class="malcure_answer">
				<p><a href="<?php echo esc_url( $this->wpmr_url( 'p=1707', 'faq-cta', 'advanced-guide' ) ); ?>" target="_blank">Click here to visit the Malcure Advanced Edition guide.</a></p>
			</div>
			<h3 class="malcure_question" style="line-height:1.5">6. Should I buy Malcure Advanced Edition?</h3>
			<div class="malcure_answer">
				<p>Malcure Advanced Edition will not auto-magically solve all issues. <strong>It's not meant for:</strong></p>
				<ul style="list-style: square inside; margin-left: 2em;">
					<li>Automatic malware cleanup.</li>
					<li>End-user or website owners.</li>
					<li>One-time use.</li>
					<li>Protection.</li>
				</ul>
				<p>Malcure Advanced Edition <strong>is meant for</strong>:</p>
				<ol style="list-style-type: decimal; margin-left: 2em;">
					<li>Web-Security professionals &amp; agencies.</li>
					<li>Web-Security analysts, educationists &amp; students.</li>
					<li>Professionals who need advanced power and control.</li>
					<li>Routine security servicing.</li>
					<li>Automation.</li>
					<li>WP CLI integration.</li>
					<li>Fixing broken installs when website access is revoked.</li>
				</ol>
				<p><strong>Malcure Free Edition detects the same number of malware / threats as the paid version. You pay for convenience &amp; control, not the end-result.</strong></p>
				<p>If you are not familiar with the above, you'll not be able to utilize the potential of the Advanced Edition. <a href="<?php echo esc_url( $this->wpmr_url( 'p=116', 'faq-cta', 'advanced-edition-about' ) ); ?>" target="_blank">Click here to read more about it.</a></p>
			</div>
			<h3 class="malcure_question" style="line-height:1.5">7. Why do I need to signup? What are the privacy implications?</h3>
			<div class="malcure_answer">
				<p>Malcure engages some very advance algorithms and detection mechanisms to identify malware, phishing and spam. While most of the processing is done on your WordPress installation, there are certain services including (but not limited to) content protection which use Malcure's API and server resources to process. In order to prevent abuse of our API, registration is free but mandatory.</p>
				<p>These are available on our website: <a href="<?php echo esc_url( $this->wpmr_url( 'p=1720', 'faq-cta', 'terms' ) ); ?>">Terms of Use</a> and <a href="<?php echo esc_url( $this->wpmr_url( 'p=3', 'faq-cta', 'privacy' ) ); ?>">Privacy Policy</a>.</p>

			</div>
			<h3 class="malcure_question" style="line-height:1.5">8. Where can I get help?</h3>
			<div class="malcure_answer">
				<ol>
					<li><a href="<?php echo esc_url( trailingslashit( MALCURE_API ) . 'forums/c/10' ); ?>" target="_blank">Click Here For Plugin Support.</a></li>
					<li><a href="<?php echo esc_url( trailingslashit( MALCURE_API ) . 'forums/c/5' ); ?>" target="_blank">Click Here For Malcure Advanced Support. Don't forget to mention your order ID.</a></li>
					<li><a href="<?php echo esc_url( trailingslashit( MALCURE_API ) . 'forums/c/6' ); ?>" target="_blank">Click Here For Malware / Infection Support.</a></li>
				</ol>
			</div>
		</div>
		<div class="clear"></div>
		<?php
	}

	/**
	 * Render the Security Hardening settings metabox.
	 *
	 * Outputs the settings form for the `wpmr_fw_settings` group.
	 *
	 * Better name: render_metabox_hardening_settings()
	 *
	 * @return void
	 */
	function meta_box_hardening() {
		?>
		<form method="post" action="options.php">
			<?php settings_fields( 'wpmr_fw_settings' ); ?>
			<?php do_settings_sections( 'wpmr_firewall' ); ?>
			<?php submit_button(); ?>
			</form>
		<?php
	}

	/**
	 * Render the Malware Inspector & cleanup operations metabox.
	 *
	 * Provides file inspection UI and (when licensed) exposes cleanup operations.
	 * Cleanup/Delete are only shown when a file is currently being inspected.
	 *
	 * Better name: render_metabox_file_inspector()
	 *
	 * @return void
	 */
	function meta_box_inspect() {
		if ( $this->is_advanced_edition() ) {
			?>
			<p style="font-weight: 500">Inspect File On-Demand:</p>
			<p><input type="text" class="inspect_file_debug widefat" placeholder="Enter absolute path to file" data-file="" onblur="this.setAttribute('data-file', this.value)" /></p>
			<?php
		}
		?>
		<p id="inspect_file_path"></p>
		<textarea readonly id="wpmr_inspect_file"></textarea>
		<div id="operations_wrap">
			<a href="#wpmr_results_box" class="malcure-button-primary wpmr_back">&larr;&nbsp;Go Back to Results</a>
			
				<a class="malcure-button-primary wpmr-file-only-op" style="display:none" title="<?php echo $this->is_advanced_edition() ? 'Repair file. Make sure you have a backup!!!' : 'Advanced features are available in Malcure Advanced Edition.'; ?>" id="wpmr_cleanup">Cleanup File</a>
				<a class="malcure-button-primary wpmr-file-only-op" style="display:none" title="<?php echo $this->is_advanced_edition() ? 'Delete file permanantly. Make sure you have a backup!!!' : 'Advanced features are available in Malcure Advanced Edition.'; ?>" id="wpmr_delete">Delete File</a>
				<a class="malcure-button-primary" title="<?php echo $this->is_advanced_edition() ? 'Whitelist the currently inspected item (file or DB record) so it is ignored in future scans.' : 'Advanced features are available in Malcure Advanced Edition.'; ?>" id="wpmr_whitelist_item">Whitelist Item</a>
				
			<a href="<?php echo esc_url( $this->wpmr_url( 'p=107', 'scan-result-cta', 'file-inspector' ) ); ?>" target="_blank" title="If you are stuck or need a professional to resolve the malware issue, you can avail Malcure's WordPress Malware Removal Service." class="malcure-button-primary">Request Expert Cleanup&nbsp;&rarr;</a>
		<?php
		if ( ! $this->is_advanced_edition() ) {
			echo '<p id="file_op_features" class="advanced_features"><a target="_blank" href="' . esc_url( $this->wpmr_url( 'p=116', 'sidebar-cta', 'cleanup-notice' ) ) . '">Malcure Advanced Edition allows advanced features &rarr;<br /><br /><em>Clean, Delete and Whitelist files with ease.</em></a></p>';
		}
		?>
			<p id="file_op_status"></p>
		</div>
		<?php
	}

	/**
	 * Render the License Key metabox.
	 *
	 * Includes the license key field and JavaScript to activate/deactivate via AJAX.
	 *
	 * Better name: render_metabox_license()
	 *
	 * @return void
	 */
	function meta_box_license() {

		$license_key = $this->get_setting( 'license_key' );
		if ( empty( $license_key ) ) {
			$license_key = '';
		}
		?>
		<div id="wpmr_license_form">
			
			<input 
				type="<?php echo ! $this->is_advanced_edition() ? 'text' : 'password'; ?>" 
				size="50" 
				required 
				placeholder="Check purchase receipt in your email for license key." 
				id="wpmr_license" 
				name="wpmr_license" 
				value="<?php echo esc_attr( $license_key ); ?>" 
			/>
			<div id="wpmr_license_response"></div>			
			<div id="wpmr_license_status"><img style="width:16px;height:16px;" src="<?php echo esc_url( $this->url . 'assets/spinner2.svg' ); ?>" /></div>
			<?php
			if ( ! empty( $license_key ) ) {
				?>
				<p><input type="button" id="wpmr_license_action" class="button malcure-button-primary" value="De-Activate"></p>
				<?php
			} else {
				?>
				<p><input type="button" id="wpmr_license_action" class="button malcure-button-primary" value="Save & Activate"></p>
				<?php
			}
			?>
		</div>

		<script type="text/javascript">
			//<![CDATA[
			jQuery(document).ready(function($) {
				
				// Unified license action handler (activate/deactivate)
				$(document).on('click', '#wpmr_license_action', function(e) {
					e.preventDefault();
					
					var buttonValue = $(this).val();
					var isDeactivate = buttonValue === 'De-Activate';
					
					var license_key = $('#wpmr_license').val().trim();
					
					if (!isDeactivate && !license_key) {
						render_license_error_js('License key is required.', 'error');
						return;
					}
					
					var overlayMessage = isDeactivate ? 'Deactivating license...' : 'Activating license...';
					showOverlay(overlayMessage);
					
					var ajaxData = {
						action: 'wpmr_license_action',
						wpmr_license_action_nonce: '<?php echo esc_js( wp_create_nonce( 'wpmr_license_action' ) ); ?>',
						license_action: isDeactivate ? 'deactivate' : 'activate'
					};
					if (!isDeactivate) {
						ajaxData.license_key = license_key;
					}

					$.ajax({
						url: ajaxurl,
						method: 'POST',
						data: ajaxData,
						success: function(response) {
							hideOverlay();
							if (response.success) {
								// Update button and input for successful activation
								if (!isDeactivate) {
									fetch_license_status();
									$('#wpmr_license').attr('type', 'password');
									$('#wpmr_license').val(license_key); // Ensure the key stays in the field
									$('#wpmr_license_action').val('De-Activate');
									/*
									// need to call refresh_checksums_async via ajax.
									$.ajax({
										url: ajaxurl,
										method: 'POST',
										data: {
											action: 'wpmr_refresh_checksums',
											nonce: '<?php echo esc_js( wp_create_nonce( 'wpmr_refresh_checksums' ) ); ?>'
										},
										complete: function(jqXHR, textStatus) {
											console.log('Checksum refresh triggered.');
										}
									});
									*/
								}
							} else {
								render_license_error_js(response.data, 'error');
							}
						},
						error: function(xhr, status, error) {
							hideOverlay();
							render_license_error_js('Request failed: ' + error, 'error');
						},
						complete: function(jqXHR, textStatus){
							if(isDeactivate){
								$('#wpmr_license').val('');
								$('#wpmr_license').attr('type', 'text');
								$('#wpmr_license_action').val('Save & Activate');
								$('#wpmr_license_status').html('');
							}
						}
					});
				});

				jQuery(document).ready(function($) {
					
					// Fetch license status if license key is present
					if( $('#wpmr_license').val().trim() !== '') {
						console.dir('License key present, fetching status');
						fetch_license_status();
					} else {
						$('#wpmr_license_status').html('');
					}
				});

				// Function to fetch and display license status via AJAX
				function fetch_license_status() {
					console.dir('Fetching license status via AJAX');
					$.ajax({
						url: ajaxurl,
						method: 'POST',
						data: {
							action: 'wpmr_fetch_license_status',
							wpmr_fetch_license_nonce: '<?php echo esc_js( wp_create_nonce( 'wpmr_fetch_license' ) ); ?>'
						},
						success: function(response) {
							if (response.success) {
								display_license_status_js(response.data);
							} else {
								$('#wpmr_license_status').html('<div class="notice notice-error"><p>' + response.data + '</p></div>');
							}
						},
						error: function(xhr, status, error) {
							$('#wpmr_license_status').html('<div class="notice notice-error"><p>Failed to fetch license status: ' + error + '</p></div>');
						}
					});
				}

				// Function to display license status data
				function display_license_status_js(data) {
					var statusHtml = '<div class="license-status-info">';
					
					if (data.license_status) {
						statusHtml += '<p><strong>Status:</strong> ' + data.license_status + '</p>';
					}
					
					if (data.error_reason) {
						statusHtml += '<p><strong>Reason:</strong> ' + data.error_reason + '</p>';
					}
					
					if (data.customer_email) {
						statusHtml += '<p><strong>Buyer Email:</strong> ' + data.customer_email + '</p>';
					}
					
					if (data.customer_name) {
						statusHtml += '<p><strong>Customer:</strong> ' + data.customer_name + '</p>';
					}
					
					if (data.activations) {
						statusHtml += '<p><strong>Activations:</strong> ' + data.activations.used + ' of ' + data.activations.limit + '</p>';
						statusHtml += '<p><strong>Remaining:</strong> ' + data.activations.remaining + '</p>';
					}
					
					if (data.expires_formatted) {
						statusHtml += '<p><strong>Expires:</strong> ' + data.expires_formatted + '</p>';
					}
					
					if (data.renewal_link) {
						statusHtml += '<p><em>Your license has expired. <a href="' + data.renewal_link + '" target="_blank" class="malcure-button-primary button-primary">Renew License First &rarr;</a></em></p>';
					}
					
					statusHtml += '</div>';
					$('#wpmr_license_status').html(statusHtml);
				}
				
				// Show license message function
				function render_license_error_js(message, type) {
					var messageClass = type === 'error' ? 'notice-error' : 'notice-success';
					var messageHtml = '<div class="notice ' + messageClass + ' is-dismissible"><p><strong>' + message + '</strong></p></div>';
					$('#wpmr_license_response').html(messageHtml);
					$('#wpmr_license_response').fadeIn();
				}
			});
			//]]>
			</script>

		<?php
	}

	/**
	 * Render the Scan Logs metabox.
	 *
	 * Reads persisted scan log transients (`_transient_WPMR_log_*`) and renders the stored
	 * detections (DB/file/vulnerabilities) for debugging and forensics.
	 *
	 * Better name: render_metabox_scan_logs()
	 *
	 * @return void
	 */
	function meta_box_logs() {
		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Scan log review must reflect current persisted forensic data, and wildcard option enumeration has no equivalent core helper.
		$results = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT `option_name` AS `name`, `option_value` AS `value` FROM {$wpdb->options} WHERE `option_name` LIKE %s ORDER BY `option_name` DESC",
				'%_transient_WPMR_log_%'
			)
		);

		if ( ! $results ) {
			echo '<div class="log postbox"><h2 class="toggle-section hndle">Nothing in scan logs</h2><div class="section-content inside"><p>Scan log is empty. Scan logs are retained for 30 days.</p></div></div>';
			return;
		}

		$timezone_string = function_exists( 'wp_timezone_string' ) ? wp_timezone_string() : $this->timezone_string_compat();
		$timezone        = new DateTimeZone( $timezone_string );

		foreach ( $results as $result ) {
			$time = str_replace( '_transient_WPMR_log_', '', $result->name );

			// Convert timestamp
			try {
				$date = new DateTime( '@' . $time ); // Timestamp in UTC
				$date->setTimezone( $timezone );
				$formatted_time = $date->format( get_option( 'date_format' ) . ', h:i:s A' ) . ' ' . $timezone_string;
			} catch ( Exception $e ) {
				$formatted_time = 'Invalid Timestamp';
			}

			echo '<div class="log postbox">';
			echo '<h2 class="toggle-section hndle">Scan Log ' . esc_html( $formatted_time ) . ' [ <a href="' . esc_url( get_admin_url( null, 'options-general.php' ) ) . '#WPLANG">WordPress Time</a> ]</h2>';

			$detection = json_decode( $result->value, true );
			echo '<div class="section-content inside">';

			if ( ! empty( $detection['vulnerabilities'] ) ) {
				echo '<h4>Vulnerabilities</h4>';
				echo '<table class="scan_log"><tr><th>Status</th><th>Component</th></tr>';

				// Display WordPress core vulnerabilities
				if ( ! empty( $detection['vulnerabilities']['core'] ) ) {
					foreach ( $detection['vulnerabilities']['core'] as $component => $vuln ) {
						$severity   = esc_attr( $vuln['severity'] );
						$ssig       = esc_html( $vuln['signature'] );
						$threat_url = esc_url( $this->wpmr_url( 'p=2074&ssig=' . $ssig, 'ioc-lookup', 'vulnerability' ) );

						echo '<tr><td><a target="_blank" class="threat ' . esc_attr( $severity ) . '" href="' . esc_url( $threat_url ) . '">' . esc_html( strtoupper( $severity ) ) . '</a></td><td><pre class="record">' . esc_html( $component ) . '</pre></td></tr>';
					}
				}

				// Display plugin vulnerabilities
				if ( ! empty( $detection['vulnerabilities']['plugins'] ) ) {
					foreach ( $detection['vulnerabilities']['plugins'] as $plugin => $vuln ) {
						$severity   = esc_attr( $vuln['severity'] );
						$ssig       = esc_html( $vuln['signature'] );
						$threat_url = esc_url( $this->wpmr_url( 'p=2074&ssig=' . $ssig, 'ioc-lookup', 'vulnerability' ) );

						echo '<tr><td><a target="_blank" class="threat ' . esc_attr( $severity ) . '" href="' . esc_url( $threat_url ) . '">' . esc_html( strtoupper( $severity ) ) . '</a></td><td><pre class="record">' . esc_html( $plugin ) . '</pre></td></tr>';
					}
				}

				// Display theme vulnerabilities
				if ( ! empty( $detection['vulnerabilities']['themes'] ) ) {
					foreach ( $detection['vulnerabilities']['themes'] as $theme => $vuln ) {
						$severity   = esc_attr( $vuln['severity'] );
						$ssig       = esc_html( $vuln['signature'] );
						$threat_url = esc_url( $this->wpmr_url( 'p=2074&ssig=' . $ssig, 'ioc-lookup', 'vulnerability' ) );

						echo '<tr><td><a target="_blank" class="threat ' . esc_attr( $severity ) . '" href="' . esc_url( $threat_url ) . '">' . esc_html( strtoupper( $severity ) ) . '</a></td><td><pre class="record">' . esc_html( $theme ) . '</pre></td></tr>';
					}
				}

				echo '</table>';
			}

			if ( ! empty( $detection['users'] ) ) {
				echo '<h4>User Account Flags</h4>';
				echo '<table class="scan_log"><tr><th>Severity</th><th>User</th></tr>';
				$edit_base = is_multisite() ? network_admin_url( 'user-edit.php?user_id=' ) : admin_url( 'user-edit.php?user_id=' );
				foreach ( $detection['users'] as $user ) {
					$severity = esc_attr( $user['severity'] );
					$user_id  = (int) $user['ID'];
					$edit_url = esc_url( $edit_base . $user_id );

					$reasons = array();
					if ( ! empty( $user['missing_email'] ) ) {
						$reasons[] = 'email missing';
					}
					if ( ! empty( $user['has_app_passwords'] ) ) {
						$count = (int) ( isset( $user['app_password_count'] ) ? $user['app_password_count'] : 0 );
						$reasons[] = 'app passwords: ' . $count;
					}
					if ( ! empty( $user['has_elevated_caps'] ) ) {
						$reasons[] = 'elevated caps';
					}
					if ( ! empty( $user['missing_first_name'] ) || ! empty( $user['missing_last_name'] ) ) {
						$reasons[] = 'name missing';
					}
					if ( ! empty( $user['ip_spread_score'] ) && (float) $user['ip_spread_score'] > 0 ) {
						$reasons[] = 'ip spread ' . number_format( (float) $user['ip_spread_score'], 3 );
					}
					$tooltip = 'User ID ' . $user_id . ' — ' . $severity . ( $reasons ? ' (' . implode( ', ', $reasons ) . ')' : '' );

					echo '<tr title="' . esc_attr( $tooltip ) . '">';
					echo '<td><a target="_blank" class="threat ' . esc_attr( $severity ) . '" href="' . esc_url( $edit_url ) . '">' . esc_html( strtoupper( $severity ) ) . '</a></td>';
					echo '<td><pre class="record">User ID ' . esc_html( $user_id ) . '</pre></td>';
					echo '</tr>';
				}
				echo '</table>';
			}

			if ( ! empty( $detection['db'] ) ) {
				echo '<h4>Database Infections</h4>';
				echo '<table class="scan_log"><tr><th>Severity</th><th>Type</th><th>Action</th></tr>';
				foreach ( $detection['db'] as $infection ) {
					echo '<tr><td><a target="_blank" class="threat ' . esc_attr( $infection['severity'] ) . '" href="' . esc_url( $this->wpmr_url( 'p=2074&ssig=' . $infection['infection'], 'ioc-lookup', 'database' ) ) . '">' . esc_html( strtoupper( $infection['severity'] ) ) . '</a></td><td><pre class="record">' . esc_html( strtoupper( $infection['type'] ) ) . ' ' . esc_html( $infection['id'] ) . '</pre></td><td><a href="' . esc_url( $this->wpmr_url( 'p=107', 'scan-result-cta', 'service-request' ) ) . '" target="_blank" class="malcure-button-primary">Request Expert Cleanup →</a></td></tr>';
				}
				echo '</table>';
			}

			if ( ! empty( $detection['files'] ) ) {
				echo '<h4>File Infections</h4>';
				echo '<table class="scan_log"><tr><th>Severity</th><th>File</th><th>Action</th></tr>';
				foreach ( $detection['files'] as $f => $det ) {
					$file_path  = htmlentities( $f );
					$severity   = esc_attr( $det['severity'] );
					$ssig       = esc_html( $det['id'] );
					$threat_url = esc_url( $this->wpmr_url( 'p=2074&ssig=' . $ssig, 'ioc-lookup', 'file' ) );

					if ( file_exists( $f ) ) {
						echo '<tr><td><a target="_blank" class="threat ' . esc_attr( $severity ) . '" href="' . esc_url( $threat_url ) . '">' . esc_html( strtoupper( $severity ) ) . '</a></td><td><pre class="record">' . esc_html( $file_path ) . '</pre></td><td><a href="' . esc_url( $this->wpmr_url( 'p=107', 'scan-result-cta', 'service-request' ) ) . '" target="_blank" class="malcure-button-primary">Request Expert Cleanup &rarr;</a></td></tr>';
					} else {
						echo '<tr><td><a target="_blank" class="threat ' . esc_attr( $severity ) . '" href="' . esc_url( $threat_url ) . '">' . esc_html( strtoupper( $severity ) ) . '</a></td><td><pre class="record"><del>' . esc_html( $file_path ) . '</del></pre></td><td></td></tr>';
					}
				}
				echo '</table>';
			}

			echo '</div>';
			echo '</div>';
		}
	}

	/**
	 * Render the "Advanced Options" metabox (scan toggles and advanced inputs).
	 *
	 * Better name: render_metabox_advanced_options()
	 *
	 * @return void
	 */
	function meta_box_pro() {
		?>
		<p><input type="checkbox" name="do_redirect_scan" checked id="do_redirect_scan"/> <label for="do_redirect_scan">Scan for Redirects</label></p>
		<p><input type="checkbox" name="do_vuln_scan" checked id="do_vuln_scan"/> <label for="do_vuln_scan">Scan Vulnerabilities</label></p>
		<p><input type="checkbox" name="do_user_scan" checked id="do_user_scan"/> <label for="do_user_scan">Scan User Accounts</label></p>
		<p><input type="checkbox" name="do_db_scan" checked id="do_db_scan"/> <label for="do_db_scan">Scan Database</label></p>
		<p><input type="checkbox" name="do_file_scan" checked id="do_file_scan"/> <label for="do_file_scan">Scan Files</label></p>
		<p><input type="checkbox" name="show_suspicious" id="show_suspicious" /> <label for="show_suspicious">Paranoia-Mode: Show suspicious matches too.</label></p>
		<p><strong>Force-skip the following directories:</strong></p>
		<p><input type="text" name="skipdirs" id="skipdirs" class="widefat" placeholder="wp-content,mu-plugins" /></p>

		<?php
		if ( $this->is_advanced_edition() ) {
			?>
			<p><strong>Additional File Scan Definition</strong></p>
			<p><input type="text" name="wpmr_extra_reg" id="wpmr_extra_reg" class="widefat" placeholder="Proper PHP RegEx String Like: /https:\/\/bit\.ly\//is"/></p>
			<p><strong>Additional Database Scan Definition:</strong></p>
			<table class="widefat">
			<tr>
				<th><strong>Database Query String:</strong></th>
				<th><strong>RegEx to match in the results of the query:</strong></th>
			</tr>
			<tr>
				<td><input type="text" name="wpmr_extra_db_query" id="wpmr_extra_db_query" class="widefat" placeholder="Like SQL: %message%" /></td>
				<td><input type="text" name="wpmr_extra_db_regex" id="wpmr_extra_db_regex" class="widefat" placeholder="Proper PHP RegEx String Like: /https:\/\/bit\.ly\//is" /></td>
			</tr>
			</table>
			<p><strong>Only scan the following custom file:</strong></p>
			<p><input type="text" name="wpmr_scan_single_file" id="wpmr_scan_single_file" class="widefat" placeholder="<?php echo esc_attr( 'Absolute path to the file like ' . trailingslashit( ABSPATH ) . 'index.php' ); ?>"/></p>
			<p><strong>Only scan the following custom directories:</strong></p>
			<p><input type="text" name="wpmr_scan_only_dirs" id="wpmr_scan_only_dirs" class="widefat" placeholder="Paths relative to <?php echo esc_html( ABSPATH ); ?> and comma separated, like wp-content/uploads"/></p>
			<?php
		}
	}

	/**
	 * Render the Scan Results metabox container.
	 *
	 * The UI populates this section via client-side scripting during/after scans.
	 *
	 * Better name: render_metabox_results()
	 *
	 * @return void
	 */
	function meta_box_results() {
		?>
		<div class="scan_results">
		<?php
		if ( $this->is_advanced_edition() ) {
			echo '<p><strong>';
			submit_button( 'Copy Results', 'malcure-button-primary', 'wpmr_copy', false );
			echo '<span id="copied_check"></span>';
			echo '</strong></p>';
		}
		?>
			<div id="result_range">            
			<?php
			if ( empty( $this->get_setting( 'sig_time' ) ) ) {
				echo '<h4 id="definition_warning">Your site is using out of date definitions. <Span class="wpmr_no_copy">Click here to connect to Malcure API Server for a thorough scan →</span></h4>';
			}
			?>
				<div id="results_wrap">
					<h2 id="results_head">&#x2973;&larr;&larr;&larr;&nbsp;MALCURE&nbsp;SCAN&nbsp;LOG&nbsp;&rarr;&rarr;&rarr;&#x2974;</h2>
					<h3>&nbsp;&mdash;&nbsp;Redirect&nbsp;Hijack&nbsp;&mdash;&nbsp;</h3>
					<div id="redirect_hijack"></div>
					<h3>&nbsp;&mdash;&nbsp;Title&nbsp;Hack&nbsp;&mdash;&nbsp;</h3>
					<div id="title_hack"></div>
					<h3>&nbsp;&mdash;&nbsp;Vulnerabilities&nbsp;&mdash;&nbsp;</h3>
					<div id="vulnerabilities"></div>
					<h3>&nbsp;&mdash;&nbsp;User&nbsp;Account&nbsp;Audit&nbsp;&mdash;&nbsp;</h3>
					<div id="user_results"></div>
					<div id="whitelist_wrap">
						<?php
						if ( ! $this->is_advanced_edition() ) {
							echo '<p class="advanced_features wpmr_no_copy"><a href="' . esc_url( $this->wpmr_url( 'p=116', 'sidebar-cta', 'whitelist-notice' ) ) . '">Did you know, you can now whitelist files and database records in Malcure Advanced Edition&nbsp;&rarr;</a></p>';
						} else {
							?>
								<h4 style="text-align:center">&mdash; WHITELISTED DATABASE RECORDS &mdash;</h4>
								<div id="db_whitelist">
									<p id="db-whitelist-present-placeholder" style="text-align:center;display:none;"><strong>The following whitelisted database records will not be scanned&nbsp;&rarr;</strong></p>
									<p id="db-whitelist-absent-placeholder" style="text-align:center;display:none;">No database records whitelisted.</p>
									<?php
									if ( $this->get_db_record_whitelist() ) {
										$this->render_db_record_whitelist();
									}
									?>
								</div>

								<h4 style="text-align:center">&mdash; WHITELISTED FILES &mdash;</h4>
								<div id="whitelist">
									<p id="whitelist-present-placeholder" style="text-align:center;display:none;"><strong>The following whitelisted files will not be scanned&nbsp;&rarr;</strong></p>
									<p id="whitelist-absent-placeholder" style="text-align:center;display:none;">No files whitelisted.</p>
							<?php
							if ( $this->get_user_whitelist() ) {
								$this->render_whitelist();
							}
							?>
								</div>
							<?php
						}
						?>
					</div>
					<h3>&nbsp;&mdash;&nbsp;Database&nbsp;Scan&nbsp;&mdash;&nbsp;</h3>
					<div id="db_results"></div>
					<h3>&nbsp;&mdash;&nbsp;File&nbsp;Scan&nbsp;&mdash;&nbsp;</h3>
					<div id="file_results"></div>
				</div>
				<div id="wpmr_cta_wrap">
					<?php
					if ( ! $this->is_registered() ) {
						echo '<a class="blink" id="cta-register">Unable to ensure accuracy of malware detection due to outdated definitions.<br /><span class="wpmr_no_copy">Click here to connect to the API and update definitions</span></a>';
					}
					?>
					<div  id="service_cta"></div>
				</div>
			</div>
		</div>
			<?php
	}

	/**
	 * Render the Updates/Registration metabox.
	 *
	 * When registered, shows definition update controls, reset controls, UX audio toggle,
	 * and optional Google Search Console connection. When not registered, renders the
	 * registration form.
	 *
	 * Better name: render_metabox_updates()
	 *
	 * @return void
	 */
	function meta_box_updates() {
		$registered = $this->is_registered();
		// Read-only admin render flag for showing operator diagnostics.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- `debug` only toggles admin-only output and does not process state changes.
		$is_debug_request = isset( $_REQUEST['debug'] );
		if ( $registered ) {
			$class = 'registered';
		} else {
			$class = 'unregistered';
		}
		?>
		<div class="wpmr_updates_wrap <?php echo esc_attr( $class ); ?>">
		<?php
		if ( $this->is_registered() ) {
			if ( $this->is_advanced_edition() ) {
				?>
					<div class="malcure_pro_info licensed">
						<h2 id="heading">Malcure Advanced Edition</h2>
					</div>
				<?php
			}
			if ( $this->definition_updates_available() ) {
				echo '<p id="update_notice_p" style="color:hsl(350, 66%, 50%);">New malware definitions version <strong>' . esc_html( $this->get_setting( 'update-version' ) ) . '</strong> are available. Please update!</p>';
			}
			echo '<div class="wpmr_updates_wrap">';

			if ( $this->is_advanced_edition() ) {
				echo '<label><input type="checkbox" ' . ( $this->get_setting( 'def_auto_update_enabled' ) ? 'checked' : '' ) . ' id="wpmr_def_auto_update_enabled"/>Auto-Update Definitions</label>';
			}
			submit_button( 'Update Definitions', 'malcure-button-primary', 'wpmr_update' );
			echo '<div id="update_response"></div></div>'; // end wpmr_updates_wrap
			echo '<div class="wpmr_reset_wrap">';

			if ( $this->is_advanced_edition() || $is_debug_request ) {
				echo '<label><input type="checkbox" id="wpmr_reset_logs"> Also reset scan logs</label>';
				submit_button( 'Reset Plugin', 'primary', 'wpmr_reset' );
			}
			echo '</div>'; // end wpmr_reset_wrap
			echo '<div class="wpmr_misc_wrap"><label><input type="checkbox" ' . ( $this->get_setting( 'ux_notifications_enabled' ) != 'off' ? 'checked' : '' ) . ' id="wpmr_ux_notifications_enabled"/>Enable Audio Notifications</label></div>';

			$reg       = $this->get_setting( 'user' );
			$statevars = $this->encode( array_merge( $this->get_diag_data(), $reg ) );
			echo '<div id="wpmr_gsc_wrap">';
			if ( empty( $reg['gsc'] ) ) {
				echo '<p><a id="wpmrgscconnect" class="malcure-button-primary" href="' . esc_url( WPMR_SERVER . '?p=495&wpmr_authenticate=' . $statevars ) . '">Connect to Google Search Console&nbsp;&rarr;</a></p>';
				echo '<p style="margin-top:0;"><small><em for="wpmrgscconnect">Get security alerts from Google Search Console.</em></small></p>';
				if ( $is_debug_request ) {
					echo wp_kses_post( $this->debug_value_to_string( $this->get_setting( 'user' ) ) );
				}
			}
			echo '</div>';
		} else {
			echo '<div id="is_unregistered"><h3 style="line-height: 1.618em;"><strong>Thank you for installing Malcure Malware Scanner - Advanced Virus and Infection Cleanup</strong></h3><div class="reg_wrap" style="padding: 0em 1.618em">
                <h1 style="line-height:1;padding:0;">Activate Malcure<small><sup>&trade;</sup></small>&nbsp;Cloud&nbsp;&rarr;</h1>
				<p data-style="width:61%;margin: 1em auto;">Malcure requires a <strong>free</strong> connection with Malcure Cloud for malware scanning. Access is provided at no charge under fair-use; rate limits may apply.<br /></p>';

			$current_user = wp_get_current_user();
			?>
				<form id="wpmp_reg_form">
					<table id="wpmr_reg" style="margin: 0;">
						<tr>
							<td>First&nbsp;Name:</td>
							<td><input style="width:100%;" type="text" name="wpmr_fn" id="wpmr_fn" required value="<?php echo esc_attr( empty( $current_user->user_firstname ) ? '' : $current_user->user_firstname ); ?>" /></td>
						</tr>
						<tr>
							<td>Last&nbsp;Name:</td>
							<td><input style="width:100%;" type="text" name="wpmr_ln" id="wpmr_ln" required value="<?php echo esc_attr( empty( $current_user->user_lastname ) ? '' : $current_user->user_lastname ); ?>" /></td>
						</tr>
						<tr>
							<td>Email:</td>
							<td><input style="width:100%;" type="email" name="wpmr_eml" id="wpmr_eml" <?php echo ( ! empty( $current_user->user_email ) ) ? ( $is_debug_request ? '' : 'readonly="readonly"' ) : ''; ?> required value="<?php echo esc_attr( ( ! empty( $current_user->user_email ) ) ? $current_user->user_email : '' ); ?>" /></td>
						</tr>
						<!--
						<tr>
							<td colspan="2"><label style="display:block; margin-top: 1.618em; color: #00ffff">
									<input type="checkbox" name="wpmr_scan_notify_registrant" id="wpmr_scan_notify_registrant" value="1" />
									Email me when a scheduled scan completes [<strong>Recommended</strong>].
								</label>
								<p style="margin: 0 0 1em 2em;"><small>Know if your site is clean or infected — without keeping a browser open or running scans manually.</small></p>
								<label style="display:block; margin-top: .618em; color: #00ffff">
									<input type="checkbox" name="wpmr_pulse_notify_registrant" id="wpmr_pulse_notify_registrant" value="1" />
									Email me a weekly security summary [<strong>Recommended</strong>].
								</label>
								<p style="margin: 0 0 1em 2em;"><small>Get alerted about critical before malware spreads, before your checkout breaks, before Google blacklists your site, and before your emails stop delivering.</small></p>
							</td>
						</tr>
						-->
						<tr>
							<td colspan="2"><p id="submit_control_wrap">
								<?php
								submit_button( 'Activate&nbsp;Free&nbsp;&rarr;', 'primary', 'wpmr_register', false, array( 'style' => 'width:100%' ) );
								echo '<br /><br /><small>By registering you agree to our <a href="' . esc_url( $this->wpmr_url( 'p=1720', 'registration', 'terms' ) ) . '" target="_blank">T&amp;C and Privacy Policy</a>.</small></p>';
								?>
							</td>
						</tr>
						
				</table>
			</form>
			<?php

			echo '<div id="reg_error"></div>';
			echo '</div>';
			echo '</div>';
		}

		?>
			</div>
		<?php
	}

	/**
	 * Prevent hiding of Malcure metaboxes.
	 *
	 * Hooked to `hidden_meta_boxes` and returns an empty list on Malcure screens.
	 *
	 * Better name: filter_hidden_meta_boxes_for_wpmr()
	 *
	 * @param array  $hidden       Hidden metabox IDs.
	 * @param object $screen       Current screen object.
	 * @param bool   $use_defaults Whether default hidden boxes are used.
	 * @return array
	 */
	function no_hidden_meta_boxes( $hidden, $screen, $use_defaults ) {
		if ( preg_match( '/wpmr/', $screen->id ) ) {
			return array(); // No hidden meta boxes
		}
		return $hidden;
	}

	/**
	 * Block AJAX requests that change metabox order/state on Malcure pages.
	 *
	 * Hooked via the `check_ajax_referer` action. Stops `meta-box-order` and
	 * `closedpostboxes` actions for Malcure pages.
	 *
	 * Better name: block_wpmr_metabox_order_changes()
	 *
	 * @param string $action Action name passed into `check_ajax_referer`.
	 * @return void
	 */
	function prevent_meta_box_order( $action ) {
		// This callback runs from the `check_ajax_referer` action after core nonce verification.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- The request page check is guarded by the verified caller contract on the hook.
		$page = isset( $_REQUEST['page'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['page'] ) ) : '';
		if ( ( 'meta-box-order' === $action || 'closedpostboxes' === $action ) && preg_match( '/wpmr/', $page ) ) {
			die( 'Nope!' );
		}
	}

	/**
	 * Remove existing metabox registrations from Malcure screens.
	 *
	 * Hooked to `add_meta_boxes` to ensure third-party metaboxes cannot interfere with the
	 * Malcure UI screens.
	 *
	 * Better name: remove_conflicting_metaboxes()
	 *
	 * @return void
	 */
	function remove_metaboxes() {
		global $wp_meta_boxes;
		if ( empty( $wp_meta_boxes ) ) {
			return;
		}
		foreach ( $wp_meta_boxes as $k => $v ) {
			if ( preg_match( '/wpmr/', $k ) ) {
				$wp_meta_boxes[ $k ] = array();
			}
		}
	}
}