<?php
/**
 * Plugin uninstall — clean up ALL database options when plugin is deleted.
 *
 * Called automatically by WordPress when plugin is deleted via WP Admin.
 * NOT called on deactivation — only on full deletion.
 *
 * @package ParcelSelector
 */

// phpcs:disable WordPress.WP.AlternativeFunctions.file_system_operations_rmdir -- rmdir() acceptable on uninstall — WP_Filesystem requires init that may not be available during uninstall.php execution

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

// ── Core plugin options ──────────────────────────────────────────────────────
$parcselect_options = array(
	'parcselect_map_engine',
	'parcselect_default_country',
	'parcselect_version',
	'parcselect_needs_zone_setup',
	'parcselect_custom_pickup',
	'parcselect_shipping_config',
	'parcselect_shipping_zone_id',
	'parcselect_zone_setup_version',
	'parcselect_zone_setup_complete',
	'parcselect_license_status',
	'parcselect_license_data',
	'parcselect_license_key',
	'parcselect_license_email',
	'parcselect_license_plan',
	'parcselect_license_expires_ts',
	'parcselect_license_expires_fmt',
	'parcselect_license_last_sync',
	'parcselect_license_orders_limit',
	'parcselect_license_orders_used',
	'parcselect_remote_update_info',
	'parcselect_activation_notice_dismissed',
	// Route & carrier settings (added v3.4.0+)
	'parcselect_shop_origin_country',
	'parcselect_carrier_routes',
	'parcselect_enabled_carriers',
	'parcselect_show_legend',
	'parcselect_routes_seeded',
	'parcselect_wizard_completed',
	'parcselect_prosiaczek_rules_v2',
	'parcselect_show_powered_by',
);

// ── License / activation options ─────────────────────────────────────────────
$parcselect_inpost_options = array(
	'parcselect_activated',
	'inpost_activation_date',
	'inpost_activation_personal',
	'inpost_activation_company',
	'inpost_activation_consent',
	'inpost_activation_redirect',
	'parcselect_installation_id',
	'parcselect_license_type',
	'parcselect_license_mnemonic',
	'inpost_license_seeds',
	'parcselect_license_ends_at',
	'inpost_trial_ends',
	'parcselect_counter_value',
	'parcselect_counter_limit',
	'inpost_order_count',
	'parcselect_order_limit',
	'inpost_orders_remaining',
	'inpost_days_remaining',
	'inpost_tracked_order_ids',
	'inpost_first_order_baseline',
	'inpost_first_order_baseline_date',
	'inpost_first_order_ts',
	'inpost_seed_pending',
	'inpost_server_allowed',
	'inpost_server_allowed_at',
	'inpost_server_confirmed_count',
	'parcselect_server_confirmed_ends_at',
	'parcselect_server_notice',
	'parcselect_order_display_html',
	'parcselect_paczkomaty_options',
	'inpost_consent_given',
);

foreach ( array_merge( $parcselect_options, $parcselect_inpost_options ) as $parcselect_option ) {
	delete_option( $parcselect_option );
}

// ── Scheduled events (cron) ──────────────────────────────────────────────────
wp_clear_scheduled_hook( 'parcselect_license_daily_sync' );
wp_clear_scheduled_hook( 'parcselect_heartbeat_event' );
wp_clear_scheduled_hook( 'etykietownik_cleanup_expired' );
wp_clear_scheduled_hook( 'etykietownik_retry_failed' );
wp_clear_scheduled_hook( 'parcselect_currency_refresh' );
wp_clear_scheduled_hook( 'parcselect_label_poll_pending' );
// Actual hook names registered by Parcselect_Label_Hooks::schedule_cleanup() — the
// etykietownik_* aliases above were stale names from pre-rename. Without
// clearing these, cron would keep firing PS_Label_Hooks handlers after a
// plugin uninstall+reinstall until the next activation registers them fresh.
wp_clear_scheduled_hook( 'parcselect_label_cleanup_expired' );
wp_clear_scheduled_hook( 'parcselect_label_retry_failed' );
wp_clear_scheduled_hook( 'parcselect_label_prune_old_pdfs' );
// v4.4.5 M3 — cron migracji PDF do tabeli DB (rejestrowany przez Parcselect_Label_Pdf_Store::init()).
wp_clear_scheduled_hook( 'parcselect_label_pdf_migrate_cron' );

