<?php
/**
 * FleekDash uninstall cleanup.
 *
 * Removes scheduled events, database artifacts, options and metadata that
 * belong to the FleekDash plugin when the plugin is uninstalled from WordPress.
 *
 * Keep the scheduled-hook list in sync with any new wp_schedule_* usage.
 * New transients should include "fleekdash" in the transient name (see docs/architecture/uninstall-data-cleanup.md).
 *
 * @package FleekDash V2
 */

if (!defined('WP_UNINSTALL_PLUGIN')) {
    // Safety guard: this file can only run via the WordPress uninstall flow.
    exit;
}

const FLEEKDASH_UNINSTALL_MU_MARKER_LOADER = 'FleekDash Integrations MU Plugin Loader';

$plugin_dir = __DIR__;
$autoload_path = $plugin_dir . '/vendor/autoload.php';

// ✅ CRITICAL: Define plugin constants before loading migration classes
// These constants are normally defined in fleekdash.php, but during uninstall
// WordPress doesn't load the main plugin file, so we need to define them here
if (!defined('FLEEKDASH_DIR')) {
    define('FLEEKDASH_DIR', $plugin_dir . '/');
}
if (!defined('FLEEKDASH_PLUGIN_DIR')) {
    define('FLEEKDASH_PLUGIN_DIR', $plugin_dir . '/');
}
if (!defined('FLEEKDASH_PLUGIN_FILE')) {
    define('FLEEKDASH_PLUGIN_FILE', $plugin_dir . '/fleekdash.php');
}

if (file_exists($autoload_path)) {
    require_once $autoload_path;
}

// Ensure migration classes are available even if Composer autoload is skipped.
if (!class_exists(\FleekDash\Database\Core\MigrationManager::class)) {
    require_once $plugin_dir . '/database/Core/MigrationManager.php';
}
if (!class_exists(\FleekDash\Database\Core\MigrationInstaller::class)) {
    require_once $plugin_dir . '/database/Core/MigrationInstaller.php';
}

use FleekDash\Database\Core\MigrationInstaller;
use FleekDash\Database\Core\MigrationManager;

global $wpdb;

/**
 * @return array<int, string>
 */
function fleekdashUninstallMuFileContentMarkers(): array
{
    return [
        'FLEEKDASH_MU_LOADER',
        'fleekdash_is_integration_enabled',
        'fleekdash_register_mu_integration',
        FLEEKDASH_UNINSTALL_MU_MARKER_LOADER,
        'Auto-generated MU plugin',
        'fleekdash-integration',
    ];
}

/**
 * @return array<int, string>
 */
function fleekdashUninstallMuDirStrictMarkers(): array
{
    return [
        'FLEEKDASH_MU_LOADER',
        'fleekdash_is_integration_enabled',
        'fleekdash_register_mu_integration',
        FLEEKDASH_UNINSTALL_MU_MARKER_LOADER,
    ];
}

/**
 * @param array<int, string> $markers
 */
function fleekdashUninstallContentHasAnyMarker(string $content, array $markers, bool $caseInsensitive): bool
{
    foreach ($markers as $marker) {
        $found = $caseInsensitive
            ? stripos($content, $marker) !== false
            : strpos($content, $marker) !== false;
        if ($found) {
            return true;
        }
    }

    return false;
}

/**
 * Clear any scheduled cron events registered by the plugin.
 */
function fleekdashUninstallClearScheduledEvents(): void
{
    $hooks = [
        'fleekdash_search_background_index',
        'fleekdash_search_incremental_index',
        'fleekdash_search_immediate_index',
        'fleekdash_index_single_post',
        'fleekdash_index_single_user',
        'fleekdash_daily_cache_cleanup',
        'fleekdash_integration_cleanup',
        'fleekdash_daily_analytics_aggregation',
        'fleekdash_optimize_indexes',
        'fleekdash_analytics_cache_warmup',
        'fleekdash_check_remote_activation',
        'fleekdash_process_webhooks',
        'fleekdash_cleanup_metrics',
        'fleekdash_growth_meter_monthly_snapshot',
        'fleekdash_realtime_dispatch_outbox',
        'fleekdash_cleanup_expired_overrides',
        'fleekdash_async_activation_runner',
        'fleekdash_warm_cache',
        'fleekdash_process_rollback',
        'fleekdash_process_restore',
        'fleekdash_process_update',
        'fleekdash_install_theme',
    ];

    foreach ($hooks as $hook) {
        wp_clear_scheduled_hook($hook);
        while ($timestamp = wp_next_scheduled($hook)) {
            wp_unschedule_event($timestamp, $hook);
        }
    }
}

