<?php
/**
 * Guardian Shield — Uninstall Script
 *
 * WordPress calls this file directly (not via hooks) when an administrator
 * clicks "Delete" on the Plugins screen.  It is executed with full WordPress
 * bootstrap, so $wpdb and all WP functions are available.
 *
 * WHAT THIS FILE DOES
 * ──────────────────────────────────────────────
 * 1. Verifies the uninstall was initiated by WordPress (not a direct HTTP hit).
 * 2. Respects the "remove data on uninstall" option the admin can set in
 *    Guardian Shield → Settings → Advanced.  If the option is off the DB
 *    tables and options are left intact so they survive a reinstall.
 * 3. If removal is authorised:
 *    - Drops all six custom database tables.
 *    - Deletes all `gs_*` wp_options rows.
 *    - Clears all `gs_*` transients.
 *    - Removes the log and quarantine directories (best-effort).
 *    - Clears any scheduled cron events added by the plugin.
 *
 * @package GuardianShield
 * @since   1.0.0
 */

// ── Safety: abort if called directly (not by WP uninstall machinery) ──────────
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
	exit;
}

// ── Load the plugin constants so we can reference paths & option names ────────
if ( ! defined( 'GS_VERSION' ) ) {
	// Minimal constants — the main file won't be loaded during uninstall.
	define( 'GS_LOG_DIR',      WP_CONTENT_DIR . '/gs-logs/'       );
	define( 'GS_QUARANTINE',   WP_CONTENT_DIR . '/gs-quarantine/' );
}

global $wpdb;

// ── Respect the admin's preference ────────────────────────────────────────────
$remove_data = get_option( 'gs_remove_data_on_uninstall', false );

if ( ! $remove_data ) {
	// Leave all data intact — admin wants to preserve logs & settings on reinstall.
	return;
}

// ── 1. Drop custom tables ─────────────────────────────────────────────────────
$tables = [
	'gs_attack_logs',
	'gs_login_attempts',
	'gs_file_hashes',
	'gs_firewall_events',
	'gs_ip_rules',
	'gs_scan_results',
];

foreach ( $tables as $table ) {
	// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
	$wpdb->query( "DROP TABLE IF EXISTS `{$wpdb->prefix}{$table}`" );
}

// ── 2. Delete all plugin options ──────────────────────────────────────────────
// Options whose names are known at install time:
$known_options = [
	'gs_db_version',
	'gs_activation_hash',
	'gs_secret_key',
	'gs_enable_firewall',
	'gs_enable_rate_limiting',
	'gs_enable_bot_detection',
	'gs_enable_login_security',
	'gs_enable_2fa_hooks',
	'gs_enable_login_url_hiding',
	'gs_custom_login_slug',
	'gs_max_login_attempts',
	'gs_lockout_duration',
	'gs_session_ip_lock',
	'gs_block_xmlrpc',
	'gs_rate_limit_xmlrpc',
	'gs_block_rest_for_guests',
	'gs_enable_security_headers',
	'gs_csp_policy',
	'gs_enable_hsts',
	'gs_hsts_max_age',
	'gs_enable_file_monitoring',
	'gs_monitor_core',
	'gs_monitor_plugins',
	'gs_monitor_themes',
	'gs_enable_malware_scanner',
	'gs_scan_frequency',
	'gs_auto_quarantine',
	'gs_send_email_alerts',
	'gs_alert_email',
	'gs_alert_on_brute_force',
	'gs_alert_on_malware',
	'gs_alert_on_file_change',
	'gs_alert_on_critical_attack',
	'gs_cloudflare_mode',
	'gs_geoip_block_enabled',
	'gs_geoip_blocked_countries',
	'gs_remove_data_on_uninstall',
];

foreach ( $known_options as $option ) {
	delete_option( $option );
	delete_site_option( $option ); // Multisite safety.
}

// Also sweep for any dynamically-created gs_ options:
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$dynamic_options = $wpdb->get_col(
	"SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE 'gs\_%'"
);
foreach ( (array) $dynamic_options as $opt ) {
	delete_option( $opt );
}

// ── 3. Clear transients ───────────────────────────────────────────────────────
// Transients follow the pattern _transient_gs_* and _transient_timeout_gs_*
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$wpdb->query(
	"DELETE FROM {$wpdb->options}
	 WHERE option_name LIKE '\_transient\_gs\_%'
	    OR option_name LIKE '\_transient\_timeout\_gs\_%'"
);

// Multisite object cache may hold these; flush what we can:
if ( function_exists( 'wp_cache_flush_group' ) ) {
	wp_cache_flush_group( 'guardian_shield' );
}

// ── 4. Clear user meta added by the plugin ───────────────────────────────────
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$wpdb->query(
	"DELETE FROM {$wpdb->usermeta}
	 WHERE meta_key LIKE '\_gs\_%'"
);

// ── 5. Clear scheduled cron events ────────────────────────────────────────────
$cron_hooks = [
	'gs_scheduled_malware_scan',
	'gs_scheduled_integrity_check',
	'gs_cleanup',
];

foreach ( $cron_hooks as $hook ) {
	$timestamp = wp_next_scheduled( $hook );
	if ( $timestamp ) {
		wp_unschedule_event( $timestamp, $hook );
	}
	wp_clear_scheduled_hook( $hook );
}

// ── 6. Remove log & quarantine directories ────────────────────────────────────
/**
 * Recursively delete a directory and its contents.
 *
 * @param string $dir Absolute filesystem path.
 */
function gs_uninstall_rmdir( string $dir ): void {
	if ( ! is_dir( $dir ) ) {
		return;
	}

	$items = new RecursiveIteratorIterator(
		new RecursiveDirectoryIterator( $dir, FilesystemIterator::SKIP_DOTS ),
		RecursiveIteratorIterator::CHILD_FIRST
	);

	foreach ( $items as $item ) {
		if ( $item->isDir() ) {
			@rmdir( $item->getRealPath() );
		} else {
			@unlink( $item->getRealPath() );
		}
	}

	@rmdir( $dir );
}

$log_dir       = defined( 'GS_LOG_DIR' )    ? GS_LOG_DIR    : WP_CONTENT_DIR . '/gs-logs/';
$quarantine    = defined( 'GS_QUARANTINE' ) ? GS_QUARANTINE : WP_CONTENT_DIR . '/gs-quarantine/';

gs_uninstall_rmdir( $log_dir );
gs_uninstall_rmdir( $quarantine );

// ── Done ──────────────────────────────────────────────────────────────────────
// All Guardian Shield data has been purged.  The plugin is now fully removed.
