<?php
/**
 * Fast Events setup
 *
 * @package FastEvents
 * @since 1.0
 */

declare(strict_types=1);

defined( 'ABSPATH' ) || exit;

use FeData\FastEvents\Admin\AdminMenu;
use FeData\FastEvents\Core\Activation;
use FeData\FastEvents\Core\Upgrade;
use FeData\FastEvents\Helpers\AuthHelper;
use FeData\FastEvents\Hooks\Actions\CleanCacheAction;
use FeData\FastEvents\Hooks\Actions\ConfirmationTimeoutAction;
use FeData\FastEvents\Hooks\Actions\PaymentExpireAction;
use FeData\FastEvents\Hooks\Actions\SendMailAction;
use FeData\FastEvents\Hooks\Actions\UpdateWebUIAction;
use FeData\FastEvents\Hooks\Actions\WebhookAction;
use FeData\FastEvents\Hooks\Shortcodes\DownloadShortcode;
use FeData\FastEvents\Hooks\Shortcodes\OrderPageShortcode;
use FeData\FastEvents\Hooks\Shortcodes\PersonaliseShortcode;
use FeData\FastEvents\Hooks\Shortcodes\RetryUrlShortcode;
use FeData\FastEvents\RestAPI\Admin\OrderingShortcodesController;
use FeData\FastEvents\RestAPI\Admin\SettingsController;
use FeData\FastEvents\RestAPI\CouponsAdminController;
use FeData\FastEvents\RestAPI\EventsAdminController;
use FeData\FastEvents\RestAPI\ExportImportController;
use FeData\FastEvents\RestAPI\KmlAdminController;
use FeData\FastEvents\RestAPI\LoginController;
use FeData\FastEvents\RestAPI\OrderingController;
use FeData\FastEvents\RestAPI\OrdersAdminController;
use FeData\FastEvents\RestAPI\PaymentController;
use FeData\FastEvents\RestAPI\PersonaliseController;
use FeData\FastEvents\RestAPI\Public\AccountsController;
use FeData\FastEvents\RestAPI\Public\BulkCouponsController;
use FeData\FastEvents\RestAPI\Public\BulkEmailsController;
use FeData\FastEvents\RestAPI\Public\BulkOrderEmailsController;
use FeData\FastEvents\RestAPI\Public\BulkRefundsController;
use FeData\FastEvents\RestAPI\Public\CouponsController;
use FeData\FastEvents\RestAPI\Public\Download\InvoiceDownloadController;
use FeData\FastEvents\RestAPI\Public\Download\TicketsDownloadController;
use FeData\FastEvents\RestAPI\Public\EmailsController;
use FeData\FastEvents\RestAPI\Public\EmailWebhooksController;
use FeData\FastEvents\RestAPI\Public\EventsController;
use FeData\FastEvents\RestAPI\Public\InputFieldsController;
use FeData\FastEvents\RestAPI\Public\LogsController;
use FeData\FastEvents\RestAPI\Public\MailListsController;
use FeData\FastEvents\RestAPI\Public\OrdersController;
use FeData\FastEvents\RestAPI\Public\PdfTemplatesController;
use FeData\FastEvents\RestAPI\Public\QrcodeScansController;
use FeData\FastEvents\RestAPI\Public\ScanKeysController;
use FeData\FastEvents\RestAPI\Public\StatSalesController;
use FeData\FastEvents\RestAPI\Public\StatScansController;
use FeData\FastEvents\RestAPI\Public\SubAccountsController;
use FeData\FastEvents\RestAPI\Public\TicketsController;
use FeData\FastEvents\RestAPI\Public\TicketTypesController;
use FeData\FastEvents\RestAPI\Public\WebhooksController;
use FeData\FastEvents\RestAPI\SaasController;
use FeData\FastEvents\RestAPI\TrackingController;
use FeData\FastEvents\Storage\Options;
use FeData\FastEvents\Storage\PluginSettings;
use FeData\FastEvents\Utilities\SettingsDefaults;
use JetBrains\PhpStorm\NoReturn;