/**
 * Remove plugin specific options and metadata from the database.
 */
function fleekdashUninstallPurgeOptions(): void
{
    global $wpdb;

    $option_patterns = [
        'fleekdash_%',
        '_fleekdash_%',
        'fdv2_%',
    ];

    foreach ($option_patterns as $pattern) {
        $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
                $pattern
            )
        );
    }

    $transient_patterns = [
        '_transient_%fleekdash%',
        '_transient_timeout_%fleekdash%',
        '_site_transient_%fleekdash%',
        '_site_transient_timeout_%fleekdash%',
        '_transient_semantic_%',
        '_transient_timeout_semantic_%',
    ];

    foreach ($transient_patterns as $pattern) {
        $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$wpdb->options} WHERE option_name LIKE %s",
                $pattern
            )
        );
    }

    if (is_multisite()) {
        foreach ($option_patterns as $pattern) {
            $wpdb->query(
                $wpdb->prepare(
                    "DELETE FROM {$wpdb->sitemeta} WHERE meta_key LIKE %s",
                    $pattern
                )
            );
        }
        foreach ($transient_patterns as $pattern) {
            $wpdb->query(
                $wpdb->prepare(
                    "DELETE FROM {$wpdb->sitemeta} WHERE meta_key LIKE %s",
                    $pattern
                )
            );
        }
    }

    $usermeta_patterns = [
        'fleekdash_%',
        '_fleekdash_%',
    ];

    foreach ($usermeta_patterns as $pattern) {
        $wpdb->query(
            $wpdb->prepare(
                "DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE %s",
                $pattern
            )
        );
    }
}

/**
 * Roll back executed migrations and drop tracking tables.
 */
function fleekdashUninstallResetMigrations(): void
{
    try {
        $manager = new MigrationManager();
        $manager->reset();
    } catch (\Throwable $exception) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('FleekDash uninstall: failed to rollback migrations - ' . $exception->getMessage());
        }
    }

    try {
        MigrationInstaller::uninstall();
    } catch (\Throwable $exception) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('FleekDash uninstall: failed to drop migration table - ' . $exception->getMessage());
        }
    }
}

/**
 * @param array<int, string> $patterns
 */
function fleekdashUninstallDeletePostMetaByPatterns(array $patterns): void
{
    global $wpdb;

    foreach ($patterns as $pattern) {
        try {
            $wpdb->query(
                $wpdb->prepare(
                    "DELETE FROM {$wpdb->postmeta} WHERE meta_key LIKE %s",
                    $pattern
                )
            );
        } catch (\Throwable $exception) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('FleekDash uninstall: failed to remove post meta (' . $pattern . ') - ' . $exception->getMessage());
            }
        }
    }
}

/**
 * @return array<int, int>
 */
function fleekdashUninstallGetAiDocumentPostIds(): array
{
    global $wpdb;

    $doc_prefix_pattern = $wpdb->esc_like('doc_') . '%';

    $ids = $wpdb->get_col(
        $wpdb->prepare(
            "SELECT DISTINCT pm1.post_id
                FROM {$wpdb->postmeta} pm1
                INNER JOIN {$wpdb->postmeta} pm2 ON pm1.post_id = pm2.post_id
                WHERE pm1.meta_key = %s
                AND pm1.meta_value LIKE %s
                AND pm2.meta_key = %s
                AND (pm2.meta_value = %s OR pm2.meta_value = %s OR pm2.meta_value = %s)",
            'document_id',
            $doc_prefix_pattern,
            'created_via_ai',
            'b:1;',
            '1',
            'true'
        )
    );

    $out = [];
    foreach ($ids as $id) {
        $id = (int) $id;
        if ($id > 0) {
            $out[] = $id;
        }
    }

    return $out;
}

