<?php
/**
 * Uninstall cleanup for Mail Doctor.
 *
 * @package MailDoctor
 */

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

if ( ! defined( 'MAIL_DOCTOR_PATH' ) ) {
	define( 'MAIL_DOCTOR_PATH', plugin_dir_path( __FILE__ ) );
}

require_once __DIR__ . '/includes/support/helpers.php';
require_once __DIR__ . '/includes/mail/retry/class-mail-doctor-retry.php';
require_once __DIR__ . '/includes/integrations/class-mail-doctor-woocommerce.php';
require_once __DIR__ . '/includes/core/class-mail-doctor-logger.php';
require_once __DIR__ . '/includes/services/class-mail-doctor-profiles.php';
require_once __DIR__ . '/includes/services/class-mail-doctor-suppression.php';
require_once __DIR__ . '/includes/support/class-mail-doctor-capabilities.php';

$mail_doctor_optional_files = array(
	__DIR__ . '/includes/mail/alerts/class-mail-doctor-alerts.php',
	__DIR__ . '/includes/services/class-mail-doctor-rate-limiter.php',
);

foreach ( $mail_doctor_optional_files as $mail_doctor_optional_file ) {
	if ( file_exists( $mail_doctor_optional_file ) ) {
		require_once $mail_doctor_optional_file;
	}
}

use MailDoctor\Helpers\Migrations;
use MailDoctor\Retry;
use MailDoctor\Woo;
use MailDoctor\Alerts;
use MailDoctor\Logger;
use MailDoctor\Profiles;
use MailDoctor\RateLimiter;
use MailDoctor\Suppression;
use MailDoctor\Capabilities;

if ( ! function_exists( 'mail_doctor_delete_option_like' ) ) {
	/**
	 * Delete option rows matching a given prefix.
	 *
	 * @param string $prefix Option name prefix (without wildcard symbol).
	 * @return void
	 */
	function mail_doctor_delete_option_like( string $prefix ): void {
		global $wpdb;

		if ( empty( $wpdb->options ) ) {
			return;
		}

		$like = $wpdb->esc_like( $prefix ) . '%';

		// Direct query required: WordPress provides no function to delete options by prefix pattern.
		// Query is properly prepared with $wpdb->prepare() for security.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
				$like
			)
		);
	}
}

if ( ! function_exists( 'mail_doctor_cleanup_site' ) ) {
	/**
	 * Perform per-site uninstall cleanup.
	 *
	 * @return void
	 */
	function mail_doctor_cleanup_site(): void {
		global $wpdb;

		Retry::deactivate();
		Logger::deactivate();
		if ( class_exists( Alerts::class ) && method_exists( Alerts::class, 'deactivate' ) ) {
			Alerts::deactivate();
		}

		if ( function_exists( 'as_unschedule_all_actions' ) ) {
			as_unschedule_all_actions( 'mail_doctor_async_send', null, 'maildoctor' );
		}

		if ( class_exists( RateLimiter::class ) ) {
			delete_transient( RateLimiter::TRANSIENT_WINDOW );
			delete_transient( RateLimiter::TRANSIENT_HOLD );
		}
		delete_transient( 'mail_doctor_fallback_notice' );
		delete_transient( 'mail_doctor_oauth_notice' );

		foreach ( array( 1, 7, 30 ) as $days ) {
			delete_transient( 'mail_doctor_metrics_' . $days );
		}

		mail_doctor_delete_option_like( '_transient_mail_doctor_' );
		mail_doctor_delete_option_like( '_transient_timeout_mail_doctor_' );
		mail_doctor_delete_option_like( '_site_transient_mail_doctor_' );
		mail_doctor_delete_option_like( '_site_transient_timeout_mail_doctor_' );

		$settings       = get_option( 'mail_doctor_settings', array() );
		$should_cleanup = ! empty( $settings['cleanup_on_uninstall'] );

		if ( ! $should_cleanup ) {
			return;
		}

		delete_option( 'mail_doctor_settings' );
		delete_option( Woo::TOGGLE_OPTION );
		if ( class_exists( Alerts::class ) ) {
			delete_option( Alerts::OPTION_STATE );
		}
		delete_option( 'mail_doctor_settings' );
		delete_option( 'mail_doctor_onboarding' );
		delete_option( 'mail_doctor_api_keys' );
		delete_option( Migrations::OPTION_VERSION );

		mail_doctor_delete_option_like( 'mail_doctor_secret_' );

		$tables = array(
			Logger::table_name(),
			Logger::archive_table_name(),
			Profiles::table_name(),
			Suppression::table_name(),
		);

		$like              = $wpdb->esc_like( $wpdb->prefix . 'mail_doctor_' ) . '%';

		// Direct query required: WordPress provides no function to discover tables by name pattern.
		// Query is properly prepared with $wpdb->prepare() for security.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$discovered_tables = $wpdb->get_col(
			$wpdb->prepare(
				'SHOW TABLES LIKE %s',
				$like
			)
		);

		if ( is_array( $discovered_tables ) ) {
			$tables = array_merge( $tables, $discovered_tables );
		}

		$tables = array_unique( array_filter( $tables ) );

		foreach ( $tables as $table ) {
			$safe_table = esc_sql( $table );

			// Direct query required: WordPress provides no function to drop custom tables.
			// Table name is sanitized with esc_sql() and backtick-quoted for safety.
			// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
			$wpdb->query( "DROP TABLE IF EXISTS `{$safe_table}`" );
		}

		$roles        = array( 'administrator', 'shop_manager' );
		$capabilities = Capabilities::all();

		foreach ( $roles as $role_key ) {
			$role = get_role( $role_key );

			if ( ! $role ) {
				continue;
			}

			foreach ( $capabilities as $capability ) {
				if ( $role->has_cap( $capability ) ) {
					$role->remove_cap( $capability );
				}
			}
		}
	}
}

$mail_doctor_site_ids = array( get_current_blog_id() );

if ( is_multisite() ) {
	$mail_doctor_site_ids = get_sites(
		array(
			'fields' => 'ids',
			'number' => 0,
		)
	);
}

foreach ( $mail_doctor_site_ids as $mail_doctor_site_id ) {
	if ( is_multisite() ) {
		switch_to_blog( (int) $mail_doctor_site_id );
	}

	mail_doctor_cleanup_site();

	if ( is_multisite() ) {
		restore_current_blog();
	}
}

if ( is_multisite() ) {
	delete_site_option( 'mail_doctor_network_defaults' );
}