/**
 * Main class.
 */
class FastEvents {
	public const FAST_EVENTS_VERSION = '3.0.0';
	public const FE_ADMIN_VERSION    = 'v4.6';

	/**
	 * REST API routes that have high priority during the selling and scanning phases.
	 *
	 * @since 1.0
	 * @var array
	 */
	private static array $fast_routes = array(
		'/v1/payment'     => PaymentController::class,
		'/v1/scans'       => QrcodeScansController::class,
		'/v1/tickets'     => TicketsDownloadController::class,
		'/v1/personalise' => PersonaliseController::class,
		'/v1/tracking'    => TrackingController::class,
	);

	/**
	 * REST API routes that are related to the management interface.
	 * Longest routes first. The first matching route will be used.
	 *
	 * @since 1.0
	 * @var array
	 */
	private static array $slow_routes = array(
		'~^/v1/admin/events/\d+/input-fields.*$~'   => InputFieldsController::class,
		'~^/v1/admin/events/\d+/scan-keys.*$~'      => ScanKeysController::class,
		'~^/v1/admin/events/\d+/ticket-types.*$~'   => TicketTypesController::class,
		'~^/v1/admin/accounts/\d+/sub_accounts.*$~' => SubAccountsController::class,
		'~^/v1/admin/events/\d+/sales.*$~'          => StatSalesController::class,
		'~^/v1/admin/events/\d+/scans.*$~'          => StatScansController::class,
		'~^/v1/admin/bulk/emails.*$~'               => BulkEmailsController::class,
		'~^/v1/admin/bulk/order-emails.*$~'         => BulkOrderEmailsController::class,
		'~^/v1/admin/bulk/refunds.*$~'              => BulkRefundsController::class,
		'~^/v1/admin/coupons/[a-z]+$~'              => CouponsAdminController::class,
		'~^/v1/admin/coupons/bulk/emails.*$~'       => BulkCouponsController::class,
		'~^/v1/admin/coupons.*$~'                   => CouponsController::class,
		'~^/v1/admin/accounts.*$~'                  => AccountsController::class,
		'~^/v1/admin/emaillists.*$~'                => MailListsController::class,
		'~^/v1/admin/events/(export|import)$~'      => ExportImportController::class,
		'~^/v1/admin/events/kml.*$~'                => KmlAdminController::class,
		'~^/v1/admin/events/[a-z_]+$~'              => EventsAdminController::class,
		'~^/v1/admin/events.*$~'                    => EventsController::class,
		'~^/v1/admin/orders/[a-z_]+$~'              => OrdersAdminController::class,
		'~^/v1/admin/orders.*$~'                    => OrdersController::class,
		'~^/v1/admin/pdf-templates.*$~'             => PdfTemplatesController::class,
		'~^/v1/admin/emails.*$~'                    => EmailsController::class,
		'~^/v1/admin/login.*$~'                     => LoginController::class,
		'~^/v1/admin/logs.*$~'                      => LogsController::class,
		'~^/v1/admin/shortcodes.*$~'                => OrderingShortcodesController::class,
		'~^/v1/admin/tickets.*$~'                   => TicketsController::class,
		'~^/v1/admin/webhooks.*$~'                  => WebhooksController::class,
		'~^/v1/email/webhook.*$~'                   => EmailWebhooksController::class,
		'~^/v1/invoice.*$~'                         => InvoiceDownloadController::class,
		'~^/v1/ordering.*$~'                        => OrderingController::class,
		'~^/v1/settings.*$~'                        => SettingsController::class,
		'~^/v1/(?:admin/)?saas.*$~'                 => SaasController::class,
	);

	/**
	 * REST API routes that can be embedded in other routes.
	 *
	 * @since 1.0
	 * @var array
	 */
	private static array $embedded_routes = array(
		'input_fields' => InputFieldsController::class,
		'scan_keys'    => ScanKeysController::class,
		'ticket_types' => TicketTypesController::class,
	);

	/**
	 * FastEvents instance
	 *
	 * @since 1.0
	 * @var null|FastEvents
	 */
	protected static ?FastEvents $instance = null;

