<?php

namespace WPSecurityNinja\Plugin;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
require 'sn-el-modules.php';

class Wf_Sn_El {
	/**
	 * Cached module active state.
	 *
	 * @var bool|null
	 */
	private static $is_active        = null;
	/**
	 * Cached module options.
	 *
	 * @var array<string, mixed>|false|null
	 */
	private static $options          = null;
	private static $watching_actions = false;
	/**
	 * init plugin
	 *
	 * @author  Unknown
	 * @since   v0.0.1
	 * @version v1.0.0  Wednesday, May 15th, 2024.
	 * @access  public static
	 * @return  void
	 */
	public static function init() {
		self::$options = get_option( 'wf_sn_el' );
		self::default_settings( false );

		// Register settings earlier in the init process
		add_action( 'admin_init', array( __CLASS__, 'register_settings' ) );

		add_action( 'wp_ajax_get_events_data', array( __CLASS__, 'ajax_get_events_data' ) );
		add_action( 'wp_ajax_get_events_actions', array( __CLASS__, 'ajax_get_events_actions' ) );

		// Add the monitor for new admin users
		add_action( 'user_register', array( __CLASS__, 'monitor_new_admin_creation' ) );

		// Schedule hourly check for direct database admin creations
		if ( ! wp_next_scheduled( 'secnin_check_direct_admin_creation' ) ) {
			wp_schedule_event( time(), 'hourly', 'secnin_check_direct_admin_creation' );
		}
		add_action( 'secnin_check_direct_admin_creation', array( __CLASS__, 'check_direct_admin_creation' ) );

		if ( is_null( self::$is_active ) ) {
			self::$is_active = self::is_active();
		}

		if ( is_admin() ) {
			// add tab to Security Ninja tabs
			add_filter( 'sn_tabs', array( __NAMESPACE__ . '\Wf_Sn_El', 'sn_tabs' ) );

			add_action( 'admin_enqueue_scripts', array( __NAMESPACE__ . '\Wf_Sn_El', 'enqueue_scripts' ) );

			add_action( 'wp_ajax_sn_el_truncate_log', array( __NAMESPACE__ . '\Wf_Sn_El', 'ajax_truncate_log' ) );

			add_action( 'secnin_prune_logs_cron', array( __NAMESPACE__ . '\Wf_Sn_El', 'do_cron_prune_logs' ) );

			if ( self::$is_active ) {
				add_action( 'all', array( __NAMESPACE__ . '\Wf_Sn_El', 'watch_actions' ), 9, 10 );
			}
		}

		// REST API logging hooks
		add_filter( 'rest_authentication_errors', array( __CLASS__, 'rest_log_auth_errors' ), 999 );
		add_filter( 'determine_current_user', array( __CLASS__, 'rest_log_determine_user' ), 99 );
		add_filter( 'rest_pre_dispatch', array( __CLASS__, 'rest_log_pre_dispatch' ), 999, 3 );
		add_filter( 'rest_post_dispatch', array( __CLASS__, 'rest_log_post_dispatch' ), 999, 3 );

		// Schedule the cron job to run twice daily
		if ( ! wp_next_scheduled( 'secnin_prune_logs_cron' ) ) {
			wp_schedule_event( time(), 'daily', 'secnin_prune_logs_cron' );
		}
	}



	/**
	 * Monitor creation of new admin users through WordPress
	 *
	 * @param int $user_id The ID of the newly created user
	 * @return void
	 */
	public static function monitor_new_admin_creation( $user_id ) {
		$user = get_userdata( $user_id );
		if ( ! $user || ! in_array( 'administrator', (array) $user->roles ) ) {
			return;
		}

		if ( ! self::$options['notify_new_admin'] ) {
			return;
		}

		// self::send_admin_notification($user, false); // @todo - when activating this feature, mark existing admins to prevent notifications for existing admin accounts.

		// Update the last checked ID immediately when a legitimate admin is created
		update_option( 'secnin_last_checked_admin_id', $user_id );

		// Log the legitimate creation
		wf_sn_el_modules::log_event(
			'security_ninja',
			'admin_created',
			sprintf(
				/* translators: %s: username of the new administrator */
				__( 'New administrator account created normally: %s', 'security-ninja' ),
				$user->user_login
			),
			array( 'user_id' => $user_id )
		);
	}


	/**
	 * Log REST API authentication errors
	 *
	 * @param mixed $result
	 * @return mixed
	 */
	public static function rest_log_auth_errors( $result ) {
		if ( defined( 'REST_REQUEST' ) && REST_REQUEST && is_wp_error( $result ) ) {
			$user_ip = call_user_func( __NAMESPACE__ . '\\Wf_sn_cf::get_user_ip' );
			$payload = array(
				'ip'      => $user_ip,
				'uri'     => isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '',
				'code'    => $result->get_error_code(),
				'message' => $result->get_error_message(),
				'data'    => $result->get_error_data(),
			);
			wf_sn_el_modules::log_event( 'rest', 'auth_error', __( 'REST authentication error', 'security-ninja' ), $payload, get_current_user_id() );
		}
		return $result;
	}

	/**
	 * Log resolved user during REST requests
	 *
	 * @param int|false $user_id
	 * @return int|false
	 */
	public static function rest_log_determine_user( $user_id ) {
		return $user_id;
	}

	/**
	 * Log pre-dispatch REST errors (short-circuits)
	 *
	 * @param mixed           $result
	 * @param \WP_REST_Server $server
	 * @param \WP_REST_Request $request
	 * @return mixed
	 */
	public static function rest_log_pre_dispatch( $result, $server, $request ) {
		return $result;
	}

	/**
	 * Log REST final error responses and successful post creations
	 *
	 * @param mixed            $result
	 * @param \WP_REST_Server  $server
	 * @param \WP_REST_Request $request
	 * @return mixed
	 */
	public static function rest_log_post_dispatch( $result, $server, $request ) {
		$response = rest_ensure_response( $result );
		$status   = (int) $response->get_status();
		$data     = $response->get_data();

		// Log error responses
		if ( $status >= 400 ) {
			$error_payload = array(
				'method' => $request->get_method(),
				'route'  => $request->get_route(),
				'status' => $status,
			);
			if ( is_array( $data ) ) {
				// Include common error fields only
				$error_payload['code']    = isset( $data['code'] ) ? $data['code'] : '';
				$error_payload['message'] = isset( $data['message'] ) ? $data['message'] : '';
			}
			// Ignore expected connector plugin probe misses from WP Connectors UI.
			if (
				404 === $status
				&& isset( $error_payload['code'] )
				&& 'rest_plugin_not_found' === $error_payload['code']
				&& is_string( $error_payload['route'] )
				&& strpos( $error_payload['route'], '/wp/v2/plugins/' ) === 0
			) {
				return $result;
			}
			// Use hardcoded string to prevent infinite loop with translation functions
			wf_sn_el_modules::log_event( 'rest', 'error_response', 'REST error response', $error_payload, get_current_user_id() );
			return $result;
		}

		return $result;
	}
	/**
	 * Check for admin users created directly in the database
	 */
	public static function check_direct_admin_creation() {
		global $wpdb;

		$last_checked_id = get_option( 'secnin_last_checked_admin_id', 0 );

		$query = $wpdb->prepare(
			"SELECT DISTINCT u.ID, u.user_login, u.user_email, u.user_registered 
			 FROM {$wpdb->users} u 
			 INNER JOIN {$wpdb->usermeta} um ON u.ID = um.user_id 
			 WHERE um.meta_key = %s 
			 AND (
				 um.meta_value LIKE %s 
				 OR um.meta_value LIKE %s
				 OR um.meta_value LIKE %s
			 )
			 AND u.ID > %d",
			$wpdb->prefix . 'capabilities',
			'%administrator%',
			'%s:13:"administrator"%',
			'%a:1:{s:13:"administrator";b:1}%',
			$last_checked_id
		);

		$new_admins = $wpdb->get_results( $query );

		if ( ! empty( $new_admins ) ) {
			foreach ( $new_admins as $admin ) {
				// Check if this admin was created through WordPress (has an action log)
				$was_created_normally = $wpdb->get_var(
					$wpdb->prepare(
						"SELECT COUNT(*) FROM {$wpdb->prefix}wf_sn_el 
					 WHERE action = %s 
					 AND description LIKE %s 
					 AND timestamp > DATE_SUB(NOW(), INTERVAL 5 MINUTE)",
						'admin_created',
						'%' . $admin->user_login . '%'
					)
				);

				// @todo - what if user was created before plugin install
				// @todo - what if user
				// Only notify if it wasn't created through WordPress

				// if (!$was_created_normally) {
				//  if (isset(self::$options['notify_new_admin']) && self::$options['notify_new_admin']) {
				//      self::send_admin_notification($admin, true);
				//  }

				//  wf_sn_el_modules::log_event(
				//      'security_ninja',
				//      'direct_admin_created',
				//      sprintf(__('WARNING: Administrator account created directly in database: %s', 'security-ninja'), $admin->user_login),
				//      array('user_id' => $admin->ID)
				//  );
				// }

				update_option( 'secnin_last_checked_admin_id', $admin->ID );
			}
		}
	}

