<?php
/**
 * Rank Forge — uninstall cleanup.
 *
 * Fired when the user clicks "Delete" on the Plugins screen, NOT on
 * deactivation. We drop the two Rank-Forge–owned tables, every option
 * we registered, every transient we cached, and every postmeta key
 * we stored on user content.
 *
 * To preserve data across an uninstall (e.g. for a planned reinstall
 * onto the same site), set:
 * update_option( 'rankforge_keep_data_on_uninstall', 1 );
 * before deleting the plugin.
 */

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

// Opt-out flag — read directly to avoid bootstrapping helper classes.
$rankforge_keep = (int) get_option( 'rankforge_keep_data_on_uninstall', 0 );
if ( $rankforge_keep === 1 ) {
    return;
}

global $wpdb;


// 1. Tables — only the two we actually create. (Forge_Queue is shared with
// the rest of the Forge Suite, so we leave its table alone.)

$rankforge_tables = [
    $wpdb->prefix . 'rankforge_analysis',
    $wpdb->prefix . 'rankforge_redirects',
];

foreach ( $rankforge_tables as $rankforge_table ) {
    // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; one-time uninstall cleanup
    $wpdb->query( "DROP TABLE IF EXISTS `{$rankforge_table}`" );
}


// 2. Options — explicit list of every key we ever set. Any key we miss
// here will linger as orphaned wp_options rows after uninstall.

$rankforge_options = [
    // Settings + state
    'rankforge_settings',
    'rankforge_default_og_image',
    'rankforge_brand_name',
    'rankforge_title_separator',
    'rankforge_title_templates',
    'rankforge_tax_templates',
    'rankforge_local_seo',
    'rankforge_sitemap_settings',
    'rankforge_robots_txt',
    'rankforge_archive_robots',
    'rankforge_posttype_robots',
    'rankforge_noindex_paginated',
    'rankforge_breadcrumbs',
    'rankforge_auto_links_enabled',
    'rankforge_auto_links_max',
    'rankforge_suppress_competitors',
    'rankforge_ab_advanced_acknowledged',
    'rankforge_site_audit_result',

    // Lifecycle / install metadata
    'rankforge_installed_at',
    'rankforge_previous_version',
    'rankforge_db_version',
    'rankforge_analysis_table_ver',
    'rankforge_redirects_table_ver',

    // Broken-links scanner state
    'rankforge_broken_links_batch_done',
    'rankforge_broken_links_batch_total',
    'rankforge_broken_links_last_scan',
    'rankforge_broken_links_scanning',
    'rankforge_broken_links_total_checked',

    // GSC integration tokens + cached metrics
    'rankforge_gsc_access_token',
    'rankforge_gsc_refresh_token',
    'rankforge_gsc_token_expires',
    'rankforge_gsc_property',
    'rankforge_gsc_client_id',
    'rankforge_gsc_client_secret',
    'rankforge_gsc_last_sync',
    'rankforge_gsc_decay_cache',
    'rankforge_gsc_rankings_cache',

    // License (plugin-side mirror; Freemius keeps its own copy under fs_*)
    'rankforge_license_data',
];

foreach ( $rankforge_options as $rankforge_option ) {
    delete_option( $rankforge_option );
    delete_site_option( $rankforge_option ); // multisite safety
}


// 3. Transients — name-prefix sweep is the only safe option here because
// several keys are dynamic ('rankforge_optimize_<hash>',
// 'rankforge_sitemap_<hash>', '_transient_rankforge_404_rl_<ip>'). We
// delete by prefix instead of enumerating known names.

// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; one-time uninstall cleanup
$wpdb->query(
    "DELETE FROM {$wpdb->options}
     WHERE option_name LIKE '\\_transient\\_rankforge\\_%'
        OR option_name LIKE '\\_transient\\_timeout\\_rankforge\\_%'"
);
// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, PluginCheck.Security.DirectDB.UnescapedDBParameter -- own table from $wpdb->prefix; one-time uninstall cleanup
$wpdb->query(
    "DELETE FROM {$wpdb->options}
     WHERE option_name LIKE '\\_site\\_transient\\_rankforge\\_%'
        OR option_name LIKE '\\_site\\_transient\\_timeout\\_rankforge\\_%'"
);


// 4. Postmeta — every key we wrote to user content. delete_post_meta_by_key
// uses an indexed query, so this is fast even on large sites.

$rankforge_postmeta_keys = [
    // Analyzer + meta overrides
    '_rankforge_analysis',
    '_rankforge_focus_keyword',
    '_rankforge_meta_title',
    '_rankforge_meta_description',
    '_rankforge_noindex',
    '_rankforge_nofollow',

    // Schema overrides
    '_rankforge_manual_schema',
    '_rankforge_ai_schema',
    '_rankforge_schema_type',

    // Social (OG / Twitter) per-post overrides
    '_rankforge_og_title',
    '_rankforge_og_description',
    '_rankforge_og_image',
    '_rankforge_og_image_id',
    '_rankforge_twitter_title',
    '_rankforge_twitter_description',

    // Robots.txt per-post override
    '_rankforge_robots_txt',

    // A/B testing meta
    '_rankforge_ab_enabled',
    '_rankforge_ab_title_b',
    '_rankforge_ab_desc_b',
    '_rankforge_ab_current',
    '_rankforge_ab_start',
    '_rankforge_ab_served_a',
    '_rankforge_ab_served_b',
    '_rankforge_ab_acknowledge',

    // Brief / video SEO / events / recipes / reviews
    '_rankforge_brief_history',
    '_rankforge_video_url',
    '_rankforge_video_thumbnail',
    '_rankforge_video_duration',
    '_rankforge_video_description',
    '_rankforge_video_embed_url',
    '_rankforge_videos',
    '_rankforge_event_start',
    '_rankforge_event_end',
    '_rankforge_event_address',
    '_rankforge_event_location',
    '_rankforge_recipe_ingredients',
    '_rankforge_recipe_total_time',
    '_rankforge_recipe_yield',
    '_rankforge_review_item',
    '_rankforge_review_rating',

    // Indexing API submission history
    '_rankforge_indexing_history',
];

foreach ( $rankforge_postmeta_keys as $rankforge_key ) {
    delete_metadata( 'post', 0, $rankforge_key, '', true );
}


// 5. Scheduled cron jobs — belt-and-suspenders. The deactivation hook
// already clears these, but uninstall can fire on a still-active plugin
// via WP-CLI, so re-clear here.

wp_clear_scheduled_hook( 'rankforge_daily_gsc_sync' );
wp_clear_scheduled_hook( 'rankforge_cron_scan_links' );