/**
 * @param array<int, int> $post_ids
 */
function fleekdashUninstallDeleteDocumentMetaForPosts(array $post_ids): void
{
    global $wpdb;

    if (empty($post_ids)) {
        return;
    }

    $post_ids_string = implode(',', $post_ids);
    $wpdb->query(
        "DELETE FROM {$wpdb->postmeta}
         WHERE post_id IN ($post_ids_string)
         AND meta_key IN ('document_id', 'created_via_ai')"
    );
}

/**
 * @param array<int, int> $post_ids
 */
function fleekdashUninstallMaybeDeleteAiDraftPosts(array $post_ids): void
{
    global $wpdb;

    global $fleekdash_uninstall_delete_drafts_preference;
    $delete_drafts_on_uninstall = isset($fleekdash_uninstall_delete_drafts_preference)
        ? $fleekdash_uninstall_delete_drafts_preference
        : get_option('fleekdash_ai_delete_drafts_on_uninstall', false);

    if (!$delete_drafts_on_uninstall || empty($post_ids)) {
        return;
    }

    $post_ids_string = implode(',', $post_ids);
    $posts_with_info = $wpdb->get_results(
        "SELECT ID, post_type, post_status FROM {$wpdb->posts} WHERE ID IN ($post_ids_string)",
        OBJECT_K
    );

    foreach ($post_ids as $post_id) {
        if (!isset($posts_with_info[$post_id])) {
            continue;
        }

        $post_info = $posts_with_info[$post_id];

        if ($post_info->post_type === 'fleekdash_document') {
            continue;
        }

        if (!in_array($post_info->post_status, ['draft', 'pending', 'auto-draft'], true)) {
            continue;
        }

        if (function_exists('wp_delete_post')) {
            wp_delete_post($post_id, true);
        } else {
            $wpdb->delete($wpdb->posts, ['ID' => $post_id], ['%d']);
            $wpdb->delete($wpdb->postmeta, ['post_id' => $post_id], ['%d']);
        }
    }
}

function fleekdashUninstallPurgeAiDocumentPostMeta(): void
{
    try {
        $post_ids = fleekdashUninstallGetAiDocumentPostIds();
        fleekdashUninstallDeleteDocumentMetaForPosts($post_ids);
        fleekdashUninstallMaybeDeleteAiDraftPosts($post_ids);
    } catch (\Throwable $exception) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('FleekDash uninstall: failed to remove AI-generated post meta - ' . $exception->getMessage());
        }
    }
}

/**
 * Remove post meta entries created by FleekDash.
 */
function fleekdashUninstallPurgePostMeta(): void
{
    global $wpdb;

    $safe_patterns = [
        $wpdb->esc_like('_fleekdash_') . '%',
        $wpdb->esc_like('fleekdash_') . '%',
    ];

    fleekdashUninstallDeletePostMetaByPatterns($safe_patterns);
    fleekdashUninstallPurgeAiDocumentPostMeta();
}

/**
 * @param array<int, string|int> $post_ids
 */
function fleekdashUninstallDeletePostsForCustomType(string $post_type, array $post_ids, bool $delete_drafts_only): void
{
    global $wpdb;

    foreach ($post_ids as $post_id) {
        $post_id = (int) $post_id;
        if ($post_type === 'fleekdash_document' && $delete_drafts_only) {
            $post_status = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT post_status FROM {$wpdb->posts} WHERE ID = %d",
                    $post_id
                )
            );
            if (!in_array($post_status, ['draft', 'pending', 'auto-draft'], true)) {
                continue;
            }
        }

        if (function_exists('wp_delete_post')) {
            wp_delete_post($post_id, true);
        } else {
            $wpdb->delete($wpdb->posts, ['ID' => $post_id], ['%d']);
            $wpdb->delete($wpdb->postmeta, ['post_id' => $post_id], ['%d']);
        }
    }
}