	/**
	 * Options instance
	 *
	 * @since 1.0
	 * @var Options
	 */
	protected Options $options;

	/**
	 * PluginSettings instance
	 *
	 * @since 1.0
	 * @var PluginSettings
	 */
	protected PluginSettings $settings;

	/**
	 * Main Plugin Instance
	 * Ensures only one instance of the plugin is loaded or can be loaded.
	 *
	 * @since 1.0
	 */
	public static function instance(): FastEvents {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}


	/**
	 * Fast_Events constructor.
	 *
	 * @since 1.0
	 */
	public function __construct() {
		global $fevt_container;

		if ( ! defined( 'FAST_EVENTS_ABSPATH' ) ) {
			define( 'FAST_EVENTS_ABSPATH', dirname( FAST_EVENTS_PLUGIN_FILE ) . '/' );
		}

		// Action scheduler.
		require_once FAST_EVENTS_ABSPATH . 'libraries/action-scheduler/action-scheduler.php';

		// Options and PluginSettings instance.
		$this->options  = $fevt_container->get( Options::class );
		$this->settings = $fevt_container->get( PluginSettings::class );

		// Load action scheduler, admin-page, shortcodes, actions and rest hooks.
		add_action( 'init', array( $this, 'setup_auth' ) );
		add_action( 'init', array( $this, 'setup_action_scheduler' ) );
		add_action( 'init', array( $this, 'admin_pages' ) );
		add_action( 'init', array( $this, 'asw_hooks' ) ); // Actions and shortcodes.
		add_action( 'rest_api_init', array( $this, 'rest_api' ) );

		// Run lifecycle methods.
		add_action( 'wp_loaded', array( $this, 'check_for_upgrade' ) );

		// Add the activation hooks.
		register_activation_hook( FAST_EVENTS_PLUGIN_FILE, array( $this, 'fast_events_activate' ) );

		// Add deactivation hooks.
		register_deactivation_hook( FAST_EVENTS_PLUGIN_FILE, array( $this, 'fast_events_deactivate' ) );

		// Multisite actions.
		add_action( 'wp_initialize_site', array( $this, 'new_blog' ), 900, 2 );
		add_action( 'wp_uninitialize_site', array( $this, 'delete_blog' ), 9 );
		add_action( 'make_spam_blog', array( $this, 'set_site_status' ) );
		add_action( 'archive_blog', array( $this, 'set_site_status' ) );
		add_action( 'make_delete_blog', array( $this, 'set_site_status' ) );
		add_action( 'make_ham_blog', array( $this, 'unset_site_status' ) );
		add_action( 'unarchive_blog', array( $this, 'unset_site_status' ) );
		add_action( 'make_undelete_blog', array( $this, 'unset_site_status' ) );
	}


	/**
	 * Set up authentication hooks
	 *
	 * @since 3.0.0
	 */
	public function setup_auth(): void {
		global $fevt_container;

		// Save application password info after the user is authenticated.
		add_action( 'application_password_did_authenticate', array( $fevt_container->get( AuthHelper::class ), 'apw_save_info' ), 10, 2 );

		// Delete permission user meta-data based on uuid of the application password.
		add_action( 'wp_delete_application_password', array( $fevt_container->get( AuthHelper::class ), 'apw_delete' ), 10, 2 );

		// After authentication, we filter the endpoint if it is allowed or not.
		add_filter( 'rest_pre_dispatch', array( $fevt_container->get( AuthHelper::class ), 'apw_check_endpoint' ), 10, 3 );

		// Check if 'fe_account' users are allowed to log in to the WordPress dashboard.
		add_filter( 'authenticate', array( $fevt_container->get( AuthHelper::class ), 'user_login' ), 1000, 3 );

		// Check if 'fe_account' users are allowed to do a password reset.
		add_filter( 'allow_password_reset', array( $fevt_container->get( AuthHelper::class ), 'password_reset' ), 10, 2 );
	}

