<?php

/**
 * Uninstall cleanup for Cliq Store Locator.
 *
 * Removes plugin tables, options, the management capability and scheduled cron.
 * Runs only on real uninstall, and honours the "keep data on uninstall" setting
 * so users can opt out of destruction.
 */

declare(strict_types=1);

// Uninstall must remove plugin-owned tables/options; caching teardown operations
// would be incorrect and WordPress provides no schema-removal abstraction.
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching

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

global $wpdb;

(static function () use ($wpdb): void {

// Allow users to keep their data. Read the settings blob directly because the
// plugin bootstrap is not loaded during uninstall.
    $cliqSlSettings = get_option('cliq_sl_settings', []);
    if (is_array($cliqSlSettings) && ! empty($cliqSlSettings['keep_data_on_uninstall'])) {
        // Runtime hooks and capabilities must not survive an uninstall even when
        // the administrator elects to retain stored content for a later reinstall.
            $role = get_role('administrator');
        if ($role) {
            $role->remove_cap('manage_store_locator');
        }

        return;
    }

// Source the table list from SchemaInstaller so it can never drift. WordPress
// runs uninstall.php in isolation (the plugin bootstrap is not loaded), so pull
// in the autoloader; fall back to an inline list if it isn't present.
    $tables = null;
    $autoload = __DIR__ . '/vendor/autoload.php';
    if (is_readable($autoload)) {
        require_once $autoload;
    }
    // Extensions own tables too (designs, leads, markers, store_views) and they
    // register them on the `cliq_sl_owned_tables` filter. Without booting them
    // first, allTableNames() reports only the core set and those four tables
    // survive an uninstall that promises to remove everything.
    if (class_exists(\CliqThemes\StoreLocator\Extensions\ExtensionLoader::class)) {
        try {
            \CliqThemes\StoreLocator\Extensions\ExtensionLoader::boot();
        } catch (\Throwable $e) {
            // A feature that cannot boot must not stop the teardown; the
            // fallback list below still covers the tables this plugin ships.
        }
    }
    if (class_exists(\CliqThemes\StoreLocator\Schema\SchemaInstaller::class)) {
        $tables = \CliqThemes\StoreLocator\Schema\SchemaInstaller::allTableNames();
    }
    if (!is_array($tables) || $tables === []) {
        // Fallback — keep in sync with SchemaInstaller::TABLES. Only tables this
        // plugin creates are listed: names used by pre-release iterations are
        // deliberately absent, because such a table on somebody else's site is
        // more likely to belong to another plugin than to this one.
        $tables = [
        'cliq_sl_stores', 'cliq_sl_store_locations', 'cliq_sl_store_hours', 'cliq_sl_categories', 'cliq_sl_store_category',
        'cliq_sl_brands', 'cliq_sl_brand_store', 'cliq_sl_markers', 'cliq_sl_store_meta', 'cliq_sl_leads', 'cliq_sl_store_views',
        'cliq_sl_countries', 'cliq_sl_custom_fields', 'cliq_sl_custom_field_category', 'cliq_sl_designs',
        ];
    }

// Disable FK checks so inter-table constraints can't block the teardown.
    $wpdb->query('SET FOREIGN_KEY_CHECKS = 0');
    foreach ($tables as $table) {
        // phpcs:ignore WordPress.DB.DirectDatabaseQuery.SchemaChange -- Required uninstall cleanup for plugin-owned tables.
        $wpdb->query($wpdb->prepare('DROP TABLE IF EXISTS %i', $wpdb->prefix . $table));
    }
    $wpdb->query('SET FOREIGN_KEY_CHECKS = 1');

    delete_option('cliq_sl_schema_version');
    delete_option('cliq_sl_settings');
    delete_option('cliq_sl_onboarded');
        // Records the one-time conversion of the settings-built layout into
    // editable design rows, so a reinstall starts that conversion fresh.
    delete_option('cliq_sl_pro_designs_seeded');
// Derived cache of the icons/markers/custom fields the frontend may load. It is
// rebuilt on demand, so it is worthless after uninstall — and the readme promises
// deleting the plugin removes everything it created.
    delete_option('cliq_sl_frontend_assets');

// Remove media-library attachments created from bundled demo assets.
    $cliqSlDemoAttachments = get_option('cliq_sl_demo_media_attachments', []);
    if (is_array($cliqSlDemoAttachments)) {
        foreach (array_unique(array_map('intval', $cliqSlDemoAttachments)) as $cliqSlAttachmentId) {
            if ($cliqSlAttachmentId > 0) {
                wp_delete_attachment($cliqSlAttachmentId, true);
            }
        }
    }
    delete_option('cliq_sl_demo_media_attachments');

// Remove plugin transients (geocode cache + per-IP rate-limit buckets). These
// expire on their own, but clear the DB-stored copies on uninstall.
    $wpdb->query($wpdb->prepare(
        'DELETE FROM %i WHERE option_name LIKE %s OR option_name LIKE %s',
        $wpdb->options,
        $wpdb->esc_like('_transient_cliq_sl_') . '%',
        $wpdb->esc_like('_transient_timeout_cliq_sl_') . '%'
    ));

// Remove capability.
    $role = get_role('administrator');
    if ($role) {
        $role->remove_cap('manage_store_locator');
    }

// Remove plugin-owned marker uploads when the user did not choose to keep data.
    $uploads = wp_upload_dir();
    if (empty($uploads['error']) && ! empty($uploads['basedir'])) {
        require_once ABSPATH . 'wp-admin/includes/file.php';
        WP_Filesystem();
        global $wp_filesystem;
        if ($wp_filesystem instanceof WP_Filesystem_Base) {
            $wp_filesystem->delete(trailingslashit($uploads['basedir']) . 'cliq-store-locator', true, 'd');
        }
    }

// Clear scheduled cron.
})();