/**
 * Remove custom post types and their posts.
 *
 * For fleekdash_document posts, respects user preference to only delete drafts/pending
 * if fleekdash_ai_delete_drafts_on_uninstall is enabled.
 */
function fleekdashUninstallPurgeCustomPostTypes(): void
{
    global $wpdb;

    global $fleekdash_uninstall_delete_drafts_preference;
    $delete_drafts_on_uninstall = isset($fleekdash_uninstall_delete_drafts_preference)
        ? $fleekdash_uninstall_delete_drafts_preference
        : get_option('fleekdash_ai_delete_drafts_on_uninstall', false);

    $custom_post_types = [
        'fleekdash_document',
    ];

    foreach ($custom_post_types as $post_type) {
        try {
            $post_ids = $wpdb->get_col(
                $wpdb->prepare(
                    "SELECT ID FROM {$wpdb->posts} WHERE post_type = %s",
                    $post_type
                )
            );

            if (empty($post_ids)) {
                continue;
            }

            if ($post_type === 'fleekdash_document' && !$delete_drafts_on_uninstall) {
                continue;
            }

            $delete_drafts_only = ($post_type === 'fleekdash_document' && $delete_drafts_on_uninstall);
            fleekdashUninstallDeletePostsForCustomType($post_type, $post_ids, $delete_drafts_only);
        } catch (\Throwable $exception) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('FleekDash uninstall: failed to remove custom post type (' . $post_type . ') - ' . $exception->getMessage());
            }
        }
    }
}

/**
 * @param object $term
 */
function fleekdashUninstallDeleteTermFallback($term): void
{
    global $wpdb;

    $term_taxonomy_id = (int) $term->term_taxonomy_id;
    $term_id = (int) $term->term_id;

    $wpdb->delete($wpdb->term_relationships, ['term_taxonomy_id' => $term_taxonomy_id], ['%d']);
    $wpdb->delete($wpdb->term_taxonomy, ['term_taxonomy_id' => $term_taxonomy_id], ['%d']);

    $termmeta_table = $wpdb->termmeta;
    $termmeta_exists = $wpdb->get_var($wpdb->prepare(
        "SHOW TABLES LIKE %s",
        $termmeta_table
    )) === $termmeta_table;
    if ($termmeta_exists) {
        $wpdb->delete($wpdb->termmeta, ['term_id' => $term_id], ['%d']);
    }

    $wpdb->delete($wpdb->terms, ['term_id' => $term_id], ['%d']);
}

/**
 * @param array<int, object> $terms
 */
function fleekdashUninstallDeleteTermsForTaxonomy(string $taxonomy, array $terms): void
{
    foreach ($terms as $term) {
        if (function_exists('wp_delete_term')) {
            wp_delete_term((int) $term->term_id, $taxonomy);
        } else {
            fleekdashUninstallDeleteTermFallback($term);
        }
    }
}

/**
 * Remove custom taxonomies and their terms.
 */
function fleekdashUninstallPurgeCustomTaxonomies(): void
{
    global $wpdb;

    $custom_taxonomies = [
        'urgency',
        'importancy',
    ];

    foreach ($custom_taxonomies as $taxonomy) {
        try {
            $terms = $wpdb->get_results(
                $wpdb->prepare(
                    "SELECT term_taxonomy_id, term_id FROM {$wpdb->term_taxonomy} WHERE taxonomy = %s",
                    $taxonomy
                )
            );

            if (!empty($terms)) {
                fleekdashUninstallDeleteTermsForTaxonomy($taxonomy, $terms);
            }
        } catch (\Throwable $exception) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('FleekDash uninstall: failed to remove custom taxonomy (' . $taxonomy . ') - ' . $exception->getMessage());
            }
        }
    }
}

