<?php
/**
 * Custom Sensors for LearnDash plugin.
 *
 * Class file for alert manager.
 *
 * @package wsal
 * @subpackage wsal-learndash
 *
 * @since 5.6.0
 */

declare(strict_types=1);

namespace WSAL\WP_Sensors;

use WSAL\Helpers\Settings_Helper;
use WSAL\Controllers\Alert_Manager;
use WSAL\Helpers\DateTime_Formatter_Helper;
use WSAL\WP_Sensors\Helpers\LearnDash_Helper;
use WSAL\WP_Sensors\Alerts\LearnDash_Custom_Alerts;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! \class_exists( '\WSAL\WP_Sensors\LearnDash_Sensor' ) ) {
	/**
	 * Custom sensor for LearnDash plugin.
	 *
	 * @since 5.6.0
	 */
	class LearnDash_Sensor {

		/**
		 * Course steps metadata store before updating metadata.
		 *
		 * Structure: [ (string) $post_id => array( 'lessons' => [...], 'topics' => [...], 'quizzes' => [...] ) ]
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $before_course_steps = array();

		/**
		 * Course metadata store before updating metadata.
		 * ! used specifically to track changes in the _sfwd-courses metadata.
		 *
		 * Structure: [ (string) $post_id => array( 'certificate' => $cert_id, 'price_type' => $price_type ) ]
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $before_course_meta = array();

		/**
		 * Group metadata store before updating metadata.
		 * Used specifically to track changes in the _groups metadata.
		 *
		 * Structure: [ (string) $post_id => array( 'groups_group_start_date' => $timestamp, 'groups_group_end_date' => $timestamp ) ]
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $before_group_meta = array();

		/**
		 * Miscellaneous single-value metadata store for tracking before-state of metadata updates.
		 * Structure: [ (string) $post_id ][ $meta_key ] = $meta_value
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $ld_misc_metadata = array();

		/**
		 * Course users before update.
		 * Structure: [ (int) $course_id => array( $user_id_1, $user_id_2, ... ) ]
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $before_course_users = array();

		/**
		 * Group users before update.
		 * Structure: [ (int) $group_id => array( $user_id_1, $user_id_2, ... ) ]
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $before_group_users = array();

		/**
		 * Stores the source post ID during a duplication/cloning request.
		 *
		 * @var int|null
		 *
		 * @since 5.6.0
		 */
		private static $duplication_source_id = null;

		/**
		 * Original LearnDash dates captured early in admin_init before any meta updates.
		 *
		 * Structure: [ (int) $post_id => array(
		 *     'post_type'  => 'sfwd-courses' or 'groups',
		 *     'start_date' => $timestamp,
		 *     'end_date'   => $timestamp,
		 * )]
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $before_ld_start_end_dates = array();

		/**
		 * Pending date change events to be checked after post save completes.
		 * Used to prevent duplicate events from LearnDash's multiple meta updates,
		 * since Learndash will trigger update meta twice: one for start date and one for end date.
		 *
		 * Structure: [ (int) $post_id => array(
		 *     'meta_key' => '_sfwd-courses' or '_groups',
		 *     'checked'  => false,
		 * )]
		 *
		 * @var array
		 *
		 * @since 5.6.0
		 */
		private static $pending_date_events = array();

		/**
		 * Loads all the plugin dependencies early.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function early_init() {
			if ( LearnDash_Helper::is_learndash_active() ) {
				\add_filter(
					'wsal_default_disabled_alerts',
					array( LearnDash_Custom_Alerts::class, 'add_default_disabled_alerts' )
				);

				self::maybe_apply_first_detection_disabled_alerts();

				\add_filter(
					'wsal_event_objects',
					array( LearnDash_Helper::class, 'wsal_learndash_add_custom_event_objects' ),
					10,
					2
				);

				\add_filter(
					'wsal_ignored_custom_post_types',
					array( LearnDash_Helper::class, 'wsal_learndash_add_custom_ignored_cpt' )
				);

			}
		}

		/**
		 * Hook events related to sensor.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function init() {
			if ( LearnDash_Helper::is_learndash_active() && \is_user_logged_in() ) {
				\add_action( 'admin_init', array( __CLASS__, 'store_prev_user_activity_data' ) );
				\add_action( 'admin_init', array( __CLASS__, 'maybe_save_duplicate_action_post_id' ) );
				\add_action( 'wp_after_insert_post', array( __CLASS__, 'ld_saved_post_event_triggers' ), 10, 4 );
				\add_action( 'wp_trash_post', array( __CLASS__, 'ld_post_trashed' ), 10, 1 );
				\add_action( 'before_delete_post', array( __CLASS__, 'ld_post_perma_deleted' ), 10, 2 );
				\add_action( 'untrash_post', array( __CLASS__, 'ld_post_restored' ), 10, 1 );

				\add_action( 'create_term', array( __CLASS__, 'ld_taxonomy_creation_triggers' ), 10, 4 );
				\add_action( 'delete_term', array( __CLASS__, 'ld_taxonomy_deletion_triggers' ), 10, 5 );

				\add_action( 'wp_head', array( __CLASS__, 'ld_post_viewed' ), 10 );
				\add_action( 'admin_action_edit', array( __CLASS__, 'ld_post_opened_in_gutenberg_editor' ), 10 );
				\add_filter( 'post_edit_form_tag', array( __CLASS__, 'ld_post_opened_in_classic_editor' ), 10, 1 );

			}
		}

		/**
		 * Triggered when a user accesses the admin area.
		 *
		 * @since 5.6.0
		 */
		public static function store_prev_user_activity_data() {
			// Verify nonce before accessing any POST data.
			$nonce   = isset( $_POST['_wpnonce'] ) ? \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ) ) : '';
			$post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;

			if ( empty( $nonce ) || ! \wp_verify_nonce( $nonce, 'update-post_' . $post_id ) ) {
				return;
			}

			$post_type = \sanitize_text_field( \wp_unslash( $_POST['post_type'] ?? '' ) );

			if ( 'sfwd-courses' === $post_type ) {
				if ( isset( $_POST['post_ID'] ) && isset( $_POST['learndash_course_users_nonce'] ) ) {
					$post_id = (int) $_POST['post_ID'];

					if ( \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST['learndash_course_users_nonce'] ) ), 'learndash_course_users_nonce_' . $post_id ) ) {
						if ( \function_exists( 'learndash_get_course_users_access_from_meta' ) ) {
							self::$before_course_users[ $post_id ] = \learndash_get_course_users_access_from_meta( $post_id );
						}
					}
				}
			}

			if ( 'groups' === $post_type ) {
				if ( isset( $_POST['post_ID'] ) ) {
					$post_id      = (int) $_POST['post_ID'];
					$nonce_field  = 'learndash_group_users-' . $post_id . '-nonce';
					$nonce_action = 'learndash_group_users-' . $post_id;

					if ( isset( $_POST[ $nonce_field ] ) ) {
						if ( \wp_verify_nonce( \sanitize_text_field( \wp_unslash( $_POST[ $nonce_field ] ) ), $nonce_action ) ) {
							if ( \function_exists( 'learndash_get_groups_user_ids' ) ) {
								self::$before_group_users[ $post_id ] = \learndash_get_groups_user_ids( $post_id, true );
							}
						}
					}
				}
			}
		}

		/**
		 * Captures original LearnDash dates from DB before any meta updates.
		 * This method handles both courses and groups.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function capture_before_ld_start_end_dates() {
			// Verify nonce before accessing any POST data.
			$nonce   = isset( $_POST['_wpnonce'] ) ? \sanitize_text_field( \wp_unslash( $_POST['_wpnonce'] ) ) : '';
			$post_id = isset( $_POST['post_ID'] ) ? (int) $_POST['post_ID'] : 0;

			if ( empty( $nonce ) || ! \wp_verify_nonce( $nonce, 'update-post_' . $post_id ) ) {
				return;
			}

			$post_type = \sanitize_text_field( \wp_unslash( $_POST['post_type'] ?? '' ) );

			// Only process courses and groups.
			if ( 'sfwd-courses' !== $post_type && 'groups' !== $post_type ) {
				return;
			}

			$post_dates = LearnDash_Helper::get_ld_start_end_dates_meta( $post_id, $post_type );

			if ( isset( $post_dates['start_date'] ) && isset( $post_dates['end_date'] ) ) {
				// Store original dates.
				self::$before_ld_start_end_dates[ $post_id ] = array(
					'post_type'  => $post_type,
					'start_date' => $post_dates['start_date'],
					'end_date'   => $post_dates['end_date'],
				);
			}
		}

		/**
		 * Checks and triggers pending date change events after post save completes.
		 * This fires once per request after all LearnDash meta updates are complete,
		 * preventing duplicate events from multiple meta_update hook calls that would happen with LearnDash.
		 *
		 * @param int $post_id - Post ID.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function maybe_trigger_start_end_date_events( int $post_id ) {

			// Check if this post has pending date events to check.
			if ( ! isset( self::$pending_date_events[ $post_id ] ) ) {
				return;
			}

			// Verify we have original dates captured.
			if ( ! isset( self::$before_ld_start_end_dates[ $post_id ] ) ) {
				return;
			}

			// Skip if already checked.
			if ( self::$pending_date_events[ $post_id ]['checked'] ) {
				return;
			}

			// Mark as checked to prevent duplicate processing.
			self::$pending_date_events[ $post_id ]['checked'] = true;

			// Get the meta key to check.
			$meta_key = self::$pending_date_events[ $post_id ]['meta_key'];

			// Get values after updates from database after all meta updates.
			$final_meta     = \get_post_meta( $post_id, $meta_key, true );
			$final_metadata = \maybe_unserialize( $final_meta );

			if ( ! \is_array( $final_metadata ) ) {

				// Clean up for this post.
				unset( self::$pending_date_events[ $post_id ] );
				unset( self::$before_ld_start_end_dates[ $post_id ] );
				return;
			}

			// Get original dates from Phase 1 capture.
			$original_dates = self::$before_ld_start_end_dates[ $post_id ];

			// Determine event ID and date keys based on meta_key.
			if ( '_sfwd-courses' === $meta_key ) {
				$start_date_key = 'sfwd-courses_course_start_date';
				$end_date_key   = 'sfwd-courses_course_end_date';
				$event_id       = 11056;
			} elseif ( '_groups' === $meta_key ) {
				$start_date_key = 'groups_group_start_date';
				$end_date_key   = 'groups_group_end_date';
				$event_id       = 11507;
			} else {
				return;
			}

			/**
			 * Compare dates
			 */
			$original_start = LearnDash_Helper::cast_date_to_float( $original_dates['start_date'] );
			$original_end   = LearnDash_Helper::cast_date_to_float( $original_dates['end_date'] );
			$final_start    = LearnDash_Helper::cast_date_to_float( $final_metadata[ $start_date_key ] ?? '' );
			$final_end      = LearnDash_Helper::cast_date_to_float( $final_metadata[ $end_date_key ] ?? '' );

			// Only trigger if something actually changed.
			if ( $original_start === $final_start && $original_end === $final_end ) {
				// Clean up for this post.
				unset( self::$pending_date_events[ $post_id ] );
				unset( self::$before_ld_start_end_dates[ $post_id ] );
				return;
			}

			/**
			 * Format dates for display.
			 *
			 * LD format in case of need:
			 * $formatted_old_start = empty( $before_start_date ) ? $not_set_string : \date_i18n( 'd F Y @ H:i', (int) $before_start_date );
			 * $formatted_new_start = empty( $after_start_date ) ? $not_set_string : \date_i18n( 'd F Y @ H:i', (int) $after_start_date );
			 * $formatted_old_end   = empty( $before_end_date ) ? $not_set_string : \date_i18n( 'd F Y @ H:i', (int) $before_end_date );
			 * $formatted_new_end   = empty( $after_end_date ) ? $not_set_string : \date_i18n( 'd F Y @ H:i', (int) $after_end_date );
			 */
			$not_set_string      = \esc_html__( 'Not set', 'wp-security-audit-log' );
			$formatted_old_start = empty( $original_start ) ? $not_set_string : DateTime_Formatter_Helper::get_formatted_date_time( $original_start, 'datetime' );
			$formatted_new_start = empty( $final_start ) ? $not_set_string : DateTime_Formatter_Helper::get_formatted_date_time( $final_start, 'datetime' );
			$formatted_old_end   = empty( $original_end ) ? $not_set_string : DateTime_Formatter_Helper::get_formatted_date_time( $original_end, 'datetime' );
			$formatted_new_end   = empty( $final_end ) ? $not_set_string : DateTime_Formatter_Helper::get_formatted_date_time( $final_end, 'datetime' );

			$event_variables = array(
				'PostTitle'      => \get_the_title( $post_id ),
				'PostID'         => $post_id,
				'OldStartDate'   => $formatted_old_start,
				'NewStartDate'   => $formatted_new_start,
				'OldEndDate'     => $formatted_old_end,
				'NewEndDate'     => $formatted_new_end,
				'EditorLinkPost' => \esc_url( \get_edit_post_link( $post_id ) ),
			);

			Alert_Manager::trigger_event( $event_id, $event_variables );

			// Clean up for this post.
			unset( self::$pending_date_events[ $post_id ] );
			unset( self::$before_ld_start_end_dates[ $post_id ] );
		}

		/**
		 * Detects if a duplication action is being performed and stores the source post ID.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function maybe_save_duplicate_action_post_id() {

			// Check for common duplication actions in $_REQUEST.
			$action = isset( $_REQUEST['action'] ) ? \sanitize_text_field( \wp_unslash( $_REQUEST['action'] ) ) : '';

			$ld_clone_actions = array(
				'learndash_cloning_action_course',
				'learndash_cloning_action_lesson',
				'learndash_cloning_action_topic',
			);

			if ( empty( $action ) || ! in_array( $action, $ld_clone_actions, true ) ) {
				return;
			}

			// Extract and sanitize object_id and nonce from REQUEST.
			$object_id = isset( $_REQUEST['object_id'] ) ? (int) $_REQUEST['object_id'] : 0;
			$nonce     = isset( $_REQUEST['nonce'] ) ? \sanitize_text_field( \wp_unslash( $_REQUEST['nonce'] ) ) : '';

			// Verify nonce with LearnDash's action format.
			if ( empty( $nonce ) || ! \wp_verify_nonce( $nonce, $action . $object_id ) ) {
				return;
			}

			// Store the clone source post ID for later use.
			self::$duplication_source_id = $object_id;
		}

		/**
		 * Ignore LearnDash user meta events.
		 *
		 * @param bool   $ignore_event - True if ignore meta event, false if not.
		 * @param string $meta_key     - Meta key.
		 * @param mixed  $meta_value   - Meta value.
		 * @param int    $user_id      - User ID.
		 *
		 * @return bool
		 *
		 * @since 5.6.0
		 */
		public static function ignore_learndash_user_meta_events( $ignore_event, $meta_key, $meta_value, $user_id ) {

			if ( $ignore_event ) {
				return $ignore_event;
			}

			/**
			 * Ignore LearnDash course enrollment meta keys.
			 */
			if ( \preg_match( '/^learndash_course_\d+_enrolled_at$/', $meta_key ) || \preg_match( '/^course_\d+_access_from$/', $meta_key ) ) {
				return true;
			}

			/**
			 * Ignore LearnDash group enrollment meta keys.
			 */
			if ( \preg_match( '/^learndash_group_\d+_enrolled_at$/', $meta_key ) || \preg_match( '/^group_\d+_access_from$/', $meta_key ) || \preg_match( '/^learndash_group_users_\d+$/', $meta_key ) ) {
				return true;
			}

			/**
			 * Ignore LearnDash quiz-related meta keys.
			 */
			if ( \preg_match( '/^quiz_time_\d+$/', $meta_key ) ) {
				return true;
			}

			return $ignore_event;
		}

		/**
		 * Trigger the create event for LearnDash posts
		 *
		 * @param string $post_type - The post type, used to trigger the correct event.
		 * @param array  $event_variables - Event variables.
		 *
		 * @since 5.6.0
		 */
		public static function trigger_ld_created_post_event( $post_type, $event_variables ) {
			if ( 'sfwd-courses' === $post_type ) {
				Alert_Manager::trigger_event( 11000, $event_variables );
			} elseif ( 'sfwd-lessons' === $post_type ) {
				Alert_Manager::trigger_event( 11200, $event_variables );
			} elseif ( 'sfwd-topic' === $post_type ) {
				Alert_Manager::trigger_event( 11400, $event_variables );
			} elseif ( 'groups' === $post_type ) {
				Alert_Manager::trigger_event( 11500, $event_variables );
			} elseif ( 'sfwd-certificates' === $post_type ) {
			}
		}

		/**
		 * Trigger the publish event for LearnDash posts
		 *
		 * @param string $post_type - The post type, used to trigger the correct event.
		 * @param array  $event_variables - Event variables.
		 *
		 * @since 5.6.0
		 */
		public static function trigger_ld_published_post_event( $post_type, $event_variables ) {
			if ( 'sfwd-courses' === $post_type ) {
				Alert_Manager::trigger_event( 11001, $event_variables );
			} elseif ( 'sfwd-lessons' === $post_type ) {
				Alert_Manager::trigger_event( 11201, $event_variables );
			} elseif ( 'sfwd-topic' === $post_type ) {
				Alert_Manager::trigger_event( 11401, $event_variables );
			} elseif ( 'groups' === $post_type ) {
				Alert_Manager::trigger_event( 11501, $event_variables );
			} elseif ( 'sfwd-certificates' === $post_type ) {
			}
		}

		/**
		 * Triggers duplication event if a source post ID was detected.
		 *
		 * @param \WP_Post $post                 - The duplicated post object.
		 * @param array    $post_event_variables - Event variables for the post.
		 *
		 * @return bool - True if duplication event was triggered, false otherwise.
		 *
		 * @since 5.6.0
		 */
		public static function maybe_trigger_duplication_event( $post, $post_event_variables ) {

			if ( self::$duplication_source_id && LearnDash_Helper::is_post_duplicate( $post, self::$duplication_source_id ) ) {

				// Override PostTitle with source post.
				$post_event_variables['PostTitle'] = \esc_html( \get_the_title( self::$duplication_source_id ) );

				// Get categories from the SOURCE post.
				$post_event_variables['Categories']     = LearnDash_Helper::get_post_categories( self::$duplication_source_id );
				$post_event_variables['LdPostCategory'] = LearnDash_Helper::get_ld_post_categories( self::$duplication_source_id, $post->post_type );

				if ( 'sfwd-courses' === $post->post_type ) {
					Alert_Manager::trigger_event( 11006, $post_event_variables );

					return true;
				} elseif ( 'sfwd-lessons' === $post->post_type ) {
					Alert_Manager::trigger_event( 11209, $post_event_variables );

					return true;
				} elseif ( 'sfwd-topic' === $post->post_type ) {
					Alert_Manager::trigger_event( 11406, $post_event_variables );

					return true;
				}
			}

			return false;
		}

		/**
		 * Learndash event triggers whenever a user saves a post: create, publish, update.
		 *
		 * @param int           $post_id - Post ID.
		 * @param \WP_Post      $post - Post object that was just updated.
		 * @param bool          $update - Whether this is an existing post being updated.
		 * @param null|\WP_Post $post_before - Null for new posts, the WP_Post object prior to the update for updated posts.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function ld_saved_post_event_triggers( $post_id, $post, $update, $post_before ) {

			if ( 'auto-draft' === $post->post_status || 'trash' === $post->post_status ) {
				return;
			}

			$ld_post_types = LearnDash_Helper::get_custom_post_types();

			if ( ! \in_array( $post->post_type, $ld_post_types, true ) ) {
				return;
			}

			$post_event_variables                   = LearnDash_Helper::build_ld_post_event_variables( $post );
			$post_event_variables['PostStatus']     = $post->post_status;
			$post_event_variables['EditorLinkPost'] = \esc_url( \get_edit_post_link( $post->ID ) );

			// Check for course UI post creation.
			if ( $post_before && Learndash_Helper::ld_post_created_via_ld_course_builder( $post_before, $post, $update ) ) {
				self::trigger_ld_created_post_event( $post->post_type, $post_event_variables );

				// Return to avoid further processing.
				return;
			}

			// Check for duplication.
			if ( self::maybe_trigger_duplication_event( $post, $post_event_variables ) ) {
				// Return to avoid further processing.
				return;
			}

			/**
			 * A post is considered truly created if it's displayed in its post list.
			 */
			if ( ( 'draft' === $post->post_status || 'publish' === $post->post_status ) && $update && 'auto-draft' === $post_before->post_status ) {
				self::trigger_ld_created_post_event( $post->post_type, $post_event_variables );
			}

			if ( 'publish' === $post->post_status && $update && ( 'draft' === $post_before->post_status || 'auto-draft' === $post_before->post_status ) ) {

				// Unset PostStatus from variables, it's not needed in published event.
				unset( $post_event_variables['PostStatus'] );

				self::trigger_ld_published_post_event( $post->post_type, $post_event_variables );


				// Return to avoid further processing.
				return;

			} elseif ( $post_before && 'auto-draft' !== $post_before->post_status ) {

			}
		}

		/**
		 * Detect when a Learndash post is moved to trash.
		 *
		 * @param int $post_id - Post ID.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function ld_post_trashed( $post_id ) {
			$post = \get_post( $post_id );

			$ld_post_types = LearnDash_Helper::get_custom_post_types();

			if ( ! in_array( $post->post_type, $ld_post_types, true ) ) {
				return;
			}

			$event_variables               = LearnDash_Helper::build_ld_post_event_variables( $post );
			$event_variables['PostStatus'] = $post->post_status;

			if ( 'sfwd-courses' === $post->post_type ) {
				Alert_Manager::trigger_event( 11003, $event_variables );
			} elseif ( 'sfwd-lessons' === $post->post_type ) {
				Alert_Manager::trigger_event( 11206, $event_variables );
			} elseif ( 'sfwd-topic' === $post->post_type ) {
				Alert_Manager::trigger_event( 11404, $event_variables );
			} elseif ( 'groups' === $post->post_type ) {
				Alert_Manager::trigger_event( 11503, $event_variables );
			} elseif ( 'sfwd-certificates' === $post->post_type ) {
			}
		}

		/**
		 * Detect when a Learndash post is permanently deleted.
		 *
		 * @param int      $post_id - Post ID.
		 * @param \WP_Post $post - Post object.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function ld_post_perma_deleted( $post_id, $post ) {

			$ld_post_types = LearnDash_Helper::get_custom_post_types();

			if ( ! in_array( $post->post_type, $ld_post_types, true ) ) {
				return;
			}

			$event_variables = LearnDash_Helper::build_ld_post_event_variables( $post );

			if ( 'sfwd-courses' === $post->post_type ) {
				Alert_Manager::trigger_event( 11004, $event_variables );
			} elseif ( 'sfwd-lessons' === $post->post_type ) {
				Alert_Manager::trigger_event( 11207, $event_variables );
			} elseif ( 'sfwd-topic' === $post->post_type ) {
				Alert_Manager::trigger_event( 11405, $event_variables );
			} elseif ( 'groups' === $post->post_type ) {
				Alert_Manager::trigger_event( 11504, $event_variables );
			} elseif ( 'sfwd-certificates' === $post->post_type ) {
			}
		}

		/**
		 * Detect when a Learndash post is restored from trash.
		 *
		 * @param int $post_id - Post ID.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function ld_post_restored( $post_id ) {
			$post = \get_post( $post_id );

			$ld_post_types = LearnDash_Helper::get_custom_post_types();

			if ( ! in_array( $post->post_type, $ld_post_types, true ) ) {
				return;
			}

			$event_variables                   = LearnDash_Helper::build_ld_post_event_variables( $post );
			$event_variables['EditorLinkPost'] = \esc_url( \get_edit_post_link( $post->ID ) );

			if ( 'sfwd-courses' === $post->post_type ) {
				Alert_Manager::trigger_event( 11005, $event_variables );
			} elseif ( 'sfwd-lessons' === $post->post_type ) {
				Alert_Manager::trigger_event( 11208, $event_variables );
			} elseif ( 'groups' === $post->post_type ) {
				Alert_Manager::trigger_event( 11505, $event_variables );
			} elseif ( 'sfwd-certificates' === $post->post_type ) {
			}
		}


		/**
		 * New course category created trigger.
		 *
		 * @param int    $term_id - Term ID.
		 * @param int    $tt_id - Term taxonomy ID.
		 * @param string $taxonomy - Taxonomy slug.
		 * @param array  $args - Arguments passed to wp_insert_term().
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function ld_taxonomy_creation_triggers( $term_id, $tt_id, $taxonomy, $args ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
			$ld_taxonomies = LearnDash_Helper::get_custom_taxonomies();

			if ( ! \in_array( $taxonomy, $ld_taxonomies, true ) ) {
				return;
			}

			$term = \get_term( $term_id, $taxonomy );

			$event_variables = array(
				'TaxonomyTitle' => $term->name,
				'Slug'          => $term->slug,
			);

			if ( 'ld_course_category' === $taxonomy ) {
				$event_variables['CategoryLink'] = LearnDash_Helper::get_ld_taxonomy_edit_link( $term_id, 'ld_course_category', 'sfwd-courses' );

				Alert_Manager::trigger_event( 11080, $event_variables );
			} elseif ( 'ld_lesson_category' === $taxonomy ) {
				$event_variables['CategoryLink'] = LearnDash_Helper::get_ld_taxonomy_edit_link( $term_id, 'ld_lesson_category', 'sfwd-lessons' );

				Alert_Manager::trigger_event( 11300, $event_variables );
			} elseif ( 'ld_course_tag' === $taxonomy ) {
				$event_variables['TagLink'] = LearnDash_Helper::get_ld_taxonomy_edit_link( $term_id, 'ld_course_tag', 'sfwd-courses' );

				Alert_Manager::trigger_event( 11090, $event_variables );
			} elseif ( 'ld_lesson_tag' === $taxonomy ) {
				$event_variables['TagLink'] = LearnDash_Helper::get_ld_taxonomy_edit_link( $term_id, 'ld_lesson_tag', 'sfwd-lessons' );

				Alert_Manager::trigger_event( 11350, $event_variables );
			} elseif ( 'ld_topic_tag' === $taxonomy ) {
				$event_variables['TagLink'] = LearnDash_Helper::get_ld_taxonomy_edit_link( $term_id, 'ld_topic_tag', 'sfwd-topic' );

				Alert_Manager::trigger_event( 11450, $event_variables );
			}
		}

		/**
		 * Course category deleted trigger.
		 *
		 * @param int      $term_id - Term ID.
		 * @param int      $tt_id - Term taxonomy ID.
		 * @param string   $taxonomy - Taxonomy slug.
		 * @param \WP_Term $deleted_term - Copy of the already-deleted term.
		 * @param array    $object_ids - List of term object IDs.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		public static function ld_taxonomy_deletion_triggers( $term_id, $tt_id, $taxonomy, $deleted_term, $object_ids ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
			$ld_taxonomies = LearnDash_Helper::get_custom_taxonomies();

			if ( ! \in_array( $taxonomy, $ld_taxonomies, true ) ) {
				return;
			}

			$event_variables = array(
				'TaxonomyTitle' => $deleted_term->name,
				'Slug'          => $deleted_term->slug,
			);

			if ( 'ld_course_category' === $taxonomy ) {
				Alert_Manager::trigger_event( 11081, $event_variables );
			} elseif ( 'ld_lesson_category' === $taxonomy ) {
				Alert_Manager::trigger_event( 11301, $event_variables );
			} elseif ( 'ld_course_tag' === $taxonomy ) {
				Alert_Manager::trigger_event( 11091, $event_variables );
			} elseif ( 'ld_lesson_tag' === $taxonomy ) {
				Alert_Manager::trigger_event( 11351, $event_variables );
			} elseif ( 'ld_topic_tag' === $taxonomy ) {
				Alert_Manager::trigger_event( 11451, $event_variables );
			}
		}


		/**
		 * Detect when a logged-in user views a LearnDash course or lesson on the front-end.
		 *
		 * @return void
		 *
		 * @since 5.6.2
		 */
		public static function ld_post_viewed() {
			if ( ! \is_singular( array( 'sfwd-courses', 'sfwd-lessons' ) ) ) {
				return;
			}

			if ( ! \is_user_logged_in() || \is_admin() ) {
				return;
			}

			$post = \get_queried_object();

			if ( empty( $post ) || ! $post instanceof \WP_Post ) {
				return;
			}

			$current_path = isset( $_SERVER['REQUEST_URI'] ) ? \sanitize_text_field( \wp_unslash( $_SERVER['REQUEST_URI'] ) ) : false;

			if (
				! empty( $_SERVER['HTTP_REFERER'] )
				&& ! empty( $current_path )
				&& false !== \strpos( \sanitize_text_field( \wp_unslash( $_SERVER['HTTP_REFERER'] ) ), $current_path )
			) {
				// Ignore same-page refresh to avoid double entries.
				return;
			}

			if ( empty( $post->post_title ) ) {
				return;
			}

			if ( 'sfwd-courses' === $post->post_type ) {
				$event_id = 11020;
			} elseif ( 'sfwd-lessons' === $post->post_type ) {
				$event_id = 11215;
			} else {
				return;
			}

			$event_variables = LearnDash_Helper::build_ld_view_event_variables( $post );

			$event_variables['PostUrl']        = \esc_url( \get_permalink( $post->ID ) );
			$event_variables['EditorLinkPost'] = \esc_url( \get_edit_post_link( $post->ID ) );

			Alert_Manager::trigger_event( $event_id, $event_variables );
		}

		/**
		 * Detect when a LearnDash course or lesson is opened in the Gutenberg editor.
		 *
		 * @return void
		 *
		 * @since 5.6.2
		 */
		public static function ld_post_opened_in_gutenberg_editor() {
			$post_id = isset( $_GET['post'] ) ? (int) $_GET['post'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended

			if ( 0 === $post_id ) {
				return;
			}

			$post = \get_post( $post_id );

			if ( empty( $post ) || ! $post instanceof \WP_Post ) {
				return;
			}

			if ( ! \in_array( $post->post_type, array( 'sfwd-courses', 'sfwd-lessons' ), true ) ) {
				return;
			}

			self::ld_post_opened_in_editor( $post );
		}

		/**
		 * Detect when a LearnDash course or lesson is opened in the Classic editor.
		 *
		 * @param \WP_Post $post - Post object.
		 *
		 * @return \WP_Post
		 *
		 * @since 5.6.2
		 */
		public static function ld_post_opened_in_classic_editor( $post ) {
			if ( empty( $post ) || ! $post instanceof \WP_Post ) {
				return $post;
			}

			if ( ! \in_array( $post->post_type, array( 'sfwd-courses', 'sfwd-lessons' ), true ) ) {
				return $post;
			}

			self::ld_post_opened_in_editor( $post );

			return $post;
		}

		/**
		 * Shared logic for triggering the "opened in editor" event for LearnDash courses and lessons.
		 *
		 * @param \WP_Post $post - Post object.
		 *
		 * @return void
		 *
		 * @since 5.6.2
		 */
		private static function ld_post_opened_in_editor( $post ) {
			$current_path = isset( $_SERVER['SCRIPT_NAME'] ) ? \esc_url_raw( \wp_unslash( $_SERVER['SCRIPT_NAME'] ) ) . '?post=' . $post->ID : false;
			$referrer     = isset( $_SERVER['HTTP_REFERER'] ) ? \esc_url_raw( \wp_unslash( $_SERVER['HTTP_REFERER'] ) ) : false;

			// If the referrer is post-new then we can ignore this one.
			if ( ! empty( $referrer ) ) {
				$parsed_url = \wp_parse_url( $referrer );

				if ( isset( $parsed_url['path'] ) && 'post-new' === basename( $parsed_url['path'], '.php' ) ) {
					return;
				}
			}

			if ( ! empty( $referrer ) && false !== strpos( $referrer, $current_path ) ) {
				// Ignore same-page to avoid double entries.
				return;
			}

			if ( empty( $post->post_title ) ) {
				return;
			}

			if ( 'sfwd-courses' === $post->post_type ) {
				$event_id = 11021;
			} elseif ( 'sfwd-lessons' === $post->post_type ) {
				$event_id = 11216;
			} else {
				return;
			}

			if ( ! Alert_Manager::was_triggered( $event_id ) ) {
				$event_variables = LearnDash_Helper::build_ld_view_event_variables( $post );

				$event_variables['EditorLinkPost'] = \esc_url( \get_edit_post_link( $post->ID ) );

				Alert_Manager::trigger_event( $event_id, $event_variables );
			}
		}

		/**
		 * Applies default disabled alerts when LearnDash is first detected by an existing WSAL install.
		 *
		 * This ensures high-volume events are disabled even when WSAL was installed before LearnDash.
		 *
		 * @return void
		 *
		 * @since 5.6.0
		 */
		private static function maybe_apply_first_detection_disabled_alerts() {
			$processed_plugins = \get_option( 'wsal_detected_plugins_processed', array() );

			if ( in_array( 'sfwd-lms', $processed_plugins, true ) ) {
				return;
			}

			$disabled_alerts = Settings_Helper::get_disabled_alerts();

			$learndash_defaults = LearnDash_Custom_Alerts::get_default_disabled_alerts();
			$disabled_alerts    = array_unique( array_merge( $disabled_alerts, $learndash_defaults ) );

			Settings_Helper::set_disabled_alerts( $disabled_alerts );

			$processed_plugins[] = 'sfwd-lms';

			\update_option( 'wsal_detected_plugins_processed', $processed_plugins );
		}
	}
}
