<?php
// phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- template-scope variables injected by mbs_get_template_part(); not global vars
/**
 * File Path: uninstall.php
 *
 * My Book Showroom Uninstall
 *
 * Runs when the plugin is deleted (not deactivated).
 * Removes all plugin data.
 *
 */

// If uninstall not called from WordPress, exit.
if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
	exit;
}

// Revoke the mbs_book capabilities from the administrator role before any
// option/postmeta wipe. Loaded explicitly because the plugin autoloader is
// not registered during uninstall.
require_once plugin_dir_path( __FILE__ ) . 'includes/class-mbs-capabilities.php';
MBS_Capabilities::revoke_admin_caps();

global $wpdb;

// Drop custom tables.
// Note: table names are composed from $wpdb->prefix and a hardcoded string —
// no user input is involved, so $wpdb->prepare() is not applicable here.
// $wpdb->prefix is set by WordPress from the database configuration, not from
// user-supplied data.
$tables = array(
	// ── Per-book data tables (added in install + early migrations) ──────────
	'mbs_format_rows',
	'mbs_buy_links',
	'mbs_buy_link_clicks',        // INSIGHTS-1: click-tracking rows for buy links
	'mbs_endorsements',
	'mbs_section_order',
	'mbs_arc_recipients',
	'mbs_arc_applicants',         // F-027: public ARC signup applicants
	'mbs_arc_campaigns',          // migration 4.8: one row per book campaign
	'mbs_activity_log',
	'mbs_book_collection_positions',
	'mbs_book_club',
	'mbs_book_club_questions',
	'mbs_book_club_files',
	'mbs_related_products',       // F-020 Phase 8: ONIX product relations
	'mbs_book_contributors',      // F-020: replaces mbs_contributors
	'mbs_contributors',           // U-001: legacy table (pre-F-020 installs)

	// ── Single-row-per-book lookup tables (added in 4.x migrations) ─────────
	'mbs_book_classification_codes', // migration 4.6
	'mbs_book_awards',               // migration 4.7
	'mbs_book_meta',                 // migration 4.8
	'mbs_book_stats',                // migration 4.8/4.10
	'mbs_book_territorial_rights',   // migration 4.8/4.10

	// ── POS tables ───────────────────────────────────────────────────────────
	'mbs_pos_inventory',          // keyed by (location_id, format_row_id)
	'mbs_pos_locations',

	// ── Site-level cache / reference tables ──────────────────────────────────
	'mbs_pa_api_cache',           // PA-API ASIN price/rating cache
	'mbs_brand_feed_cache',       // DASH-2A brand feed cache
	'mbs_classification_codes',   // seeder reference table: BISAC/Thema/BIC codes
	'mbs_bisac_thema_map',        // seeder reference table: BISAC → Thema mapping
	'mbs_bic_thema_map',          // seeder reference table: BIC → Thema mapping

	// ── ARC / reading-order / ESP / RF-012 tables (added in 4.21–4.29 migrations) ──
	'mbs_arc_review_urls',         // R2-004: per-recipient review URLs
	'mbs_reading_order',           // R2-002: series reading-order rows
	'mbs_esp_queue',               // RF-011: ESP email queue
	'mbs_affiliate_stores',        // RF-012: affiliate store definitions
	'mbs_author_social_links',     // RF-012: author social-link rows
	'mbs_brand_feed_urls',         // RF-012: brand feed URL rows
);

foreach ( $tables as $table ) {
	$table_name = $wpdb->prefix . $table;
	$wpdb->query( "DROP TABLE IF EXISTS {$table_name}" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- DAO layer -- direct DB access is intentional per MBS architecture
}

// Delete all plugin options.
$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- DAO layer -- direct DB access is intentional per MBS architecture
	$wpdb->prepare(
		"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
		$wpdb->esc_like( 'mbs_' ) . '%'
	)
);

// Delete all postmeta for mbs_book posts.
// Subquery using $wpdb->posts is safe — no user input.
$wpdb->query( "DELETE FROM {$wpdb->postmeta} WHERE post_id IN (SELECT ID FROM {$wpdb->posts} WHERE post_type = 'mbs_book')" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- DAO layer -- direct DB access is intentional per MBS architecture

// Delete all mbs_book posts.
$wpdb->query( "DELETE FROM {$wpdb->posts} WHERE post_type = 'mbs_book'" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- DAO layer -- direct DB access is intentional per MBS architecture

// Delete taxonomy terms, relationships, and term_meta for all MBS taxonomies.
// U-003: wp_termmeta rows must be deleted before term_taxonomy rows are removed,
// because the termmeta DELETE relies on an INNER JOIN through term_taxonomy.
$taxonomies = array( 'mbs_author', 'mbs_series', 'mbs_genre', 'mbs_tag', 'mbs_collection', 'mbs_universe', 'mbs_theme', 'mbs_content_warning' );
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- U-003: remove termmeta/term_relationship/term/term_taxonomy rows; DAO layer; direct DB access per MBS architecture
foreach ( $taxonomies as $tax ) {
	$wpdb->query( $wpdb->prepare( "DELETE tm FROM {$wpdb->termmeta} tm INNER JOIN {$wpdb->term_taxonomy} tt ON tm.term_id = tt.term_id WHERE tt.taxonomy = %s", $tax ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall.php: direct query required; no cache to prime during plugin removal
	$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->term_relationships} WHERE term_taxonomy_id IN (SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy} WHERE taxonomy = %s)", $tax ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall.php: direct query required; no cache to prime during plugin removal
	$wpdb->query( $wpdb->prepare( "DELETE t FROM {$wpdb->terms} t INNER JOIN {$wpdb->term_taxonomy} tt ON t.term_id = tt.term_id WHERE tt.taxonomy = %s", $tax ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall.php: direct query required; no cache to prime during plugin removal
	$wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->term_taxonomy} WHERE taxonomy = %s", $tax ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall.php: direct query required; no cache to prime during plugin removal
}
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

// Delete taxonomy seeder guard options.
// These are explicitly removed here for clarity even though the blanket
// 'mbs_%' option DELETE above already covers them. Kept explicit so that
// any future scope change to the blanket query does not silently leave
// stale seed-guard rows that block re-seeding on a clean re-install.
// mbs_author, mbs_series, mbs_genre, mbs_tag, mbs_collection, mbs_universe
// have no seeder classes and therefore no guard options.
delete_option( 'mbs_themes_seeded' );          // MBS_Theme_Seeder::SEEDED_VERSION guard
delete_option( 'mbs_content_warnings_seeded' ); // MBS_Content_Warning_Seeder::SEEDED_VERSION guard

// Clear any remaining transients.
$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- DAO layer -- direct DB access is intentional per MBS architecture
	$wpdb->prepare(
		"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s",
		$wpdb->esc_like( '_transient_mbs_' ) . '%',
		$wpdb->esc_like( '_transient_timeout_mbs_' ) . '%'
	)
);