/**
 * Remove term meta entries created by FleekDash.
 */
function fleekdashUninstallPurgeTermMeta(): void
{
    global $wpdb;

    $table_name = $wpdb->termmeta;
    $table_exists = $wpdb->get_var($wpdb->prepare(
        "SHOW TABLES LIKE %s",
        $table_name
    )) === $table_name;

    if (!$table_exists) {
        return;
    }

    $termmeta_patterns = [
        $wpdb->esc_like('_fleekdash_') . '%',
        $wpdb->esc_like('fleekdash_') . '%',
    ];

    foreach ($termmeta_patterns as $pattern) {
        try {
            $wpdb->query(
                $wpdb->prepare(
                    "DELETE FROM {$wpdb->termmeta} WHERE meta_key LIKE %s",
                    $pattern
                )
            );
        } catch (\Throwable $exception) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('FleekDash uninstall: failed to remove term meta (' . $pattern . ') - ' . $exception->getMessage());
            }
        }
    }
}

function fleekdashUninstallDirectoryHasStrictMuMarkers(string $dir_path): bool
{
    $php_files = glob($dir_path . '/*.php');
    if (!$php_files) {
        return false;
    }

    $markers = fleekdashUninstallMuDirStrictMarkers();
    foreach ($php_files as $php_file) {
        $content = @file_get_contents($php_file);
        if ($content !== false && fleekdashUninstallContentHasAnyMarker($content, $markers, true)) {
            return true;
        }
    }

    return false;
}

/**
 * Check if a directory is a FleekDash MU plugin directory.
 *
 * @param string $dir_path Directory path
 */
function fleekdashUninstallIsFleekdashMuDir(string $dir_path): bool
{
    $dir_name = basename($dir_path);

    if (strpos($dir_name, 'fleekdash-') === 0) {
        return true;
    }

    return fleekdashUninstallDirectoryHasStrictMuMarkers($dir_path);
}

/**
 * Check if a file is a FleekDash MU plugin.
 *
 * @param string $file_path File path
 */
function fleekdashUninstallIsFleekdashMuFile(string $file_path): bool
{
    if (!file_exists($file_path)) {
        return false;
    }

    $content = @file_get_contents($file_path);
    if ($content === false) {
        return false;
    }

    return fleekdashUninstallContentHasAnyMarker($content, fleekdashUninstallMuFileContentMarkers(), false);
}

function fleekdashUninstallRemoveLegacyMuLoaderFile(string $mu_plugins_dir): void
{
    $loader_file = $mu_plugins_dir . '/fleekdash-integrations-loader.php';
    if (file_exists($loader_file)) {
        @unlink($loader_file);
    }
}

function fleekdashUninstallRemoveFleekdashMuDirectories(string $mu_plugins_dir): void
{
    $mu_dirs = glob($mu_plugins_dir . '/fleekdash-*', GLOB_ONLYDIR);
    if (!$mu_dirs) {
        return;
    }
    foreach ($mu_dirs as $mu_dir) {
        if (fleekdashUninstallIsFleekdashMuDir($mu_dir)) {
            fleekdashUninstallRemoveDirectory($mu_dir);
        }
    }
}

function fleekdashUninstallRemoveFleekdashMuPhpFiles(string $mu_plugins_dir): void
{
    $mu_files = glob($mu_plugins_dir . '/fleekdash-*.php');
    if (!$mu_files) {
        return;
    }
    foreach ($mu_files as $mu_file) {
        if (basename($mu_file) === 'fleekdash-integrations-loader.php') {
            continue;
        }
        if (fleekdashUninstallIsFleekdashMuFile($mu_file)) {
            @unlink($mu_file);
        }
    }
}

/**
 * Remove MU plugins created by FleekDash.
 */