	/**
	 * Send admin creation notification email
	 *
	 * @param \WP_User|object $user               User object.
	 * @param bool            $is_direct_creation Whether the user was created directly in database.
	 *
	 * @return void
	 */
	private static function send_admin_notification( $user, $is_direct_creation ) {
		$site_name    = esc_html( get_bloginfo( 'name' ) );
		$settings_url = admin_url( 'admin.php?page=wf-sn' );
		$headers      = array( 'Content-Type: text/html; charset=UTF-8' );

		try {
			add_filter( 'wp_mail_content_type', array( __NAMESPACE__ . '\Wf_Sn_El', 'sn_set_html_mail_content_type' ) );

			$is_whitelabel = class_exists( '\WPSecurityNinja\Plugin\Wf_Sn_Wl' ) && 1 === \WPSecurityNinja\Plugin\Wf_Sn_Wl::is_active();

			// Set subject based on creation type and white label status
			if ( $is_direct_creation ) {
				$subject = $is_whitelabel
					? sprintf( /* translators: %s: site name */ esc_html__( '[%s] WARNING: Administrator Created in Database', 'security-ninja' ), $site_name )
					: sprintf( /* translators: %s: site name */ esc_html__( '[%s] Security Ninja - WARNING: Direct Database Creation', 'security-ninja' ), $site_name );
			} else {
				$subject = $is_whitelabel
					? sprintf( /* translators: %s: site name */ esc_html__( '[%s] New Administrator Account Created', 'security-ninja' ), $site_name )
					: sprintf( /* translators: %s: site name */ esc_html__( '[%s] Security Ninja - New Administrator Account', 'security-ninja' ), $site_name );
			}

			// Build the notification table
			$body = sprintf(
				'<table style="width: 100%%; border-collapse: collapse; margin: 20px 0;">
					<tr>
						<td style="padding: 12px; vertical-align: top;"><strong>%s</strong></td>
						<td style="padding: 12px; vertical-align: top;">%s</td>
					</tr>
					<tr style="background-color: #f8f9fa;">
						<td style="padding: 12px; vertical-align: top;"><strong>%s</strong></td>
						<td style="padding: 12px; vertical-align: top;">%s</td>
					</tr>
					<tr>
						<td style="padding: 12px; vertical-align: top;"><strong>%s</strong></td>
						<td style="padding: 12px; vertical-align: top;">%s</td>
					</tr>
					<tr style="background-color: #f8f9fa;">
						<td style="padding: 12px; vertical-align: top;"><strong>%s</strong></td>
						<td style="padding: 12px; vertical-align: top;">%s</td>
					</tr>
				</table>',
				esc_html__( 'Username', 'security-ninja' ),
				esc_html( $user->user_login ),
				esc_html__( 'Email', 'security-ninja' ),
				esc_html( $user->user_email ),
				esc_html__( 'Created By', 'security-ninja' ),
				$is_direct_creation ? esc_html__( 'Direct Database Creation', 'security-ninja' ) : esc_html( wp_get_current_user()->user_login ),
				esc_html__( 'Created On', 'security-ninja' ),
				esc_html(
					$is_direct_creation
						? date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), strtotime( $user->user_registered ) )
						: date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) )
				)
			);

			// Add appropriate header text
			$header_text = $is_direct_creation
				? esc_html__( 'WARNING: An administrator account has been created directly in the database. This could indicate a security breach if you did not create this user manually.', 'security-ninja' )
				: esc_html__( 'A new administrator account has been created on your website.', 'security-ninja' );

			$body = sprintf( '<p>%s</p>%s', $header_text, $body );

			// Add footer with settings link
			$body .= sprintf(
				'<p style="margin-top: 20px; color: #666;">%s</p>',
				sprintf(
					// translators: %1$s: opening link tag, %2$s: closing link tag
					$is_whitelabel
						? esc_html__( 'Notification settings can be adjusted in %1$sWordPress admin%2$s', 'security-ninja' )
						: esc_html__( 'Security Ninja notification settings can be adjusted in %1$sWordPress admin%2$s', 'security-ninja' ),
					'<a href="' . esc_url( $settings_url ) . '" style="color: #0073aa; text-decoration: underline;">',
					'</a>'
				)
			);

			// Ensure proper HTML formatting
			if ( strpos( $body, '<html' ) === false ) {
				$body = sprintf(
					'<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body>%s</body></html>',
					$body
				);
			}

			$sent = wp_mail( self::$options['new_admin_notification_email'], $subject, $body, $headers );

			if ( ! $sent ) {
				wf_sn_el_modules::log_event(
					'security_ninja',
					'new_admin_notification_failed',
					esc_html__( 'Failed to send new admin notification email.', 'security-ninja' ),
					array( 'new_admin' => $user->user_login )
				);
			}
		} catch ( \Exception $e ) {
			wf_sn_el_modules::log_event(
				'security_ninja',
				'new_admin_notification_error',
				esc_html__( 'Error sending new admin notification email', 'security-ninja' ),
				array(
					'error'     => $e->getMessage(),
					'new_admin' => $user->user_login,
				)
			);
		} finally {
			remove_filter( 'wp_mail_content_type', array( __NAMESPACE__ . '\Wf_Sn_El', 'sn_set_html_mail_content_type' ) );
		}
	}

	/**
	 * return_table_name.
	 *
	 * @author  Unknown
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, December 8th, 2023.
	 * @access  public static
	 * @return  mixed
	 */
	public static function return_table_name() {
		global $wpdb;
		return $wpdb->prefix . 'wf_sn_el';
	}



	/**
	 * ajax_get_events_data.
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, October 27th, 2023.
	 * @version v1.0.1  Thursday, October 26th, 2023.
	 * @version v1.0.2  Monday, May 20th, 2024.
	 * @access  public static
	 * @return  mixed
	 */
	public static function ajax_get_events_data() {
		global $wpdb;

		// Verify nonce
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'sn_datatables_nonce' ) ) {
			wp_die( 'Permission denied' );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => 'Error saving dismiss pointer.' ) );
		}

		// Get DataTables parameters
		$draw          = intval( $_POST['draw'] );
		$start         = intval( $_POST['start'] );
		$length        = intval( $_POST['length'] );
		$search        = sanitize_text_field( $_POST['search']['value'] ?? '' );
		$action_filter = sanitize_text_field( $_POST['action_filter'] ?? '' );
		$order         = $_POST['order'] ?? array();

		$table = $wpdb->prefix . 'wf_sn_el';

		// Build the base query with placeholders for user input (WordPress: use prepare() for queries with user data).
		$where_conditions_sql = array();
		$prepare_args         = array();

		if ( ! empty( $search ) ) {
			$like                   = '%' . $wpdb->esc_like( $search ) . '%';
			$where_conditions_sql[] = '(description LIKE %s OR ip LIKE %s OR action LIKE %s OR user_agent LIKE %s)';
			$prepare_args[]         = $like;
			$prepare_args[]         = $like;
			$prepare_args[]         = $like;
			$prepare_args[]         = $like;
		}

		if ( ! empty( $action_filter ) ) {
			$where_conditions_sql[] = 'action = %s';
			$prepare_args[]         = $action_filter;
		}

		$base_query = 'SELECT id, timestamp, ip, user_agent, user_id, action, raw_data, description FROM ' . $table;
		if ( ! empty( $where_conditions_sql ) ) {
			$base_query .= ' WHERE ' . implode( ' AND ', $where_conditions_sql );
		}

		// Get the total number of records before filtering
		$total_records = $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $table );

		// Get the total number of records after filtering
		if ( ! empty( $prepare_args ) ) {
			$count_query    = 'SELECT COUNT(*) FROM (' . $base_query . ') AS filtered_table';
			$total_filtered = $wpdb->get_var( $wpdb->prepare( $count_query, $prepare_args ) );
		} else {
			$total_filtered = $wpdb->get_var( 'SELECT COUNT(*) FROM ' . $table );
		}

		// Handle sorting (column index and direction are validated; no user string in SQL)
		$columns  = array( 'timestamp', 'description', 'ip', 'user_agent', 'user_id', 'action' );
		$order_by = ' ORDER BY timestamp DESC';
		if ( ! empty( $order ) ) {
			$order_by = ' ORDER BY ';
			foreach ( $order as $o ) {
				$col_index = intval( $o['column'] );
				if ( $col_index < 0 || $col_index >= count( $columns ) ) {
					continue;
				}
				$col_dir   = ( isset( $o['dir'] ) && $o['dir'] === 'asc' ) ? 'ASC' : 'DESC';
				$order_by .= $columns[ $col_index ] . ' ' . $col_dir . ', ';
			}
			$order_by = rtrim( $order_by, ', ' );
			if ( $order_by === ' ORDER BY ' ) {
				$order_by = ' ORDER BY timestamp DESC';
			}
		}

		$data_query = $base_query . $order_by;

		// Add pagination and execute with prepare() when we have LIMIT
		if ( $length != -1 ) {
			$data_query       .= ' LIMIT %d, %d';
			$data_prepare_args = array_merge( $prepare_args, array( $start, $length ) );
			$events            = $wpdb->get_results( $wpdb->prepare( $data_query, $data_prepare_args ) );
		} elseif ( ! empty( $prepare_args ) ) {
				$events = $wpdb->get_results( $wpdb->prepare( $data_query, $prepare_args ) );
		} else {
			$events = $wpdb->get_results( $data_query );
		}
		$data = array();

		$current_time = current_time( 'timestamp' );
		// Process each event for output
		foreach ( $events as $event ) {
			$user         = ( $event->user_id && $event->user_id !== '0' ) ? get_userdata( $event->user_id ) : null;
			$user_details = '';

			if ( $user instanceof \WP_User ) {
				$user_details = esc_html( $user->user_nicename ) . '<br><small>';
			}

			// Geolocate IP (premium feature)
			$geolocate_ip = false;
			if ( secnin_fs()->can_use_premium_code__premium_only() ) {
				// Ensure the geolocation class is loaded
				if ( ! class_exists( __NAMESPACE__ . '\\SN_Geolocation' ) ) {
					include_once WF_SN_PLUGIN_DIR . 'modules/cloud-firewall/class-sn-geolocation.php';
				}

				if ( class_exists( __NAMESPACE__ . '\\SN_Geolocation' ) ) {
					$geolocate_ip = \WPSecurityNinja\Plugin\SN_Geolocation::geolocate_ip( $event->ip, true );
					if ( $geolocate_ip && $geolocate_ip['country'] !== '-' ) {
						$country_code = $geolocate_ip['country'];

						$country_img_url = \WPSecurityNinja\Plugin\Utils::get_country_img__premium_only( $country_code );
						if ( $country_img_url ) {
							$geoip_countrylist = \WPSecurityNinja\Plugin\Utils::get_country_list();
							$country_name      = $geoip_countrylist[ $country_code ] ?? 'Unknown';
							$country_img_html = '<img src="' . esc_url( $country_img_url ) . '" width="20" height="20" class="countryimg" title="' . esc_html( $country_name ) . '"> ';
							$user_details    .= $country_img_html;
						}
					}
				}
			}
			$user_details .= esc_html( $event->ip ) . '</small>';

			// Prepare details output
			$raw_data = maybe_unserialize( $event->raw_data );

			// Initialize the details output
			$details_output = '';

			if ( ! empty( $raw_data ) ) {
				$details_output  = '<button class="button button-small button-secondary">' . __( 'Details', 'security-ninja' ) . '</button>';
				$details_output .= '<div class="details-content" style="display:none;"><dl class="rowdetails">';

				if ( is_array( $raw_data ) ) {
					foreach ( $raw_data as $key => $value ) {
						// Check if the value is a WP_Error object
						if ( is_wp_error( $value ) ) {
							// Handle the error, for example, display the error message
							$details_output .= '<dt>' . esc_html( $key ) . '</dt><dd>' . esc_html( $value->get_error_message() ) . '</dd>';
						} elseif ( is_object( $value ) ) {
							// Handle the object, for example, display the class name
							$details_output .= '<dt>' . esc_html( $key ) . '</dt><dd>' . esc_html( get_class( $value ) ) . '</dd>';
						} elseif ( is_array( $value ) ) {
							// Handle array values
							$details_output .= '<dt>' . esc_html( $key ) . '</dt><dd>';
							foreach ( $value as $sub_key => $sub_value ) {
								if ( is_scalar( $sub_value ) ) {
									$details_output .= esc_html( $sub_key ) . ': ' . esc_html( $sub_value ) . '<br>';
								} else {
									$details_output .= esc_html( $sub_key ) . ': ' . esc_html( gettype( $sub_value ) ) . '<br>';
								}
							}
							$details_output .= '</dd>';
						} else {
							// Process normally if it's not an error, object, or array
							$details_output .= '<dt>' . esc_html( $key ) . '</dt><dd>' . esc_html( $value ) . '</dd>';
						}
					}
				} else {
					// If $raw_data is not an array, check if it is a WP_Error
					if ( is_wp_error( $raw_data ) ) {
						$details_output .= '<dd>' . esc_html( $raw_data->get_error_message() ) . '</dd>';
					} elseif ( is_object( $raw_data ) ) {
						// Handle the object, for example, display the class name
						$details_output .= '<dd>' . esc_html( get_class( $raw_data ) ) . '</dd>';
					} else {
						$details_output .= '<dd>' . esc_html( $raw_data ) . '</dd>';
					}
				}

				$details_output .= '</dl></div>';
			}

			$timestamp_unix = strtotime( $event->timestamp );

			// Calculate the time since
			$time_since = human_time_diff( $timestamp_unix, $current_time ) . ' ' . __( 'ago', 'security-ninja' );

			// Format the original timestamp
			$formatted_timestamp = date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $timestamp_unix );

			// Concatenate the time since and the formatted timestamp
			$timestamp_details = esc_html( $time_since ) . '<br><small>' . esc_html( $formatted_timestamp ) . '</small>';

			$data[] = array(
				'timestamp'   => $timestamp_details,
				'user_id'     => $user_details,
				'action'      => esc_html( $event->action ),
				'description' => esc_html( $event->description ),
				'details'     => $details_output,
			);
		}

		// Return JSON response
		$response = array(
			'draw'            => $draw,
			'recordsTotal'    => $total_records,
			'recordsFiltered' => $total_filtered,
			'data'            => $data,
		);
		wp_send_json( $response );
		wp_die();
	}

	/**
	 * Get unique actions for the filter dropdown
	 *
	 * @author  Lars Koudal
	 * @since   v1.0.0
	 * @version v1.0.0  Monday, December 9th, 2024.
	 * @access  public static
	 * @return  mixed
	 */
	public static function ajax_get_events_actions() {
		global $wpdb;

		// Verify nonce
		if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'sn_datatables_nonce' ) ) {
			wp_die( 'Permission denied' );
		}

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission denied.', 'security-ninja' ) ) );
		}

		// Get unique actions from the database
		$actions = $wpdb->get_col( 'SELECT DISTINCT action FROM ' . $wpdb->prefix . 'wf_sn_el ORDER BY action ASC' );

		wp_send_json_success( array( 'actions' => $actions ) );
		wp_die();
	}





	/**
	 * Send a webhook event.
	 *
	 * @since   v0.0.1
	 * @version v1.0.1  Thursday, October 5th, 2023.
	 * @access  public static
	 * @param   string $event The event name.
	 * @param   array  $data  The event data.
	 * @return  bool          True on success, false on failure.
	 */
	public static function send_webhook_event__premium_only( $event, $data ) {
		if ( empty( $event ) || ! is_string( $event ) || empty( $data ) || ! is_array( $data ) ) {
			return false;
		}

		$options = get_option( 'wf_sn_el' );

		if (
			! isset( $options['webhook_active'] ) || intval( $options['webhook_active'] ) !== 1 ||
			empty( $options['webhook_url'] ) || ! filter_var( $options['webhook_url'], FILTER_VALIDATE_URL )
		) {
			return false;
		}

		if ( empty( $options[ $event ] ) || intval( $options[ $event ] ) !== 1 ) {
			return false;
		}

		$data = array_merge(
			$data,
			array(
				'event'          => sanitize_text_field( $event ),
				'source'         => site_url(),
				'plugin_version' => \WPSecurityNinja\Plugin\Utils::get_plugin_version(),
				'webhook_url'    => esc_url( $options['webhook_url'] ),
			)
		);

		$response = wp_remote_post(
			$options['webhook_url'],
			array(
				'body'    => wp_json_encode( $data ),
				'headers' => array( 'Content-Type' => 'application/json' ),
				'timeout' => 15,
			)
		);

		if ( is_wp_error( $response ) ) {
			wf_sn_el_modules::log_event(
				'security_ninja',
				'webhook_event',
				esc_html__( 'Webhook request failed', 'security-ninja' ),
				array( 'error' => $response->get_error_message() )
			);
			return false;
		}

		wf_sn_el_modules::log_event(
			'security_ninja',
			'webhook_event',
			sprintf(
				// translators: %s: event name
				esc_html__( 'Webhook event sent - %s', 'security-ninja' ),
				esc_attr( $event )
			)
		);
		return true;
	}




	/**
	 * Is the event logger enabled
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @return  mixed
	 */
	public static function is_active() {
		if ( self::$is_active !== null ) {
			return self::$is_active;
		}

		if ( ! self::$options ) {
			self::$options = get_option( 'wf_sn_el' );
		}

		if ( isset( self::$options['active'] ) ) {
			self::$is_active = (bool) self::$options['active'];
		} else {
			self::$is_active = false;
		}

		return self::$is_active;
	}

	/**
	 * enqueue CSS and JS scripts on plugin's admin page
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @return  void
	 */
	public static function enqueue_scripts() {
		if ( ! Wf_Sn::is_plugin_page() ) {
			return;
		}

		$plugin_url = plugin_dir_url( __FILE__ );

		$datatables_nonce = wp_create_nonce( 'sn_datatables_nonce' );
		wp_enqueue_script( 'sn-el-datatables', $plugin_url . 'js/jquery.dataTables.min.js', array( 'jquery' ), wf_sn::$version, true );
		wp_localize_script(
			'sn-el-datatables',
			'datatables_object',
			array(
				'nonce' => $datatables_nonce,
			)
		);

		wp_enqueue_style( 'sn-el-datatables', $plugin_url . 'css/jquery.dataTables.min.css', array(), wf_sn::$version );

		$js_vars = array(
			'nonce' => wp_create_nonce( 'wf_sn_el' ),
		);

		wp_register_script( 'sn-el', $plugin_url . 'js/wf-sn-el.js', array( 'jquery', 'sn-el-datatables' ), wf_sn::$version, true );
		wp_localize_script( 'sn-el', 'wf_sn_el', $js_vars );
		wp_enqueue_script( 'sn-el' );

		wp_enqueue_style( 'sn-el', $plugin_url . 'css/wf-sn-el.css', array(), wf_sn::$version );
	}

	/**
	 * add new tab
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @param   mixed   $tabs
	 * @return  mixed
	 */
	public static function sn_tabs( $tabs ) {
		$logger_tab = array(
			'id'       => 'sn_logger',
			'class'    => '',
			'label'    => esc_html__( 'Events', 'security-ninja' ),
			'callback' => array( __NAMESPACE__ . '\\wf_sn_el', 'logger_page' ),
		);
		$done       = false;
		$tab_count  = count( $tabs );

		for ( $i = 0; $i < $tab_count; $i++ ) {
			if ( $tabs[ $i ]['id'] === 'sn_logger' ) {
				$tabs[ $i ] = $logger_tab;
				$done       = true;
				break;
			}
		}

		if ( ! $done ) {
			$tabs[] = $logger_tab;
		}

		return $tabs;
	}


	/**
	 * Baseline Events Logger options (wizard and first-time defaults).
	 *
	 * @since  5.289
	 * @access public static
	 * @return array<string, mixed>
	 */
	public static function get_baseline_options() {
		$options = array(
			'active'                       => 1,
			'email_reports'                => '',
			'email_modules'                => array(
				'users',
				'menus',
				'file_editor',
				'taxonomies',
				'media',
				'posts',
				'widgets',
				'installer',
				'comments',
				'settings',
				'security_ninja',
				'woocommerce',
			),
			'email_to'                     => get_option( 'admin_email' ),
			'retention'                    => 'day-7',
			'remove_settings_deactivate'   => 0,
			'notify_new_admin'             => 0,
			'new_admin_notification_email' => get_option( 'admin_email' ),
		);

		if ( function_exists( 'secnin_fs' ) && is_object( secnin_fs() ) ) {
			if ( secnin_fs()->can_use_premium_code__premium_only() ) {
				$options['webhook_active']          = 0;
				$options['webhook_url']             = '';
				$options['webhook_firewall_events'] = 0;
				$options['webhook_user_logins']     = 0;
				$options['webhook_updates']         = 0;
			}
		}

		return $options;
	}

	/**
	 * Set default options.
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @param   boolean $force  Default: false
	 * @return  void
	 */
	public static function default_settings( $force = true ) {
		$options = self::get_baseline_options();

		if ( $force ) {
			update_option( 'wf_sn_el', $options );
		} else {
			$existing = get_option( 'wf_sn_el', array() );
			if ( is_array( $existing ) && ! empty( $existing ) ) {
				$merged = array_merge( $options, $existing );
				update_option( 'wf_sn_el', $merged );
			} else {
				add_option( 'wf_sn_el', $options, '', false );
			}
		}
	}



	/**
	 * sanitize settings on save
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @version v1.0.1  Monday, November 13th, 2023.
	 * @version v1.0.2  Thursday, February 22nd, 2024.
	 * @access  public static
	 * @param   mixed   $values
	 * @return  mixed
	 */
	public static function sanitize_settings( $values ) {
		// Handle null or non-array values (WordPress may call this with null)
		if ( ! is_array( $values ) ) {
			// Return existing options normalized
			$old_options = get_option( 'wf_sn_el', array() );
			if ( ! is_array( $old_options ) ) {
				$old_options = array();
			}
			// Normalize existing boolean values
			$boolean_keys = array(
				'active',
				'notify_new_admin',
			);
			if ( function_exists( 'secnin_fs' ) && is_object( secnin_fs() ) ) {
				if ( secnin_fs()->can_use_premium_code__premium_only() ) {
					$boolean_keys = array_merge(
						$boolean_keys,
						array( 'webhook_firewall_events', 'webhook_user_logins', 'webhook_updates', 'webhook_active' )
					);
				}
			}
			foreach ( $boolean_keys as $key ) {
				if ( isset( $old_options[ $key ] ) ) {
					$old_options[ $key ] = \WPSecurityNinja\Plugin\Utils::normalize_flag( $old_options[ $key ] );
				}
			}
			return $old_options;
		}

		$old_options = get_option( 'wf_sn_el', array() );
		if ( ! is_array( $old_options ) ) {
			$old_options = array();
		}
		$new_options = $old_options;

		// Add to boolean_keys array
		$boolean_keys = array(
			'active',
			'notify_new_admin',
		);
		if ( function_exists( 'secnin_fs' ) && is_object( secnin_fs() ) ) {
			if ( secnin_fs()->can_use_premium_code__premium_only() ) {
				$boolean_keys = array_merge(
					$boolean_keys,
					array( 'webhook_firewall_events', 'webhook_user_logins', 'webhook_updates', 'webhook_active' )
				);
			}
		}

		// Ensure all boolean keys are normalized to 0/1, defaulting to 0 if not present
		foreach ( $boolean_keys as $key ) {
			if ( isset( $values[ $key ] ) ) {
				$new_options[ $key ] = \WPSecurityNinja\Plugin\Utils::normalize_flag( $values[ $key ] );
			} else {
				// Preserve existing value if not in form submission
				$new_options[ $key ] = isset( $old_options[ $key ] ) ? \WPSecurityNinja\Plugin\Utils::normalize_flag( $old_options[ $key ] ) : 0;
			}
		}

		// Handle all other keys with specific data types or requirements
		foreach ( $values as $key => $value ) {
			switch ( $key ) {
				case 'retention':
				case 'email_reports':
				case 'email_to':
				case 'remove_settings_deactivate':
				case 'new_admin_notification_email':
					// Sanitize text fields
					$new_options[ $key ] = sanitize_text_field( $value );
					break;

				case 'email_modules':
					// Ensure array values are sanitized
					if ( is_array( $value ) ) {
						$new_options[ $key ] = array_map( 'sanitize_text_field', $value );
					}
					break;
			}
		}

		if ( function_exists( 'secnin_fs' ) && is_object( secnin_fs() ) ) {
			if ( secnin_fs()->can_use_premium_code__premium_only() ) {
				if ( isset( $values['webhook_url'] ) ) {
					$new_options['webhook_url'] = sanitize_text_field( $values['webhook_url'] );
				}
				if ( isset( $values['webhook_events'] ) && is_array( $values['webhook_events'] ) ) {
					$new_options['webhook_events'] = array_map( 'sanitize_text_field', $values['webhook_events'] );
				}
			}
		}

		// Optional: Check and initialize missing fields if necessary
		$new_options['email_modules'] = $new_options['email_modules'] ?? array();

		return $new_options;
	}





	/**
	 * all settings are saved in one option key
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @return  void
	 */
	public static function register_settings() {
		register_setting( 'wf_sn_el', 'wf_sn_el', array( __NAMESPACE__ . '\\wf_sn_el', 'sanitize_settings' ) );
	}



	/**
	 * process selected actions / filters
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @return  void
	 */
	public static function watch_actions() {
		$current_action = current_action();

		// Hard skip translation hooks - they are extremely noisy and can cause recursion and memory issues
		// when other plugins (e.g., debug tools) render translated output on shutdown.
		if ( empty( $current_action ) || 0 === strpos( $current_action, 'gettext' ) ) {
			return;
		}

		// Prevent infinite recursion
		if ( self::$watching_actions ) {
			return;
		}

		// Set flag to prevent recursive calls
		self::$watching_actions = true;

		try {
			// Skip low-level WordPress hooks that can cause recursion during query parsing
			$skip_hooks = array( 'sanitize_key', 'parse_query', 'pre_get_posts' );
			if ( in_array( $current_action, $skip_hooks, true ) ) {
				return;
			}

			// Define audited hooks once per request (this function runs on the global "all" hook).
			static $login_actions     = null;
			static $security_ninja    = null;
			static $users             = null;
			static $menus             = null;
			static $file_editor       = null;
			static $taxonomies        = null;
			static $media             = null;
			static $posts             = null;
			static $widgets           = null;
			static $installer         = null;
			static $comments          = null;
			static $settings          = null;
			static $woocommerce       = null;
			static $premium_hooks_all = null;
			static $module_hooks      = null;

			// Resolve enabled modules once per request; empty means \"all enabled\" for backward compatibility.
			$enabled_modules = array();
			if ( isset( self::$options['email_modules'] ) && is_array( self::$options['email_modules'] ) ) {
				$enabled_modules = self::$options['email_modules'];
			}

			if ( is_null( $login_actions ) ) {
				$login_actions = array(
					'wp_login_failed',  // Failed login attempts (basic security logging)
				);

				$security_ninja = array(
					'security_ninja_done_testing',
					'security_ninja_scheduled_scanner_done_cron',
					'security_ninja_core_scanner_done_scanning',
					'security_ninja_remote_access',
					'security_ninja_malware_scanner_done_scanning',
				);

				// Premium version: actions that can be audited for premium users.
				$users       = array(
					'user_register',
					'wp_login_failed',
					'profile_update',
					'password_reset',
					'retrieve_password',
					'set_logged_in_cookie',
					'clear_auth_cookie',
					'delete_user',
					'deleted_user',
					'set_user_role',
					'add_user_role',
					'remove_user_role',
				);
				$menus       = array(
					'wp_create_nav_menu',
					'wp_update_nav_menu',
					'delete_nav_menu',
				);
				$file_editor = array( 'wp_redirect' );
				$taxonomies  = array(
					'created_term',
					'delete_term',
				);
				$media       = array(
					'add_attachment',
					'edit_attachment',
					'delete_attachment',
					'wp_save_image_editor_file',
				);
				$posts       = array(
					'deleted_post',           // When a post is deleted
					'publish_post',           // When a post is published
					'trash_post',             // When a post is moved to trash
					'untrash_post',           // When a post is restored from trash
				);
				$widgets     = array(
					'update_option_sidebars_widgets',
				);
				$installer   = array(
					'upgrader_process_complete',
					'switch_theme',
					'_core_updated_successfully',
					'activate_plugin',
					'activated_plugin',
					'deactivate_plugin',
					'deactivated_plugin',
				);
				$comments    = array(
					'comment_flood_trigger',
					'wp_insert_comment',
					'edit_comment',
					'delete_comment',
					'trash_comment',
					'untrash_comment',
					'spam_comment',
					'unspam_comment',
					'transition_comment_status',
					'comment_duplicate_trigger',
				);
				$settings    = array(
					'update_site_option',
					'update_option_permalink_structure',
					'update_option_category_base',
					'update_option_tag_base',
				);

				$woocommerce = array(
					// Product actions
					'woocommerce_update_product',
					'woocommerce_new_product_data',
					'woocommerce_product_duplicate',
					'woocommerce_update_product_variation',
					'woocommerce_delete_product',

					// Customer actions
					'woocommerce_new_customer',             // New customer added
					'woocommerce_delete_customer',          // Customer deleted
					'woocommerce_customer_reset_password',  // Customer reset password

					// Order actions
					'woocommerce_new_order',                // New order created
					'woocommerce_delete_order',             // Order deleted
					'woocommerce_order_status_changed',     // Order status changed
					'woocommerce_order_refunded',           // Order refunded

					// Coupon actions
					'woocommerce_delete_coupon',            // Coupon deleted
					'woocommerce_coupon_updated',           // Coupon updated
					'woocommerce_coupon_created',           // Coupon created
				);

				$premium_hooks_all = array_unique(
					array_merge(
						$users,
						$menus,
						$file_editor,
						$taxonomies,
						$media,
						$posts,
						$widgets,
						$installer,
						$comments,
						$settings,
						$woocommerce
					)
				);

				// Map hooks to their logical modules for fast module-based filtering.
				$module_hooks = array(
					'users'          => $users,
					'menus'          => $menus,
					'file_editor'    => $file_editor,
					'taxonomies'     => $taxonomies,
					'media'          => $media,
					'posts'          => $posts,
					'widgets'        => $widgets,
					'installer'      => $installer,
					'comments'       => $comments,
					'settings'       => $settings,
					'security_ninja' => $security_ninja,
					'woocommerce'    => $woocommerce,
				);
			}

			// Bail early if this hook isn't one we audit (prevents calling Freemius on every hook).
			if (
				! in_array( $current_action, $login_actions, true ) &&
				! in_array( $current_action, $security_ninja, true ) &&
				! in_array( $current_action, $premium_hooks_all, true )
			) {
				return;
			}

			// Only fetch args if we're going to log something.
			$args = func_get_args();

			// Free version: Check login actions and Security Ninja actions first
			if ( in_array( $current_action, $login_actions, true ) ) {
				wf_sn_el_modules::parse_action_users( $current_action, $args );
				return; // Exit early if we handled it
			} elseif ( in_array( $current_action, $security_ninja, true ) ) {
				wf_sn_el_modules::parse_action_security_ninja( $current_action, $args );
				return; // Exit early if we handled it
			}

			// Premium hooks: dispatch to parsers (no premium check before DB write; this module only loads in premium).
			if ( in_array( $current_action, $premium_hooks_all, true ) ) {
				// If specific modules are configured, skip logging for disabled modules.
				if ( ! empty( $enabled_modules ) ) {
					$current_module = null;
					foreach ( $module_hooks as $module_key => $hooks ) {
						if ( in_array( $current_action, $hooks, true ) ) {
							$current_module = $module_key;
							break;
						}
					}
					if ( $current_module && ! in_array( $current_module, $enabled_modules, true ) ) {
						return;
					}
				}

				if ( in_array( $current_action, $users, true ) ) {
					wf_sn_el_modules::parse_action_users( $current_action, $args );
				} elseif ( in_array( $current_action, $menus, true ) ) {
					wf_sn_el_modules::parse_action_menus( $current_action, $args );
				} elseif ( in_array( $current_action, $file_editor, true ) ) {
					wf_sn_el_modules::parse_action_file_editor( $current_action, $args );
				} elseif ( in_array( $current_action, $taxonomies, true ) ) {
					wf_sn_el_modules::parse_action_taxonomies( $current_action, $args );
				} elseif ( in_array( $current_action, $media, true ) ) {
					wf_sn_el_modules::parse_action_media( $current_action, $args );
				} elseif ( in_array( $current_action, $posts, true ) ) {
					wf_sn_el_modules::parse_action_posts( $current_action, $args );
				} elseif ( in_array( $current_action, $widgets, true ) ) {
					wf_sn_el_modules::parse_action_widgets( $current_action, $args );
				} elseif ( in_array( $current_action, $installer, true ) ) {
					wf_sn_el_modules::parse_action_installer( $current_action, $args );
				} elseif ( in_array( $current_action, $comments, true ) ) {
					wf_sn_el_modules::parse_action_comments( $current_action, $args );
				} elseif ( in_array( $current_action, $settings, true ) ) {
					wf_sn_el_modules::parse_action_settings( $current_action, $args );
				} elseif ( in_array( $current_action, $woocommerce, true ) ) {
					wf_sn_el_modules::parse_action_woocommerce( $current_action, $args );
				}
			}
		} finally {
			// Always reset the flag, even if an exception occurs
			self::$watching_actions = false;
		}
	}





	/**
	 * truncate event log table
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @return  void
	 */
	public static function ajax_truncate_log() {
		global $wpdb;

		check_ajax_referer( 'wf_sn_el' );

		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error(
				array(
					'message' => __( 'Failed.', 'security-ninja' ),
				)
			);
		}
		$options = get_option( 'wf_sn_el' );

		$options['last_reported_event'] = 0;
		update_option( 'wf_sn_el', $options, false );

		$wpdb->query( 'TRUNCATE TABLE ' . $wpdb->prefix . 'wf_sn_el' );

		wp_send_json_success(
			array(
				'message' => __( 'Emptied the log.', 'security-ninja' ),
			)
		);

		exit();
	}








	/**
	 * prune events log table
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @version v1.0.1  Tuesday, October 24th, 2023.
	 * @version v1.0.2  Monday, November 13th, 2023.
	 * @access  public static
	 * @return  void
	 */
	public static function do_cron_prune_logs() {
		global $wpdb;
		if ( empty( self::$options['retention'] ) ) {
			return false;
		}

		// Define the list of protected actions
		$protected_actions = array(
			'login_form_blocked_ip',
			'blockadminlogin',
			'blacklisted_IP',
			'blocked_ip_banned',
			'blocked_ip_suspicious_request',
			'blocked_ip_country_ban',
			'login_denied_banned_IP',
			'firewall_ip_banned',
		);

		// Prepare placeholders for protected actions
		$placeholders = implode( ', ', array_fill( 0, count( $protected_actions ), '%s' ) );

		// Prepare the base query with placeholders for dynamic values
		$base_query = "DELETE FROM {$wpdb->prefix}wf_sn_el WHERE (action NOT IN ($placeholders) OR (action IN ($placeholders) AND timestamp < DATE_SUB(NOW(), INTERVAL 2 YEAR)))";

		// Determine retention strategy
		$tmp             = explode( '-', self::$options['retention'] );
		$retention_value = (int) $tmp[1];

		if ( 'cnt' === $tmp[0] ) {
			$id = $wpdb->get_var( $wpdb->prepare( "SELECT id FROM {$wpdb->prefix}wf_sn_el ORDER BY id DESC LIMIT %d, 1", $retention_value ) );
			if ( $id ) {
				$query = $wpdb->prepare( $base_query . ' AND id < %d', array_merge( $protected_actions, $protected_actions, array( $id ) ) );
				$wpdb->query( $query );
			}
		} else {
			$query = $wpdb->prepare( $base_query . ' AND timestamp < DATE_SUB(NOW(), INTERVAL %d DAY)', array_merge( $protected_actions, $protected_actions, array( $retention_value ) ) );
			$wpdb->query( $query );
		}

		$deleted_rows = $wpdb->rows_affected;
		if ( $deleted_rows > 0 ) {
			wf_sn_el_modules::log_event(
				'security_ninja',
				'prune_events_log',
				sprintf(
					// translators: %d: number of deleted rows
					esc_html__( 'Cron job: Emptied event logs. Deleted rows: %d', 'security-ninja' ),
					$deleted_rows
				),
				array( 'Deleted rows' => $deleted_rows )
			);
		}

		return true;
	}


	/**
	 * send email reports based on user's preferences
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @version v1.0.1  Friday, March 3rd, 2023.
	 * @access  public static
	 * @param   mixed   $last_id
	 * @return  void
	 */
	public static function send_email_reports( $last_id ) {
		global $wpdb;

		$body = '';

		if ( ! isset( self::$options ) || ! is_array( self::$options ) || ! isset( self::$options['email_reports'] ) || ! self::$options['email_reports'] || ! $last_id ) {
			return false;
		}

		if ( isset( self::$options['last_reported_event'] ) && ( $last_id - self::$options['last_reported_event'] >= (int) self::$options['email_reports'] ) ) {
			$modules = '';

			if ( self::$options['email_modules'] ) {
				$modules = " and module IN('" . implode( "', '", self::$options['email_modules'] ) . "') ";
			}

			$events = $wpdb->get_results( 'SELECT * FROM ' . $wpdb->prefix . 'wf_sn_el WHERE id > ' . self::$options['last_reported_event'] . $modules . ' ORDER BY id DESC LIMIT ' . self::$options['email_reports'] );

			if ( ! $events || count( $events ) < (int) self::$options['email_reports'] ) {
				return;
			}

			self::$options['last_reported_event'] = $events[0]->id;
			update_option( 'wf_sn_el', self::$options, false );

			$admin_url = admin_url( 'admin.php?page=wf-sn#sn_logger' );
			// if ($admin_url = SecNin_Rename_WP_Login::new_login_slug()) {
			//  $admin_url = trailingslashit(site_url( $admin_url)) . 'admin.php?page=wf-sn#sn_logger';
			// }

			$headers = array( 'Content-Type: text/html; charset=UTF-8' );

			$body .= sprintf(
				// translators: %1$s: site name, %2$s: opening link tag, %3$s: closing link tag, %4$s: line break
				__( 'Recent events on %1$s: %2$s(more details are available in WordPress admin)%3$s%4$s', 'security-ninja' ),
				esc_html( get_bloginfo( 'name' ) ),
				'<a href="' . esc_url( $admin_url ) . '">',
				'</a>',
				'<br>'
			);

			// Add email-friendly responsive table styles
			$body .= '
			<table style="width: 100%; border-collapse: collapse; margin: 20px 0;">
				<thead>
					<tr style="background-color: #f8f9fa;">
						<th style="padding: 12px; text-align: left; border-bottom: 2px solid #dee2e6;">' .
				esc_html__( 'Date & Time', 'security-ninja' ) .
				'</th>
						<th style="padding: 12px; text-align: left; border-bottom: 2px solid #dee2e6;">' .
				esc_html__( 'Event Details', 'security-ninja' ) .
				'</th>
					</tr>
				</thead>
				<tbody>';

			foreach ( $events as $event ) {
				$user = '';
				if ( $event->user_id ) {
					$user_info = get_userdata( $event->user_id );
					if ( $user_info ) {
						$user  = '<strong>' . esc_html( $user_info->user_nicename ) . '</strong>';
						$user .= ' (' . esc_html( implode( ', ', $user_info->roles ) ) . ')';
					} else {
						$user = '<strong>' . __( 'user deleted', 'security-ninja' ) . '</strong>';
					}
				} elseif ( substr( $event->user_agent, 0, 10 ) === 'WordPress/' ) {
					$user = '<strong>' . __( 'WP cron', 'security-ninja' ) . '</strong>';
				} else {
					$user = '<strong>' . __( 'Anonymous user', 'security-ninja' ) . '</strong>';
				}

				if ( '' !== $event->ip ) {
					$user .= ' (' . esc_html( $event->ip ) . ')';
				}

				$module = str_replace( array( '_', '-', 'ninja' ), array( ' ', ' ', 'Ninja' ), ucfirst( $event->module ) );

				// Format the timestamp according to WP settings
				$timestamp = sprintf(
					'%s<br><span style="color: #666; font-size: 0.9em;">%s</span>',
					esc_html( date_i18n( get_option( 'date_format' ), strtotime( $event->timestamp ) ) ),
					esc_html( date_i18n( get_option( 'time_format' ), strtotime( $event->timestamp ) ) )
				);

				// Format the event details
				$event_details = sprintf(
					// translators: 1: Event description, 2: User name, 3: Module name
					__( '%1$s by %2$s in %3$s module.', 'security-ninja' ),
					esc_html( $event->description ),
					$user, // already escaped
					esc_html( $module )
				);

				$body .= sprintf(
					'<tr style="border-bottom: 1px solid #dee2e6;">
						<td style="padding: 12px; vertical-align: top; min-width: 140px;">%s</td>
						<td style="padding: 12px; vertical-align: top;">%s</td>
					</tr>',
					$timestamp,
					$event_details
				);
			}

			$body .= '</tbody></table>';

			$body .= sprintf(
				'<p style="margin-top: 20px; color: #666;">' .
					// translators: %1$s: opening link tag, %2$s: closing link tag
					__( 'Events Logger email report settings can be adjusted in %1$sWordPress admin%2$s', 'security-ninja' ) . '</p>',
				'<a href="' . esc_url( $admin_url ) . '" style="color: #0073aa; text-decoration: underline;">',
				'</a>'
			);

			$emreps = (array) explode( ',', self::$options['email_to'] );
			foreach ( $emreps as $emrep ) {
				$emrep = trim( $emrep );
				if ( ! empty( $emrep ) && is_email( $emrep ) ) {

					try {
						add_filter( 'wp_mail_content_type', array( __NAMESPACE__ . '\Wf_Sn_El', 'sn_set_html_mail_content_type' ) );

						$subject = sprintf(
							esc_html__( '[%s] Security Ninja - Events Logger report', 'security-ninja' ),
							wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES )
						);

						// Ensure body is properly formatted as HTML
						if ( strpos( $body, '<html' ) === false ) {
							$body = sprintf(
								'<!DOCTYPE html><html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /></head><body>%s</body></html>',
								$body
							);
						}

						// Send email
						$sendrep = wp_mail( $emrep, $subject, $body, $headers );

						if ( ! $sendrep ) {
							wf_sn_el_modules::log_event(
								'security_ninja',
								'send_email_update',
								esc_html__( 'Email could not be sent.', 'security-ninja' ),
								array( 'recipient' => $emrep )
							);
						} else {
							wf_sn_el_modules::log_event(
								'security_ninja',
								'send_email_update',
								esc_html__( 'Email update sent', 'security-ninja' ),
								array( 'recipient' => $emrep )
							);
						}
					} catch ( \Exception $e ) {
						// Log the error
						wf_sn_el_modules::log_event(
							'security_ninja',
							'send_email_error',
							esc_html__( 'Email error occurred', 'security-ninja' ),
							array(
								'error'     => $e->getMessage(),
								'recipient' => $emrep,
							)
						);
					} finally {
						// Always remove the filter, even if an error occurred
						remove_filter( 'wp_mail_content_type', array( __NAMESPACE__ . '\Wf_Sn_El', 'sn_set_html_mail_content_type' ) );
					}
				} else {
					wf_sn_el_modules::log_event( 'security_ninja', 'send_email_update', __( 'Invalid email address.', 'security-ninja' ), array( 'recipient' => $emrep ) );
				}
			}
		}
	}



	/**
	 * sn_set_html_mail_content_type.
	 *
	 * @author  Unknown
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, November 8th, 2024.
	 * @access  public static
	 * @return  mixed
	 */
	public static function sn_set_html_mail_content_type() {
		return 'text/html';
	}

	/**
	 * display results
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @return  void
	 */
	public static function logger_page() {
		global $wpdb;
		$current_user = wp_get_current_user();

		$email_reports_settings = array(
			''     => __( 'Do not email reports', 'security-ninja' ),
			'10'   => __( 'Email report after 10 events', 'security-ninja' ),
			'25'   => __( 'Email report after 25 events', 'security-ninja' ),
			'50'   => __( 'Email report after 50 events', 'security-ninja' ),
			'100'  => __( 'Email report after 100 events', 'security-ninja' ),
			'250'  => __( 'Email report after 250 events', 'security-ninja' ),
			'500'  => __( 'Email report after 500 events', 'security-ninja' ),
			'1000' => __( 'Email report after 1000 events', 'security-ninja' ),
		);

		$retention_settings = array(
			'day-1'         => __( 'Keep logs for 1 day', 'security-ninja' ),
			'day-7'         => __( 'Keep logs for 7 days', 'security-ninja' ),
			'day-30'        => __( 'Keep logs for 30 days', 'security-ninja' ),
			'day-60'        => __( 'Keep logs for 60 days', 'security-ninja' ),
			'day-90'        => __( 'Keep logs for 90 days', 'security-ninja' ),
			'day-180'       => __( 'Keep logs for 180 days', 'security-ninja' ),
			'day-365'       => __( 'Keep logs for 365 days', 'security-ninja' ),
			'records-100'   => __( 'Keep last 100 records', 'security-ninja' ),
			'records-250'   => __( 'Keep last 250 records', 'security-ninja' ),
			'records-500'   => __( 'Keep last 500 records', 'security-ninja' ),
			'records-1000'  => __( 'Keep last 1000 records', 'security-ninja' ),
			'records-5000'  => __( 'Keep last 5000 records', 'security-ninja' ),
			'records-10000' => __( 'Keep last 10000 records', 'security-ninja' ),
		);

		$modules = array(
			'users'          => __( 'Users', 'security-ninja' ),
			'menus'          => __( 'Menus', 'security-ninja' ),
			'file_editor'    => __( 'File Editor', 'security-ninja' ),
			'taxonomies'     => __( 'Taxonomies', 'security-ninja' ),
			'media'          => __( 'Media', 'security-ninja' ),
			'posts'          => __( 'Posts', 'security-ninja' ),
			'widgets'        => __( 'Widgets', 'security-ninja' ),
			'installer'      => __( 'Installer', 'security-ninja' ),
			'comments'       => __( 'Comments', 'security-ninja' ),
			'settings'       => __( 'Settings', 'security-ninja' ),
			'security_ninja' => 'Security Ninja',
			'woocommerce'    => __( 'WooCommerce', 'security-ninja' ),
		);
		?>
		<div class="section">
			<div class="wf-el-tab-content">
			<div class="nav-tab-wrapper" id="wf-sn-el-subtabs">
				<a href="#sn_el_log" class="nav-tab nav-tab-active"><?php esc_html_e( 'Event Log', 'security-ninja' ); ?></a>
				<a href="#sn_el_settings" class="nav-tab"><?php esc_html_e( 'Settings', 'security-ninja' ); ?></a>
				<?php
				$can_use_premium = false;
				if ( secnin_fs()->can_use_premium_code__premium_only() ) {
					$can_use_premium = true;
				}
				$pro_class = $can_use_premium ? '' : ' profeature';
				?>
				<a href="#sn_el_notifications" class="nav-tab<?php echo esc_attr( $pro_class ); ?>"><?php esc_html_e( 'Notifications', 'security-ninja' ); ?></a>
				<?php if ( secnin_fs()->can_use_premium_code__premium_only() ) { ?>
				<a href="#sn_el_webhooks" class="nav-tab"><?php esc_html_e( 'Webhooks', 'security-ninja' ); ?></a>
				<?php } ?>
			</div>

				<form action="options.php" method="post">
					<?php settings_fields( 'wf_sn_el' ); ?>

					<div id="sn_el_log" class="wf-sn-el-subtab">
						<div class="sncard">
							<h2><span class="dashicons dashicons-info-outline"></span> <?php esc_html_e( 'Events Logger', 'security-ninja' ); ?></h2>
							<p><?php esc_html_e( 'Track and analyze security events on your WordPress site', 'security-ninja' ); ?></p>
							
							<!-- Action Filter -->
							<div class="sn-el-filter-container">
								<select id="sn-el-action-filter">
									<option value=""><?php esc_html_e( 'Loading...', 'security-ninja' ); ?></option>
								</select>
								<button type="button" id="sn-el-reset-filter" class="button button-secondary"><?php esc_html_e( 'Reset', 'security-ninja' ); ?></button>
							</div>
							
							<table class="wp-list-table widefat fixed table-view-list" id="sn-el-datatable" style="border-spacing: 0;">
								<thead>
									<tr>
										<th id="sn-el-date" class="column-primary"><?php esc_html_e( 'Time', 'security-ninja' ); ?></th>
										<th id="sn-el-event"><?php esc_html_e( 'Event', 'security-ninja' ); ?></th>
										<th id="sn-el-user_id"><?php esc_html_e( 'User', 'security-ninja' ); ?></th>
										<th id="sn-el-action"><?php esc_html_e( 'Action', 'security-ninja' ); ?></th>
										<th id="sn-el-details"><?php esc_html_e( 'Details', 'security-ninja' ); ?></th>
									</tr>
								</thead>
								<tbody>
								</tbody>
								<tfoot>
									<tr>
										<th class="column-primary"><?php esc_html_e( 'Time', 'security-ninja' ); ?></th>
										<th><?php esc_html_e( 'Event', 'security-ninja' ); ?></th>
										<th><?php esc_html_e( 'User', 'security-ninja' ); ?></th>
										<th><?php esc_html_e( 'Action', 'security-ninja' ); ?></th>
										<th><?php esc_html_e( 'Details', 'security-ninja' ); ?></th>
									</tr>
								</tfoot>
							</table>

							<div id="datatable-error" class="card" style="display:none;"></div>
						</div>
					</div>

					<div id="sn_el_settings" class="wf-sn-el-subtab" style="display:none;">
						<div class="sncard settings-card">
							<div id="wf-sn-el-options-container">
								<h2><?php esc_html_e( 'General Settings', 'security-ninja' ); ?></h2>
								<p><?php esc_html_e( 'Configure how events are logged and managed', 'security-ninja' ); ?></p>
								<table class="form-table">
									<tbody>
										<tr valign="top">
											<th scope="row"><label for="wf_sn_el_active">
													<h3><?php esc_html_e( 'Enable events logging', 'security-ninja' ); ?></h3>
													<p class="description"><?php esc_html_e( 'If enabled events happening on your website will be logged here.', 'security-ninja' ); ?></p>
													<p class="description"><?php esc_html_e( 'Note - Some important events will still be logged here.', 'security-ninja' ); ?></p>
												</label></th>
											<td class="sn-cf-options">
												<?php
												\WPSecurityNinja\Plugin\Utils::create_toggle_switch(
													'wf_sn_el_active',
													array(
														'saved_value' => self::$options['active'],
														'option_key'  => 'wf_sn_el[active]',
													)
												);
												?>
											</td>
										</tr>
										<?php if ( secnin_fs()->can_use_premium_code__premium_only() ) { ?>
										<tr valign="top">
											<th scope="row"><label for="email_reports">
													<h3><?php esc_html_e( 'Email Reports', 'security-ninja' ); ?></h3>
													<p class="description"><?php esc_html_e( 'Email reports with a specified number of latest events can be automatically emailed to alert the admin of any suspicious events. Default: Do not email any reports', 'security-ninja' ); ?></p>
												</label></th>
											<td><select id="email_reports" name="wf_sn_el[email_reports]" class="regular-text">
													<?php foreach ( $email_reports_settings as $value => $label ) { ?>
														<option value="<?php echo esc_attr( $value ); ?>" <?php selected( self::$options['email_reports'], $value ); ?>>
															<?php echo esc_html( $label ); ?>
														</option>
													<?php } ?>
												</select>

											</td>
										</tr>
											<?php
											$selected_modules = (array) self::$options['email_modules'];
											?>
										<tr valign="top">
											<th scope="row"><label for="email_modules">
													<h3><?php esc_html_e( 'Which parts of WordPress to monitor', 'security-ninja' ); ?>
												</label></h3>
												<p class="description"><?php esc_html_e( 'If you don\'t want to monitor events from specific parts of WordPress, deselect them. Default: all modules.', 'security-ninja' ); ?></p>
											</th>
											<td><select size="12" id="email_modules" multiple="multiple" name="wf_sn_el[email_modules][]">
													<?php foreach ( $modules as $value => $label ) { ?>
														<option value="<?php echo esc_attr( $value ); ?>" <?php selected( in_array( $value, $selected_modules ), true ); ?>>
															<?php echo esc_html( $label ); ?>
														</option>
													<?php } ?>
												</select>

											</td>
										</tr>
										<tr valign="top">
											<th scope="row"><label for="email_to">
													<h3><?php esc_html_e( 'Email Recipient', 'security-ninja' ); ?></h3>
													<p class="description"><?php esc_html_e( 'One or more email addresses who will receive the reports. Separate more recipients with comma. Default: WP admin email.', 'security-ninja' ); ?></p>
												</label></th>
											<td></td>
										</tr>
										<tr>
											<td colspan="2"><input type="text" class="regular-text" id="email_to" name="wf_sn_el[email_to]" value="<?php echo esc_html( self::$options['email_to'] ); ?>" />

											</td>
										</tr>
										<tr valign="top">
											<th scope="row"><label for="retention">
													<h3><?php esc_html_e( 'Log Retention Policy', 'security-ninja' ); ?></h3>
													<p class="description"><?php esc_html_e( 'In order to preserve disk space logs are automatically deleted based on this option. Default: keep logs for 7 days.', 'security-ninja' ); ?></p>
												</label></th>
											<td><select id="retention" name="wf_sn_el[retention]" class="regular-text">
													<?php foreach ( $retention_settings as $value => $label ) { ?>
														<option value="<?php echo esc_attr( $value ); ?>" <?php selected( self::$options['retention'], $value ); ?>>
															<?php echo esc_html( $label ); ?>
														</option>
													<?php } ?>
												</select>
											</td>
										</tr>
										<?php } ?>
										<tr valign="top">
											<th scope="row"><label for="">
													<h3><?php esc_html_e( 'Miscellaneous', 'security-ninja' ); ?></h3>
													<p class="description"><?php esc_html_e( 'Delete all logged events in the database. Please note that there is NO undo for this action.', 'security-ninja' ); ?></p>
												</label></th>
										</tr>
										<tr>
											<td colspan="2"><input type="button" value="<?php esc_html_e( 'Delete all log entries', 'security-ninja' ); ?>" class="button-secondary button" id="sn-el-truncate" />

											</td>
										</tr>
									</tbody>
								</table>
								<div<?php
								if ( secnin_fs()->can_use_premium_code() ) {
									echo ' style="display:none;"';
								}
								?>>
								<div class="sncard infobox" style="margin-top: 20px;">
									<div class="inner">
										<h3>Upgrade to Pro for Advanced Event Auditing</h3>
										<p>The free version of Events Logger provides basic event auditing for your website, including login and failed login tracking. Upgrade to Security Ninja Pro to unlock powerful features:</p>
										<ul style="list-style: disc; margin-left: 20px; margin-top: 10px;">
											<li>Email reports with customizable frequency and module selection</li>
											<li>Advanced log retention policies for long-term auditing</li>
											<li>Webhook integrations for real-time event notifications</li>
											<li>Geolocation data for security events</li>
											<li>Advanced filtering and search capabilities</li>
											<li>Comprehensive tracking of all WordPress actions and changes</li>
										</ul>
										<p style="margin-top: 15px;">
											<a href="<?php echo esc_url( \WPSecurityNinja\Plugin\Utils::generate_sn_web_link( 'upgrade_tab_events_auditing', '/pricing/' ) ); ?>" class="button button-primary button-small" target="_blank" rel="noopener">Upgrade to Pro</a>
										</p>
									</div>
								</div>
								</div>
							</div>
						</div>
					</div>

					<div id="sn_el_notifications" class="wf-sn-el-subtab" style="display:none;">
						<?php if ( secnin_fs()->can_use_premium_code__premium_only() ) { ?>
							<div class="sncard settings-card">
								<h2><?php esc_html_e( 'Notification Settings', 'security-ninja' ); ?></h2>
								<p><?php esc_html_e( 'Configure notifications for important security events', 'security-ninja' ); ?></p>
								<table class="form-table">
									<tr>
										<th scope="row">
											<label for="wf_sn_el_notify_new_admin">
												<h3><?php esc_html_e( 'New Admin User Notifications', 'security-ninja' ); ?></h3>
												<p class="description">
													<?php esc_html_e( 'Get notified when a new administrator user is created', 'security-ninja' ); ?>
												</p>
											</label>
										</th>
										<td class="sn-cf-options">
											<?php
											\WPSecurityNinja\Plugin\Utils::create_toggle_switch(
												'wf_sn_el_notify_new_admin',
												array(
													'saved_value' => isset( self::$options['notify_new_admin'] ) ? self::$options['notify_new_admin'] : 0,
													'option_key'  => 'wf_sn_el[notify_new_admin]',
												)
											);
											?>

										</td>
									</tr>

									<tr class="notify-new-admin-email">
										<th scope="row">
											<label for="wf_sn_el_new_admin_notification_email">
												<h3><?php esc_html_e( 'Notification Email', 'security-ninja' ); ?></h3>
												<p class="description">
													<?php esc_html_e( 'Email address that will receive notifications about new admin users', 'security-ninja' ); ?>
												</p>
											</label>
										</th>
									</tr>
									<tr>
										<td colspan="2" class="fullwidth">
											<input
												name="wf_sn_el[new_admin_notification_email]"
												type="text"
												value="<?php echo esc_attr( ! empty( self::$options['new_admin_notification_email'] ) ? self::$options['new_admin_notification_email'] : $current_user->user_email ); ?>"
												class="regular-text">

										</td>
									</tr>
								</table>
							</div>
						<?php } ?>
						<?php
						$show_upsell = true;
						if ( secnin_fs()->can_use_premium_code__premium_only() ) {
							$show_upsell = false;
						}
						if ( $show_upsell ) :
							?>
						<div>
							<table class="form-table">
								<tbody>
									<tr>
										<td colspan="2">
											<div class="sncard infobox">
												<div class="inner">
													<h3>Upgrade to Pro for Notification Settings</h3>
													<p>The free version provides basic event logging. Upgrade to Security Ninja Pro to unlock notification features:</p>
													<ul style="list-style: disc; margin-left: 20px; margin-top: 10px;">
														<li>Get notified when new administrator users are created</li>
														<li>Customize notification email addresses</li>
													</ul>
													<p style="margin-top: 15px;">
														<a href="<?php echo esc_url( \WPSecurityNinja\Plugin\Utils::generate_sn_web_link( 'upgrade_tab_events_notifications', '/pricing/' ) ); ?>" class="button button-primary button-small" target="_blank" rel="noopener">Upgrade to Pro</a>
													</p>
												</div>
											</div>
										</td>
									</tr>
								</tbody>
							</table>
						</div>
						<?php endif; ?>
					</div>

					<?php if ( secnin_fs()->can_use_premium_code__premium_only() ) { ?>
					<div id="sn_el_webhooks" class="wf-sn-el-subtab" style="display:none;">
						<?php if ( secnin_fs()->can_use_premium_code__premium_only() ) { ?>
						<div id="sn_el_webhooks_premium" class="sncard settings-card">
							<h2><?php esc_html_e( 'Webhook Settings', 'security-ninja' ); ?></h2>
							<p><?php esc_html_e( 'Configure webhooks to integrate with external services', 'security-ninja' ); ?></p>

							<div class="sncard infobox">
								<div class="inner">
									<h3><?php esc_html_e( 'Webhooks Integration', 'security-ninja' ); ?></h3>
									<p><?php esc_html_e( 'Webhooks are sent as POST requests to the URL you specify. The request body contains a JSON object with information about the event that triggered the webhook.', 'security-ninja' ); ?></p>
								</div>
							</div>




							<table class="form-table">
								<tr valign="top">
									<th scope="row">
										<label for="webhook_active">
											<h3><?php esc_html_e( 'Webhook Active', 'security-ninja' ); ?></h3>
											<p class="description"><?php esc_html_e( 'If enabled the webhook URL will be notified about the selected events.', 'security-ninja' ); ?></p>
										</label>
									</th>
									<td class="sn-cf-options">
										<?php
										\WPSecurityNinja\Plugin\Utils::create_toggle_switch(
											'webhook_active',
											array(
												'saved_value' => ! empty( self::$options['webhook_active'] ) ? self::$options['webhook_active'] : 0,
												'option_key'  => 'wf_sn_el[webhook_active]',
											)
										);
										?>

									</td>
								</tr>
								<tr valign="top">
									<th scope="row"><label for="webhook_url">
											<h3><?php esc_html_e( 'Webhook URL', 'security-ninja' ); ?></h3>
											<p class="description"><?php esc_html_e( 'Webhooks are sent as POST requests to the URL you specify. The request body contains a JSON object with information about the event that triggered the webhook. You can use this information to take action in your own systems.', 'security-ninja' ); ?></p>
										</label></th>
								</tr>
								<tr>
									<td colspan="2" class="fullwidth"><input type="text" class="regular-text code" id="webhook_url" name="wf_sn_el[webhook_url]" value="<?php echo esc_url( isset( self::$options['webhook_url'] ) ? self::$options['webhook_url'] : '' ); ?>" placeholder="https://" />

									</td>
								</tr>
								<tr valign="top">
									<th scope="row">
										<h3><?php esc_html_e( 'Events', 'security-ninja' ); ?></h3>
										<p class="description"><?php esc_html_e( 'Select the events you want to send as webhooks. Webhooks are sent as POST requests to the specified URL. Each request contains a JSON object with details about the event, enabling you to react or log these events in your system. Note: Changes apply to future events only.', 'security-ninja' ); ?></p>
										</label>
									</th>
								</tr>

								<tr>
									<th scope="row">
										<label for="webhook_firewall_events">
											<h3><?php esc_html_e( 'Firewall events', 'security-ninja' ); ?></h3>
											<p class="description"><?php esc_html_e( 'Notify about blocked visitors', 'security-ninja' ); ?></p>
										</label>
									</th>
									<td class="sn-cf-options">
										<?php
										\WPSecurityNinja\Plugin\Utils::create_toggle_switch(
											'webhook_firewall_events',
											array(
												'saved_value' => ! empty( self::$options['webhook_firewall_events'] ) ? self::$options['webhook_firewall_events'] : 0,
												'option_key'  => 'wf_sn_el[webhook_firewall_events]',
											)
										);
										?>
									</td>
								</tr>

								<tr>
									<th>
										<label for="webhook_user_logins">
											<h3><?php esc_html_e( 'User logins', 'security-ninja' ); ?></h3>
											<p class="description"><?php esc_html_e( 'Notify on failed and successful logins', 'security-ninja' ); ?></p>
										</label>
									</th>
									<td class="sn-cf-options">
										<?php
										\WPSecurityNinja\Plugin\Utils::create_toggle_switch(
											'webhook_user_logins',
											array(
												'saved_value' => ! empty( self::$options['webhook_user_logins'] ) ? self::$options['webhook_user_logins'] : 0,
												'option_key'  => 'wf_sn_el[webhook_user_logins]',
											)
										);
										?>
									</td>
								</tr>
								<tr>
									<th>
										<label for="webhook_updates">
											<h3><?php esc_html_e( 'Updates', 'security-ninja' ); ?></h3>
											<p class="description"><?php esc_html_e( 'Notify about WordPress, plugins, and themes updates', 'security-ninja' ); ?></p>
										</label>
									</th>
									<td class="sn-cf-options">
										<?php
										\WPSecurityNinja\Plugin\Utils::create_toggle_switch(
											'webhook_updates',
											array(
												'saved_value' => ! empty( self::$options['webhook_updates'] ) ? self::$options['webhook_updates'] : 0,
												'option_key'  => 'wf_sn_el[webhook_updates]',
											)
										);
										?>
									</td>
								</tr>
							</table>
						</div>
						<?php } ?>
					</div>
					<?php } ?>

					<p class="submit">
						<input type="submit" value="<?php esc_html_e( 'Save Changes', 'security-ninja' ); ?>" class="button-primary input-button" name="Submit" />
					</p>
				</form>
			</div>
		</div>


		<?php
	}





	/**
	 * clean-up when deactivated
	 *
	 * @author  Lars Koudal
	 * @since   v0.0.1
	 * @version v1.0.0  Friday, January 1st, 2021.
	 * @access  public static
	 * @return  void
	 */
	public static function deactivate() {
		if ( ! isset( self::$options['remove_settings_deactivate'] ) ) {
			return;
		}
		if ( self::$options['remove_settings_deactivate'] ) {
			global $wpdb;
			delete_option( 'wf_sn_el' );
			$wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'wf_sn_el' );
		}

		// Clear both old and new cron jobs
		wp_clear_scheduled_hook( 'wf_sn_check_new_admins' );
		wp_clear_scheduled_hook( 'secnin_check_direct_admin_creation' );
	}
}

add_action( 'plugins_loaded', array( __NAMESPACE__ . '\wf_sn_el', 'init' ) );
register_deactivation_hook( WF_SN_BASE_FILE, array( __NAMESPACE__ . '\wf_sn_el', 'deactivate' ) );
