<?php
/**
 * Cleanup when the SimpleStats plugin is deleted from WordPress.
 *
 * @package SimpleStats
 */

defined( 'WP_UNINSTALL_PLUGIN' ) || exit;

/**
 * Remove every SimpleStats artifact belonging to the current site.
 *
 * Options and transients live in the per-site options table, so this runs once
 * per site on multisite (see the switch_to_blog() loop below). User meta is
 * global, so clearing it repeatedly is harmless.
 *
 * @return void
 */
function simplestats_uninstall_site() {
	global $wpdb;

	delete_option( 'simplestats_connection' );
	delete_option( 'simplestats_settings' );
	delete_option( 'simplestats_installation_id' );
	delete_option( 'simplestats_notifications' );
	delete_option( 'simplestats_notifications_run' );

	// Fixed-name transients.
	delete_transient( 'simplestats_activation_redirect' );
	delete_transient( 'simplestats_connect_token' );

	/*
	 * Prefixed transients. The keys are unbounded — report transients are keyed
	 * on the date range, validation on a hash of the api_key, form dedup on a
	 * hash of the visitor session and the throttle on a hash of the remote
	 * address — so there is no list to iterate. A prefix DELETE on the options
	 * table is the only complete path.
	 *
	 * esc_like() so the underscores in the prefix are matched literally rather
	 * than as single-character LIKE wildcards.
	 */
	// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange
	$wpdb->query(
		$wpdb->prepare(
			"DELETE FROM {$wpdb->options}
			 WHERE option_name LIKE %s
			    OR option_name LIKE %s",
			$wpdb->esc_like( '_transient_simplestats_' ) . '%',
			$wpdb->esc_like( '_transient_timeout_simplestats_' ) . '%'
		)
	);
}

// Per-admin half-finished signup stashes. User meta is network-wide, so this is
// done once rather than inside the per-site loop.
delete_metadata( 'user', 0, 'simplestats_pending_signup', '', true );

if ( ! is_multisite() ) {
	simplestats_uninstall_site();

	return;
}

/*
 * uninstall.php runs ONCE for the whole network, in the context of whichever
 * site initiated the delete — it is not re-entered per site. Without this loop
 * every other site's options and transients were left behind forever.
 *
 * Large networks are skipped: iterating tens of thousands of sites inside a
 * plugin-delete request would time out, and leaving a few rows behind beats
 * taking the network down. Those sites keep their (inert) options.
 */
if ( wp_is_large_network() ) {
	simplestats_uninstall_site();

	return;
}

$simplestats_site_ids = get_sites( array(
	'fields'   => 'ids',
	'number'   => 0,
	'archived' => null,
	'deleted'  => null,
	'spam'     => null,
) );

foreach ( $simplestats_site_ids as $simplestats_site_id ) {
	switch_to_blog( $simplestats_site_id );
	simplestats_uninstall_site();
	restore_current_blog();
}