function fleekdashUninstallPurgeMuPlugins(): void
{
    $mu_plugins_dir = WPMU_PLUGIN_DIR;

    if (!is_dir($mu_plugins_dir)) {
        return;
    }

    try {
        fleekdashUninstallRemoveLegacyMuLoaderFile($mu_plugins_dir);
        fleekdashUninstallRemoveFleekdashMuDirectories($mu_plugins_dir);
        fleekdashUninstallRemoveFleekdashMuPhpFiles($mu_plugins_dir);
    } catch (\Throwable $exception) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('FleekDash uninstall: failed to remove MU plugins - ' . $exception->getMessage());
        }
    }
}

/**
 * Try removing a directory via WordPress filesystem API.
 */
function fleekdashUninstallTryRemoveDirectoryWithFilesystem(string $dir): bool
{
    if (!function_exists('WP_Filesystem')) {
        return false;
    }

    if (!function_exists('request_filesystem_credentials')) {
        require_once ABSPATH . 'wp-admin/includes/file.php';
    }

    global $wp_filesystem;

    $creds = request_filesystem_credentials('', '', false, $dir, null);
    if (WP_Filesystem($creds, $dir)) {
        $result = $wp_filesystem->rmdir($dir, true);
        if ($result !== false) {
            return true;
        }
    }

    return false;
}

/**
 * Manual recursive directory removal (fallback).
 */
function fleekdashUninstallRemoveDirectoryManual(string $dir): bool
{
    $files = scandir($dir);
    if ($files === false) {
        if (defined('WP_DEBUG') && WP_DEBUG) {
            error_log('FleekDash uninstall: cannot read directory - ' . $dir);
        }

        return false;
    }

    $files = array_diff($files, ['.', '..']);

    foreach ($files as $file) {
        $path = $dir . '/' . $file;
        if (is_dir($path)) {
            if (!fleekdashUninstallRemoveDirectory($path) && defined('WP_DEBUG') && WP_DEBUG) {
                error_log('FleekDash uninstall: failed to remove subdirectory - ' . $path);
            }
        } elseif (!@unlink($path) && defined('WP_DEBUG') && WP_DEBUG) {
            error_log('FleekDash uninstall: failed to remove file - ' . $path);
        }
    }

    return (bool) @rmdir($dir);
}

/**
 * Remove directory recursively.
 *
 * @param string $dir Directory path
 */
function fleekdashUninstallRemoveDirectory(string $dir): bool
{
    if (!is_dir($dir)) {
        return true;
    }

    if (fleekdashUninstallTryRemoveDirectoryWithFilesystem($dir)) {
        return true;
    }

    return fleekdashUninstallRemoveDirectoryManual($dir);
}

/**
 * Remove cache files and temporary files created by FleekDash.
 */
function fleekdashUninstallPurgeCacheFiles(): void
{
    $plugin_dir = dirname(__FILE__);
    $cache_dirs = [
        $plugin_dir . '/cache',
        $plugin_dir . '/tmp',
        $plugin_dir . '/temp',
    ];

    foreach ($cache_dirs as $cache_dir) {
        if (!is_dir($cache_dir)) {
            continue;
        }
        try {
            fleekdashUninstallRemoveDirectory($cache_dir);
        } catch (\Throwable $exception) {
            if (defined('WP_DEBUG') && WP_DEBUG) {
                error_log('FleekDash uninstall: failed to remove cache directory (' . $cache_dir . ') - ' . $exception->getMessage());
            }
        }
    }
}

// Execute uninstall cleanup steps.
// CRITICAL: Read user preference BEFORE deleting options
global $fleekdash_uninstall_delete_drafts_preference;
$fleekdash_uninstall_delete_drafts_preference = get_option('fleekdash_ai_delete_drafts_on_uninstall', false);

fleekdashUninstallClearScheduledEvents();
fleekdashUninstallPurgePostMeta();
fleekdashUninstallPurgeCustomPostTypes();
fleekdashUninstallPurgeCustomTaxonomies();
fleekdashUninstallPurgeTermMeta();
fleekdashUninstallPurgeMuPlugins();
fleekdashUninstallPurgeCacheFiles();
fleekdashUninstallResetMigrations();
fleekdashUninstallPurgeOptions();

delete_transient('fleekdash_v2_activation_redirect');
