<?php
/**
 * Uninstall cleanup.
 *
 * There is deliberately no uninstall.php. WordPress runs EITHER uninstall.php
 * OR the registered uninstall hook, never both — and when uninstall.php exists,
 * core actively DELETES the registered hook from the `uninstall_plugins` option
 * before running it (wp-admin/includes/plugin.php, uninstall_plugin()).
 * Shipping one would silently disable the Freemius SDK's uninstall handling,
 * which is why the Freemius deployment processor rejects a plugin that has one.
 *
 * Cleanup therefore hangs off Freemius's `after_uninstall` action. Because that
 * action does NOT fire when the SDK instance cannot be resolved, safety_net()
 * below registers on the core `uninstall_{basename}` hook as well, at a late
 * priority, and no-ops when the SDK path already cleaned up.
 *
 * @package SEO_Flight_Recorder
 */

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

/**
 * Class SFRec_Uninstall
 */
class SFRec_Uninstall {

	/**
	 * Has the cleanup already run this request? Both entry points may fire;
	 * only one should do the work.
	 *
	 * @var bool
	 */
	private static $done = false;

	/**
	 * Every option this plugin has ever written.
	 *
	 * @return string[]
	 */
	private static function options() {
		return array(
			'sfrec_settings',
			'sfrec_db_version',
			'sfrec_state',
			'sfrec_events',
			'sfrec_mutes',
			// Written only by the paid build's Pro layer; deleted here so
			// uninstalling the free copy leaves no residue. Never read here.
			'sfrec_pro_settings',
		);
	}

	/**
	 * The Freemius-sanctioned entry point: fires on `after_uninstall`.
	 */
	public static function run() {
		self::cleanup();
	}

	/**
	 * The belt-and-braces entry point on core's own uninstall hook.
	 *
	 * WordPress include_once's the plugin's main file before firing the
	 * uninstall hook, so this class is loadable with no dependency on the
	 * Freemius SDK being healthy. Late priority: the SDK's handler goes first.
	 */
	public static function safety_net() {
		if ( self::$done ) {
			return; // The SDK path already cleaned up.
		}
		self::cleanup();
	}

	/**
	 * The actual cleanup: own tables, options, transients, schedules.
	 */
	private static function cleanup() {
		self::$done = true;
		global $wpdb;

		$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}sfrec_changes" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- own table, uninstall.
		$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}sfrec_snapshots" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- own table, uninstall.
		$wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}sfrec_pages" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery -- own table, uninstall.

		foreach ( self::options() as $sfrec_option ) {
			delete_option( $sfrec_option );
		}

		foreach ( SFRec_Install::cron_hooks() as $sfrec_hook ) {
			wp_clear_scheduled_hook( $sfrec_hook );
		}

		$wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name LIKE '\_transient\_sfrec\_%' OR option_name LIKE '\_transient\_timeout\_sfrec\_%' OR option_name LIKE '\_site\_transient\_sfrec\_%' OR option_name LIKE '\_site\_transient\_timeout\_sfrec\_%'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery -- transient sweep at uninstall.
	}
}