	/**
	 * Set up the action-scheduler when the WordPress version and PHP version is OK
	 *
	 * @since 1.0
	 * @since 1.4 Requires WordPress 6.0 or higher and PHP 8.0 or higher
	 * @since 2.0.3 Added action-scheduler tasks here
	 * @since 2.4.0 Requires WordPress 6.4 or higher
	 * @since 3.0.0 Requires PHP 8.1 or higher
	 */
	public function setup_action_scheduler(): void {
		if ( ! is_wp_version_compatible( '6.4' ) ) {
			add_action( 'admin_notices', array( $this, 'required_wp_version' ) );
			return;
		}
		if ( ! is_php_version_compatible( '8.1' ) ) {
			add_action( 'admin_notices', array( $this, 'required_php_version' ) );
			return;
		}

		$this->try_setup_action_scheduler_tasks();
	}


	/**
	 * Set up the admin pages if the user has the right permissions.
	 *
	 * @since 3.0
	 */
	public function admin_pages(): void {
		global $fevt_container;

		// Add the settings and admin menu.
		if ( current_user_can( 'manage_options' ) ) {
			$admin_menu = $fevt_container->get( AdminMenu::class );
			add_action( 'admin_menu', array( $admin_menu, 'add_admin_menu' ) );

			// Load the styles and js files.
			add_action( 'admin_enqueue_scripts', array( $admin_menu, 'load_styles_scripts' ) );
		}
	}


	/**
	 * Set up action hooks from the action-scheduler.
	 *
	 * @since 3.0
	 */
	public function asw_hooks(): void {
		global $fevt_container;

		// Actions for the action-scheduler.
		add_action( 'fast_events_action_clean_cache', array( $fevt_container->get( CleanCacheAction::class ), 'clean_cache' ) );
		add_action( 'fast_events_action_confirmation_timeout', array( $fevt_container->get( ConfirmationTimeoutAction::class ), 'confirmation_timeout' ) );
		add_action( 'fast_events_action_payment_expire', array( $fevt_container->get( PaymentExpireAction::class ), 'expire_payment' ) );
		add_action( 'fast_events_action_send_mail', array( $fevt_container->get( SendMailAction::class ), 'send_email' ), 10, 7 );
		add_action( 'fast_events_action_update_web', array( $fevt_container->get( UpdateWebUIAction::class ), 'update_web_ui' ), 10, 4 );
		add_action( 'fast_events_action_webhook', array( $fevt_container->get( WebhookAction::class ), 'webhook' ), 10, 4 );

		// Shortcodes.
		if ( ! is_admin() ) {
			add_filter(
				'query_vars',
				function ( array $qvars ) {
					$qvars[] = 'redirect_uid';
					$qvars[] = 'ticket_ids';
					$qvars[] = 'hash';

					return $qvars;
				}
			);
			add_shortcode( 'fast_events', array( $fevt_container->get( OrderPageShortcode::class ), 'create_page' ) );
			add_shortcode( 'fe_retry', array( $fevt_container->get( RetryUrlShortcode::class ), 'add_retry_url' ) );
			add_shortcode( 'fe_download', array( $fevt_container->get( DownloadShortcode::class ), 'add_download_url' ) );
			add_shortcode( 'fe_personalise', array( $fevt_container->get( PersonaliseShortcode::class ), 'personalise' ) );
		}
	}