// ── Etykietownik options ────────────────────────────────────────────────────
$parcselect_etyk_options = array(
	'etykietownik_client_id', 'etykietownik_client_secret',
	'etykietownik_username', 'etykietownik_password', 'etykietownik_service_id',
	'etykietownik_sender_name', 'etykietownik_sender_company',
	'etykietownik_sender_street', 'etykietownik_sender_city',
	'etykietownik_sender_postcode', 'etykietownik_sender_phone', 'etykietownik_sender_email',
	'etykietownik_default_size', 'etykietownik_default_weight',
	'etykietownik_margin', 'etykietownik_notify_email', 'etykietownik_sandbox',
	'etykietownik_pickup_inpost', 'etykietownik_pickup_orlen',
	'etykietownik_pickup_gls', 'etykietownik_pickup_dpd', 'etykietownik_pickup_dhl',
);
foreach ( $parcselect_etyk_options as $parcselect_opt ) {
	delete_option( $parcselect_opt );
}

// ── ps_label_* options (VPS-backed label flow, introduced v4.0) ─────────────
$parcselect_label_options = array(
	'parcselect_label_proxy_url', 'parcselect_label_mapserver_url', 'parcselect_label_proxy_secret',
	'parcselect_label_webhook_secret', 'parcselect_label_enrolled_at', 'parcselect_label_enabled_coins',
	'parcselect_label_wallet_sol', 'parcselect_label_direct_api', 'parcselect_label_debug_enabled',
	'parcselect_label_consent_log', // v4.4.5 M4 — consent log (audyt RODO) przeniesiony z plików JSON do opcji DB.
	'parcselect_label_default_size', 'parcselect_label_default_weight', 'parcselect_label_margin',
	'parcselect_label_sender_name', 'parcselect_label_sender_company', 'parcselect_label_sender_street',
	'parcselect_label_sender_city', 'parcselect_label_sender_postcode', 'parcselect_label_sender_phone',
	'parcselect_label_sender_email',
);
foreach ( $parcselect_label_options as $parcselect_opt ) {
	delete_option( $parcselect_opt );
}

// ── Transients ───────────────────────────────────────────────────────────────
global $wpdb;
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- uninstall.php must use direct queries; no WP API/caching available during uninstall.
$wpdb->query(
	$wpdb->prepare(
		"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s OR option_name LIKE %s",
		$wpdb->esc_like( '_transient_ps_' ) . '%',
		$wpdb->esc_like( '_transient_timeout_ps_' ) . '%',
		$wpdb->esc_like( '_transient_ps_label_' ) . '%',
		$wpdb->esc_like( '_transient_timeout_ps_label_' ) . '%'
	)
);

// ── WC shipping zone method settings ────────────────────────────────────────
// Remove any instance-level settings for our shipping method
$wpdb->query(
	$wpdb->prepare(
		"DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
		$wpdb->esc_like( 'woocommerce_parcselect_inpost_paczkomat_' ) . '%' . $wpdb->esc_like( '_settings' )
	)
);
// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

