<?php
/**
 * Speed in China — uninstall cleanup (single source of truth).
 *
 * NOT a WordPress `uninstall.php`, deliberately. Freemius's uploader REJECTS
 * any plugin ZIP containing one, and WP core's uninstall_plugin() includes
 * uninstall.php and RETURNS — which would stop Freemius's own registered
 * uninstall callback (and its `after_uninstall` action) from ever running.
 *
 * The cleanup therefore lives in this ordinary shipped include and is invoked
 * from the `after_uninstall` callback registered in speed-in-china.php right
 * after the Freemius SDK is initialised. Prior to 1.0.2 this logic shipped as
 * a root uninstall.php; the release engine now strips that file, so it was
 * ported here to keep the "no zombie data after uninstall" behaviour.
 *
 * Removes options, transients, per-user meta flags, PRO cron events and the
 * localized Google Fonts cache directory. Nothing else.
 *
 * @package SpeedInChina
 */

defined( 'ABSPATH' ) || exit;

if ( ! function_exists( 'speeinch_uninstall_cleanup' ) ) {
	/**
	 * Delete every piece of data the plugin writes.
	 *
	 * Safe to run from either the free or the premium build; PRO-only keys are
	 * simply no-ops (delete_option() on a missing key does nothing).
	 *
	 * @return void
	 */
	function speeinch_uninstall_cleanup() {
		// Delete plugin options.
		// NOTE: Keep this list in sync with every `add_option` / `update_option`
		// call across the plugin. The Google Fonts option key is the public
		// SPEEINCH_Google_Fonts::OPTION_ENABLED constant — we hard-code the value
		// here because the class may not be loaded at uninstall time.
		$speeinch_options_to_delete = array(
			// Free + PRO shared options.
			'speeinch_manual_api_run',
			'speeinch_manual_api_run_last',
			'speeinch_speed_test_history',
			'speeinch_localize_google_fonts',
			'speeinch_analysis_results',
			// PRO options — harmless in the free build (delete_option is a no-op
			// when the key does not exist), kept here so a downgrade from PRO → free
			// → uninstall sweep leaves nothing behind.
			'speeinch_cron_on',
			'speeinch_cron_schedule',
			'speeinch_cron_log',
			'speeinch_globalping_token',
			'speeinch_current_plan',
			'speeinch_last_plan_action',
			'speeinch_admin_bar_status',
			'speeinch_schedule_enabled',
			'speeinch_schedule_frequency',
			'speeinch_schedule_next_run',
		);

		foreach ( $speeinch_options_to_delete as $speeinch_option ) {
			delete_option( $speeinch_option );
		}

		// Delete per-site transients. Direct query is unavoidable here — uninstall runs
		// once, per-option deletion would issue 2N queries with N transients of unknown count.
		global $wpdb;
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall context, one-shot transient sweep.
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s",
				'_transient_speeinch_%',
				'_transient_timeout_speeinch_%'
			)
		);

		// Delete the PRO cron-log option series (`speeinch_cron_log-<id>`).
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall context.
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM $wpdb->options WHERE option_name LIKE %s",
				'speeinch_cron_log-%'
			)
		);

		// Delete legacy `china_speed_*` transients (older PRO notification cache key).
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall context.
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s",
				'_transient_china_speed_%',
				'_transient_timeout_china_speed_%'
			)
		);

		// Delete multisite site-transients (stored in sitemeta, separate from options).
		if ( is_multisite() && isset( $wpdb->sitemeta ) ) {
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery,WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall context.
			$wpdb->query(
				$wpdb->prepare(
					"DELETE FROM {$wpdb->sitemeta} WHERE meta_key LIKE %s OR meta_key LIKE %s",
					'_site_transient_speeinch_%',
					'_site_transient_timeout_speeinch_%'
				)
			);
		}

		// Delete per-user dismiss flags for the anonymous-mode admin notice.
		delete_metadata( 'user', 0, 'speeinch_anonymous_notice_dismissed', '', true );

		// Delete per-user PRO notification-dismiss flag.
		delete_metadata( 'user', 0, 'china_speed_last_notification_id', '', true );

		// Unschedule any PRO cron events still on the schedule.
		$speeinch_cron_hooks = array( 'speeinch_cron_hook', 'speeinch_scheduled_speed_test' );
		foreach ( $speeinch_cron_hooks as $speeinch_hook ) {
			$speeinch_ts = wp_next_scheduled( $speeinch_hook );
			if ( $speeinch_ts ) {
				wp_unschedule_event( $speeinch_ts, $speeinch_hook );
			}
			wp_clear_scheduled_hook( $speeinch_hook );
		}

		// Delete the Google-Fonts local cache directory (created on demand under
		// wp-content/uploads/speeinch-fonts/). Use WP_Filesystem so the path
		// resolution honors any wp-content layout overrides and so PCP does not
		// flag direct unlink()/rmdir() calls.
		$speeinch_uploads = wp_upload_dir();
		if ( empty( $speeinch_uploads['error'] ) && ! empty( $speeinch_uploads['basedir'] ) ) {
			$speeinch_font_cache = trailingslashit( $speeinch_uploads['basedir'] ) . 'speeinch-fonts';
			if ( is_dir( $speeinch_font_cache ) ) {
				if ( ! function_exists( 'WP_Filesystem' ) ) {
					require_once ABSPATH . 'wp-admin/includes/file.php';
				}
				WP_Filesystem();
				global $wp_filesystem;
				if ( $wp_filesystem instanceof WP_Filesystem_Base ) {
					$wp_filesystem->delete( $speeinch_font_cache, true );
				}
			}
		}
	}
}