	/**
	 * Load only the REST controller needed for the current request.
	 *
	 * @since 3.0
	 */
	public function rest_api(): void {
		global $fevt_container;

		// The path we are searching for.
		$path   = filter_var( wp_unslash( $_SERVER['REQUEST_URI'] ?? '' ), FILTER_SANITIZE_URL );
		$search = preg_match( '#wp-json/fast-events(.*)#', $path, $matches ) ? $matches[1] : '';

		// Look for fast routes. Return if we find one.
		foreach ( self::$fast_routes as $prefix => $controller ) {
			if ( str_starts_with( $search, $prefix ) ) {
				$fevt_container->get( $controller )->register_routes();
				return;
			}
		}

		// Now look into the slow routes. Break if there is a match.
		foreach ( self::$slow_routes as $rx => $controller ) {
			if ( preg_match( $rx, $search ) ) {
				$fevt_container->get( $controller )->register_routes();
				break;
			}
		}

		// Check whether there is an ‘_embed’ parameter—if so, we must also include those endpoints.
		$parts = wp_parse_url( $path );
		$query = $parts['query'] ?? '';
		if ( ! empty( $query ) ) {
			parse_str( $query, $query_params );
			if ( ! empty( $query_params['_embed'] ) ) {
				$embed_endpoints = explode( ',', $query_params['_embed'] );
				foreach ( $embed_endpoints as $embed_endpoint ) {
					foreach ( self::$embedded_routes as $prefix => $controller ) {
						if ( str_starts_with( $embed_endpoint, $prefix ) ) {
							$fevt_container->get( $controller )->register_routes();
						}
					}
				}
			}
		}
	}


	/**
	 * Try to set up the action-scheduler tasks.
	 *
	 * @since 2.0.3
	 * @since 3.0.0 Set/get options via Options class.
	 */
	public function try_setup_action_scheduler_tasks(): void {

		// Setup filters and actions to fine-tune the action-scheduler.
		add_filter( 'action_scheduler_retention_period', fn() => $this->settings->log_retention_days() * DAY_IN_SECONDS );
		add_filter( 'action_scheduler_queue_runner_time_limit', fn() => $this->settings->as_time_limit() );
		add_filter( 'action_scheduler_queue_runner_batch_size', fn() => $this->settings->as_batch_size() );
		add_filter( 'action_scheduler_queue_runner_concurrent_batches', fn() => $this->settings->as_concurrent_batches() );
		add_filter( 'action_scheduler_default_cleaner_statuses', fn( $statuses ) => array( ...$statuses, ActionScheduler_Store::STATUS_FAILED ) );
		add_action( 'action_scheduler_run_queue', array( $this, 'aswh_request_additional_runners' ), 0 );
		add_action( 'wp_ajax_nopriv_aswh_create_additional_runners', array( $this, 'aswh_create_additional_runners' ), 0 );

		if ( ! $this->options->is_as_initialized() && ActionScheduler::is_initialized() ) {

			// Schedule recurring clean-up tasks for expired log-entries and free format emails.
			if ( ! as_has_scheduled_action( 'fast_events_action_clean_cache' ) ) {
				as_schedule_recurring_action( time(), DAY_IN_SECONDS, 'fast_events_action_clean_cache' );
			}

			// Was the management interface already installed?
			if ( ! empty( $this->options->get_management_settings() ) ) {
				if ( ! as_has_scheduled_action( 'fast_events_action_update_web' ) ) {
					as_schedule_recurring_action( time(), DAY_IN_SECONDS, 'fast_events_action_update_web' );
				}
			}
			$this->options->set_as_initialized();
		}
	}


	/**
	 * Add additional runners to the Action Scheduler.
	 *
	 * @since 1.0
	 */
	public function aswh_request_additional_runners(): void {
		$extra_runners = $this->settings->as_additional_runners();
		if ( 0 === $extra_runners ) {
			return;
		}

		// Allow self-signed SSL certificates.
		add_filter( 'https_local_ssl_verify', '__return_false', 100 );

		for ( $i = 0; $i < $extra_runners; $i++ ) {
			wp_remote_post(
				admin_url( 'admin-ajax.php' ),
				array(
					'method'      => 'POST',
					'timeout'     => 45,
					'redirection' => 5,
					'httpversion' => '1.0',
					'blocking'    => false,
					'headers'     => array(),
					'body'        => array(
						'action'     => 'aswh_create_additional_runners',
						'instance'   => $i,
						'aswh_nonce' => wp_create_nonce( 'aswh_additional_runner_' . $i ),
					),
					'cookies'     => array(),
				)
			);
		}
	}


