<?php
/**
 * NimblyMail Uninstall
 *
 * Removes all plugin data when the plugin is deleted (not deactivated).
 * Only runs if the user has opted in via Settings → Misc → Remove Data on Uninstall.
 * On multisite the network opt-in flag (network options) is honored, and every
 * sub-site's per-site data is cleaned up in turn.
 *
 * @package NimblyMail\SMTP
 */

defined( 'WP_UNINSTALL_PLUGIN' ) || exit;

/**
 * Whether the user has opted in to data removal on uninstall.
 *
 * On multisite, checks the network options first; otherwise falls back to the
 * per-site option so a sub-site that opted in still gets its data removed.
 *
 * @since 1.0.0
 *
 * @return bool
 */
function nimblymail_uninstall_opted_in(): bool {
    if ( is_multisite() ) {
        $network = get_site_option( 'nimblymail_network_options', array() );
        if ( ! empty( $network['general']['uninstall_data'] ) ) {
            return true;
        }
    }

    $options = get_option( 'nimblymail_options', array() );
    return ! empty( $options['general']['uninstall_data'] );
}

if ( ! nimblymail_uninstall_opted_in() ) {
    return;
}

/**
 * Remove all per-site NimblyMail data for the current blog.
 *
 * Drops the logs table, deletes site options, clears the cron schedule,
 * and removes regular transients. Safe to call from inside a
 * switch_to_blog() context.
 *
 * @since 1.0.0
 * @since 1.0.2 Also removes the decrypt-failure flag, OAuth refresh locks,
 *              health-audit state, review-request install stamp, the
 *              recurring health-audit action, and pending review-request
 *              actions.
 * @since 1.0.3 Also removes the conflict-check flag, now a plain option
 *              rather than a transient so it isn't caught by the transient
 *              wildcard delete below, and the fulltext-index-available flag
 *              added for log search.
 * @since 1.0.4 Also cancels the network-dashboard stats chunk action so an
 *              in-flight chunked run does not outlive the plugin, and removes
 *              the rotation-configured marker so a reinstall doesn't skip the
 *              default log-retention floor.
 *
 * @return void
 */
function nimblymail_uninstall_cleanup_site(): void {
    global $wpdb;

    delete_option( 'nimblymail_options' );
    delete_option( 'nimblymail_db_version' );
    delete_option( 'nimblymail_wizard_redirect_done' );
    delete_option( 'nimblymail_wizard_completed' );
    delete_option( 'nimblymail_decrypt_failure' );
    delete_option( 'nimblymail_gmail_refresh_lock' );
    delete_option( 'nimblymail_outlook_refresh_lock' );
    delete_option( 'nimblymail_health_snapshot' );
    delete_option( 'nimblymail_health_last_alert' );
    delete_option( 'nimblymail_review_installed_at' );
    delete_option( 'nimblymail_conflict_check' );
    delete_option( 'nimblymail_fulltext_index_available' );
    delete_option( 'nimblymail_rotation_configured' );

    // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange
    $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'nimblymail_logs' );

    // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange
    $wpdb->query( 'DROP TABLE IF EXISTS ' . $wpdb->prefix . 'nimblymail_queue' );

    delete_option( 'nimblymail_queue_db_version' );

    if ( function_exists( 'as_unschedule_all_actions' ) ) {
        as_unschedule_all_actions( 'nimblymail_log_rotation', array(), 'nimblymail-smtp' );
        as_unschedule_all_actions( 'nimblymail_process_queue_item', array(), 'nimblymail-smtp' );
        as_unschedule_all_actions( 'nimblymail_health_audit_run', array(), 'nimblymail-smtp-audit' );
        as_unschedule_all_actions( 'nimblymail_review_request_show', array(), 'nimblymail-smtp' );
        as_unschedule_all_actions( 'nimblymail_network_stats_chunk', array(), 'nimblymail-smtp' );
    }

    $transient_like         = $wpdb->esc_like( '_transient_nimblymail_' ) . '%';
    $transient_timeout_like = $wpdb->esc_like( '_transient_timeout_nimblymail_' ) . '%';

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $wpdb->query(
        $wpdb->prepare(
            'DELETE FROM ' . $wpdb->options
            . ' WHERE option_name LIKE %s OR option_name LIKE %s',
            $transient_like,
            $transient_timeout_like
        )
    );
}

/**
 * Run per-site cleanup across every blog on a multisite network and remove the
 * network-scoped options.
 *
 * Wraps the loop in a function so its iteration variables don't sit at the
 * file scope as plugin-global variables (per WordPress.NamingConventions
 * .PrefixAllGlobals).
 *
 * @since 1.0.0
 * @since 1.0.4 Also removes the in-progress network stats accumulation
 *              transient alongside the finished snapshot, sweeps the cached
 *              pages of the network site list (whose names vary by page and
 *              so cannot be removed one by one like the ones above), and
 *              removes the network-level rotation-configured marker.
 *
 * @return void
 */
function nimblymail_uninstall_cleanup_network(): void {
    global $wpdb;

    $blog_ids = get_sites(
        array(
            'number' => 0,
            'fields' => 'ids',
        )
    );

    foreach ( $blog_ids as $blog_id ) {
        switch_to_blog( (int) $blog_id );
        nimblymail_uninstall_cleanup_site();
        restore_current_blog();
    }

    delete_site_option( 'nimblymail_network_options' );
    delete_site_option( 'nimblymail_rotation_configured_network' );
    delete_site_transient( 'nimblymail_should_run_wizard' );
    delete_site_transient( 'nimblymail_network_stats' );
    delete_site_transient( 'nimblymail_network_stats_progress' );

    // Each cached page of the network site list is stored under a name that
    // varies by page number and page size, so they cannot be enumerated and
    // removed by name like the fixed ones above. Sweep them by prefix
    // instead, the same way per-site cached values are swept above.
    $site_transient_like         = $wpdb->esc_like( '_site_transient_nimblymail_network_sites_' ) . '%';
    $site_transient_timeout_like = $wpdb->esc_like( '_site_transient_timeout_nimblymail_network_sites_' ) . '%';

    // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
    $wpdb->query(
        $wpdb->prepare(
            'DELETE FROM ' . $wpdb->sitemeta
            . ' WHERE meta_key LIKE %s OR meta_key LIKE %s',
            $site_transient_like,
            $site_transient_timeout_like
        )
    );
}

if ( is_multisite() ) {
    nimblymail_uninstall_cleanup_network();
} else {
    nimblymail_uninstall_cleanup_site();
}

// User meta is global to the user (not per-site), so clean up once.
delete_metadata( 'user', 0, 'nimblymail_conflict_dismissed', '', true );
delete_metadata( 'user', 0, 'nimblymail_import_notice_dismissed', '', true );
delete_metadata( 'user', 0, 'nimblymail_review_request', '', true );