// ── Locally mirrored PDFs in uploads/ps-labels ───────────────────────────────
// These are only label copies — the canonical record is on the VPS and in the
// order's tracking_number meta which we intentionally keep.
$parcselect_uploads = wp_upload_dir();
$parcselect_labels_dir = trailingslashit( $parcselect_uploads['basedir'] ) . 'ps-labels';
if ( is_dir( $parcselect_labels_dir ) ) {
	foreach ( (array) glob( $parcselect_labels_dir . '/*.pdf' ) as $parcselect_pdf ) {
		wp_delete_file( $parcselect_pdf );
	}
	wp_delete_file( $parcselect_labels_dir . '/.htaccess' );
	wp_delete_file( $parcselect_labels_dir . '/index.html' );
	rmdir( $parcselect_labels_dir ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- directory may already be gone.
}

// ── Legacy consent log dir (pre-v4.4.5, migrated to DB) ──────────────────────
// Defensywne czyszczenie: consent log (dane osobowe — login/IP/UA) zostal
// przeniesiony do opcji DB. Folder jest normalnie sprzatany leniwie przy
// migracji; ten blok pokrywa przypadek odinstalowania przed migracja.
$parcselect_consent_dir = trailingslashit( $parcselect_uploads['basedir'] ) . 'etykietownik/_consent';
if ( is_dir( $parcselect_consent_dir ) ) {
	foreach ( (array) glob( $parcselect_consent_dir . '/per-order/*' ) as $parcselect_cf ) {
		wp_delete_file( $parcselect_cf );
	}
	rmdir( $parcselect_consent_dir . '/per-order' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- directory may already be gone.
	foreach ( (array) glob( $parcselect_consent_dir . '/*' ) as $parcselect_cf ) {
		wp_delete_file( $parcselect_cf );
	}
	rmdir( $parcselect_consent_dir ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged -- directory may already be gone.
}

// ── NOTE: Order meta (_ps_locker_*, _ps_customer_*) is intentionally preserved ──
// Order history must remain intact. WooCommerce order data is not ours to delete.
//
// EXCEPTION: _ps_label_* meta IS purged. Label meta references an external
// service (VPS sessions, download URLs, payment proofs) that is per-installation.
// Leaving it on orders would cause a future plugin install on the same DB to
// surface another shop's "paid" label and serve a PDF from a stale VPS session.
// Tracking_number alias _ps_tracking_number is kept since it is a generic field
// other plugins / themes may rely on for shipment display.
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- uninstall.php must use direct queries.
$parcselect_label_meta_like = $wpdb->esc_like( '_ps_label_' ) . '%';

// 1. Classic CPT post meta (shop_order posts).
$wpdb->query(
	$wpdb->prepare(
		"DELETE pm FROM {$wpdb->postmeta} pm
		 INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
		 WHERE p.post_type = 'shop_order' AND pm.meta_key LIKE %s",
		$parcselect_label_meta_like
	)
);

// 2. HPOS orders meta (WooCommerce >= 8.x custom order tables).
$parcselect_hpos_table = $wpdb->prefix . 'wc_orders_meta';
$parcselect_hpos_exists = $wpdb->get_var(
	$wpdb->prepare( 'SHOW TABLES LIKE %s', $parcselect_hpos_table )
);
if ( $parcselect_hpos_exists ) {
	$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- uninstall: nazwa tabeli HPOS z $wpdb->prefix (zaufana); wartosci przez prepare()
		$wpdb->prepare(
			"DELETE FROM {$parcselect_hpos_table} WHERE meta_key LIKE %s",
			$parcselect_label_meta_like
		)
	);
}

// 3. Sweep stamp option (so a fresh future install starts clean).
delete_option( 'parcselect_label_sweep_installation_id' );

// ── Consent snapshots meta (_ps_consent_snapshots, introduced v4.4.5 M4) ─────
// Per-order GDPR consent snapshots stored as order meta. Klucz zaczyna sie od
// _ps_consent_ (nie _ps_label_), wiec sweep _ps_label_* powyzej go NIE obejmuje.
// Dane prywatne per-instalacja — czyscimy przy uninstall jak meta _ps_label_*.

// 1. Classic CPT post meta (shop_order posts).
$wpdb->query(
	$wpdb->prepare(
		"DELETE pm FROM {$wpdb->postmeta} pm
		 INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id
		 WHERE p.post_type = 'shop_order' AND pm.meta_key = %s",
		'_ps_consent_snapshots'
	)
);

// 2. HPOS orders meta (WooCommerce >= 8.x).
if ( $parcselect_hpos_exists ) {
	$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- uninstall: nazwa tabeli HPOS z $wpdb->prefix (zaufana); wartosci przez prepare()
		$wpdb->prepare(
			"DELETE FROM {$parcselect_hpos_table} WHERE meta_key = %s",
			'_ps_consent_snapshots'
		)
	);
}

// ── v4.4.5 M3 — dedykowana tabela DB bajtow PDF etykiet ──────────────────────
// 4. Drop tabeli PDF etykiet (PDF nie sa juz trzymane w uploads/etykietownik).
$parcselect_pdf_table = $wpdb->prefix . 'parcselect_label_pdf';
$wpdb->query( "DROP TABLE IF EXISTS {$parcselect_pdf_table}" ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, PluginCheck.Security.DirectDB.UnescapedDBParameter -- uninstall: usuniecie wlasnej tabeli wtyczki przy odinstalowaniu jest zamierzone; nazwa tabeli z $wpdb->prefix (zaufana), DROP IF EXISTS.

// 5. Opcja wersji schematu tabeli PDF.
delete_option( 'parcselect_label_pdf_db_version' );
// phpcs:enable