	/**
	 * Handle request for additional runners to the Action Scheduler.
	 *
	 * @since 1.0
	 */
	#[NoReturn]
	public function aswh_create_additional_runners(): void {

		if ( isset( $_POST['aswh_nonce'] ) &&
			isset( $_POST['instance'] ) &&
			wp_verify_nonce(
				sanitize_text_field( wp_unslash( $_POST['aswh_nonce'] ) ),
				'aswh_additional_runner_' . sanitize_text_field( wp_unslash( $_POST['instance'] ) )
			) ) {
			ActionScheduler_QueueRunner::instance()->run();
		}
		wp_die();
	}


	/**
	 * WordPress version requirement notice
	 *
	 * @since 1.0 Minimum version WordPress 5.6
	 * @since 1.4 Minimum version WordPress 6.0
	 * @since 2.4.0 Minimum version WordPress 6.4
	 */
	public function required_wp_version(): void {
		?>
		<div class="error">
			<p>
				<?php esc_html_e( 'Fast Events needs WordPress 6.4 or higher.', 'fast-events' ); ?>
			</p>
			<p>
				<a href="https://wordpress.org/download/">Update WordPress</a>
			</p>
		</div>
		<?php
	}


	/**
	 * PHP version requirement notice
	 *
	 * @since 1.0   Minimum version PHP 7.4
	 * @since 1.4   Minimum version PHP 8.0
	 * @since 3.0   Minimum version PHP 8.1
	 */
	public function required_php_version(): void {
		?>
		<div class="error">
			<p>
				<?php esc_html_e( 'Fast Events needs PHP version 8.1 or higher.', 'fast-events' ); ?>
			</p>
			<p>
				<a href="https://wordpress.org/support/update-php/">Update PHP</a>
			</p>
		</div>
		<?php
	}


	/**
	 * Handles version checking and upgrade tasks.
	 *
	 * @since 1.0
	 * @since 3.0.0 Move code to a separate class.
	 */
	public function check_for_upgrade(): void {
		global $fevt_container;

		$installed_version = $this->options->get_plugin_version();

		// Installed version lower than the plugin version?
		if ( version_compare( $installed_version, self::FAST_EVENTS_VERSION, '<' ) ) {

			if ( $installed_version ) {
				$upgrading = $fevt_container->get( Upgrade::class );
				$upgrading->upgrade( $installed_version );
			}

			// New version number.
			$this->options->set_plugin_version( self::FAST_EVENTS_VERSION );
		}
	}


	/**
	 * Single and multi-site activation
	 *
	 * @since 1.0
	 * @since 2.0.3 Using restore_current_blog
	 *
	 * @param bool $network_wide Only for multi-site: is it a networkwide activation.
	 */
	public function fast_events_activate( bool $network_wide ): void {
		if ( ! current_user_can( 'activate_plugins' ) ) {
			return;
		}

		if ( is_multisite() && $network_wide ) {
			foreach ( get_sites( array( 'fields' => 'ids' ) ) as $site_id ) {
				switch_to_blog( $site_id );
				$this->fast_events_execute_activate();
				restore_current_blog();
			}
		} else {
			$this->try_setup_action_scheduler_tasks();
			$this->fast_events_execute_activate();
		}
	}


	/**
	 * Create tables, demo data and fast-events uploads folder.
	 *
	 * @since 1.0
	 */
	public function fast_events_execute_activate(): void {
		require_once ABSPATH . 'wp-admin/includes/upgrade.php';
		dbDelta( Activation::get_db_schema() );

		// Check if the demo data is installed.
		if ( ! $this->options->is_demo_data_installed() ) {
			$this->options->set_plugin_settings( SettingsDefaults::default_settings() );
			$post_ids = Activation::install_demo_data();
			$this->options->demo_data_installed();
			$this->options->save_post_ids( $post_ids );
		}
	}


	/**
	 * Single and multi site de-activation
	 *
	 * @since 1.0
	 * @since 2.0.3 Using restore_current_blog
	 *
	 * @param bool $network_wide Only for multi-site: Is this a network-activated plugin.
	 */
	public function fast_events_deactivate( bool $network_wide ): void {
		if ( ! current_user_can( 'activate_plugins' ) ) {
			return;
		}

		if ( is_multisite() && $network_wide ) {
			foreach ( get_sites( array( 'fields' => 'ids' ) ) as $site_id ) {
				switch_to_blog( $site_id );
				$this->fast_events_execute_deactivate();
				restore_current_blog();
			}
		} else {
			$this->fast_events_execute_deactivate();
		}
	}


	/**
	 * Deactivation of the blog. We leave everything alive except for the schedules tasks.
	 * The plugin delete will remove everything else.
	 *
	 * @since 1.0
	 * @since 2.0 Remove scheduled tasks.
	 */
	public function fast_events_execute_deactivate(): void {
		global $wpdb;

		// Delete possible free format email messages.
		$wpdb->get_results( "DELETE FROM $wpdb->options WHERE option_name LIKE 'fast_events_email_msg_%'" );

		$tablename = $wpdb->prefix . 'actionscheduler_actions';
		if ( $wpdb->get_var( "SHOW TABLES LIKE '$tablename'" ) === $tablename ) { //phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			as_unschedule_all_actions( 'fast_events_action_send_mail' );
			as_unschedule_all_actions( 'fast_events_action_clean_cache' );
			as_unschedule_all_actions( 'fast_events_action_confirmation_timeout' );
			as_unschedule_all_actions( 'fast_events_action_payment_expire' );
			as_unschedule_all_actions( 'fast_events_action_update_web' );
			as_unschedule_all_actions( 'fast_events_action_webhook' );
		}
		$this->options->delete_as_initialized();
	}


	/**
	 * Trigger the creation of the fast-events tables of the designated blog
	 *
	 * @since 1.0
	 * @since 2.0.3 Use a new hook
	 *
	 * @param WP_Site $new_site  The new site WP_Site object.
	 */
	public function new_blog( WP_Site $new_site ): void {

		if ( is_plugin_active_for_network( 'fast-events/fast-events.php' ) ) {
			switch_to_blog( $new_site->id );
			$this->fast_events_execute_activate();
			restore_current_blog();
		}
	}


	/**
	 * Trigger deletion of the fast-event tables and settings of the designated blog
	 *
	 * @since 1.0
	 * @since 2.0.3 Use a new hook
	 * @since 2.2.0 Drop coupons table
	 *
	 * @param WP_Site $old_site The old site WP_Site object.
	 */
	public function delete_blog( WP_Site $old_site ): void {
		global $wpdb;

		if ( is_plugin_active_for_network( 'fast-events/fast-events.php' ) ) {
			switch_to_blog( $old_site->id );

			$this->fast_events_execute_deactivate();

			// Delete the tables.
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_entries" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_qrcodes" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_orders" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_events" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_seats" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_user_groups" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_webhooks" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_log" );
			$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}fe_event_coupons" );

			// Delete fast-events (sub)accounts.
			$users = get_users( array( 'role' => 'fe_account' ) );
			foreach ( $users as $user ) {
				wpmu_delete_user( $user->ID );
			}

			restore_current_blog();
		}
	}


	/**
	 * The superadmin can set a site status to deactivated, archived, or spam.
	 * All scheduled actions will be cancelled, and any free format email in the cache will be removed as well.
	 *
	 * @since 2.0.3
	 *
	 * @param int $site_id The unique id of the site.
	 */
	public function set_site_status( int $site_id ): void {
		switch_to_blog( $site_id );
		$this->fast_events_execute_deactivate();
		restore_current_blog();
	}


	/**
	 * The superadmin can unset a site status to activated, not spam, or unarchived.
	 * We will do a new activation forcing a db-upgrade check if the demo stuff is installed and try to set the cache cleaner.
	 *
	 * @since 2.0.3
	 *
	 * @param int $site_id The unique id of the site.
	 */
	public function unset_site_status( int $site_id ): void {
		switch_to_blog( $site_id );
		$this->fast_events_execute_activate();
		$this->try_setup_action_scheduler_tasks();
		restore_current_blog();
	}
}
