<?php

namespace FleekDash\API;

// Load debug helpers
if (!function_exists('fleekdash_log_debug')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use FleekDash\Core\AuthMiddleware;
use FleekDash\Core\PluginHelper;
use FleekDash\API\Plugins\PluginAssetManager;

/**
 * Plugin Directory API
 *
 * Provides advanced plugin directory browsing, search, and installation
 * with WordPress.org API integration; directory installs run in the REST request (no wp-cron hop).
 *
 * @package FleekDash\API
 */
class PluginDirectoryAPI
{
    private const ERROR_MESSAGE_ADMIN_REQUIRED = 'Admin access required';

    /**
     * Cache duration for WordPress.org API responses
     */
    const CACHE_SEARCH_DURATION = 3600; // 1 hour
    const CACHE_DETAILS_DURATION = 21600; // 6 hours
    const CACHE_CATEGORIES_DURATION = 86400; // 24 hours

    /**
     * Asset manager for plugin icons/banners
     */
    private $assetManager;

    /**
     * Constructor
     *
     * Migrated (v2.2): PluginsRoutes (Phase 2)
     * add_action removed - routes now registered via PluginDirectoryController
     */
    public function __construct()
    {
        $this->assetManager = new PluginAssetManager();
    }

    /**
     * Register REST API routes
     */
    public function register_routes() // NOSONAR php:S100 — method name matches register_rest_route callback string
    {
        $namespace = 'fleekdash/v1';

        // Search & Browse
        \register_rest_route($namespace, '/plugin-directory/search', array(
            'methods' => 'GET',
            'callback' => array($this, 'search_plugins'),
            'permission_callback' => array($this, 'check_permissions'),
            'args' => $this->get_search_args()
        ));

        \register_rest_route($namespace, '/plugin-directory/plugin/(?P<slug>[a-zA-Z0-9_-]+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_plugin_details'),
            'permission_callback' => array($this, 'check_permissions'),
        ));

        \register_rest_route($namespace, '/plugin-directory/categories', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_categories'),
            'permission_callback' => array($this, 'check_permissions'),
        ));

        \register_rest_route($namespace, '/plugin-directory/tags', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_tags'),
            'permission_callback' => array($this, 'check_permissions'),
        ));

        \register_rest_route($namespace, '/plugin-directory/featured', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_featured'),
            'permission_callback' => array($this, 'check_permissions'),
        ));

        // Installation
        \register_rest_route($namespace, '/plugin-directory/install', array(
            'methods' => 'POST',
            'callback' => array($this, 'install_plugin'),
            'permission_callback' => array($this, 'check_permissions'),
            'args' => array(
                'slug' => array('required' => true, 'type' => 'string'),
                'activate' => array('required' => false, 'type' => 'boolean', 'default' => false),
            ),
        ));

        \register_rest_route($namespace, '/plugin-directory/install-status/(?P<job_id>[a-zA-Z0-9_-]+)', array(
            'methods' => 'GET',
            'callback' => array($this, 'get_install_status'),
            'permission_callback' => array($this, 'check_permissions'),
        ));

        \register_rest_route($namespace, '/plugin-directory/cancel-install/(?P<job_id>[a-zA-Z0-9_-]+)', array(
            'methods' => 'DELETE',
            'callback' => array($this, 'cancel_install'),
            'permission_callback' => array($this, 'check_permissions'),
        ));

        // Bulk actions
        \register_rest_route($namespace, '/plugins/bulk-action', array(
            'methods' => 'POST',
            'callback' => array($this, 'bulk_action'),
            'permission_callback' => array($this, 'check_permissions'),
            'args' => array(
                'action' => array('required' => true, 'type' => 'string'),
                'plugins' => array('required' => true, 'type' => 'array'),
            ),
        ));
    }

    /**
     * Get search arguments schema
     */
    private function get_search_args() // NOSONAR php:S100 — WordPress REST helper naming convention
    {
        return array(
            'query' => array(
                'type' => 'string',
                'required' => false,
                'default' => '',
            ),
            'page' => array(
                'type' => 'integer',
                'required' => false,
                'default' => 1,
                'minimum' => 1,
            ),
            'per_page' => array(
                'type' => 'integer',
                'required' => false,
                'default' => 20,
                'minimum' => 1,
                'maximum' => 100,
            ),
            'browse' => array(
                'type' => 'string',
                'required' => false,
                'enum' => array('popular', 'featured', 'new', 'updated'),
            ),
            'category' => array(
                'type' => 'string',
                'required' => false,
            ),
            'tag' => array(
                'type' => 'string',
                'required' => false,
            ),
            'author' => array(
                'type' => 'string',
                'required' => false,
            ),
            'sort' => array(
                'type' => 'string',
                'required' => false,
                'default' => 'relevance',
                'enum' => array('relevance', 'popularity', 'rating', 'updated', 'name'),
            ),
        );
    }

    /**
     * Check permissions
     */
    public function check_permissions() // NOSONAR php:S100 — matches permission_callback in register_rest_route
    {
        return true; // Let AuthMiddleware handle auth
    }

    /**
     * Search plugins from WordPress.org
     */
    public function search_plugins(WP_REST_Request $request) // NOSONAR php:S100,php:S3776,php:S1142 — WP REST callback name; structured flow
    {
        try {
            // Auth check with graceful fallback
            $auth_check = AuthMiddleware::check('authenticated');
            if (!$auth_check['authenticated']) {
                fleekdash_log_debug('FleekDash: Plugin directory access without auth: ' . $auth_check['reason']);
            }

            $query = $request->get_param('query');
            $page = $request->get_param('page');
            $per_page = $request->get_param('per_page');
            $browse = $request->get_param('browse');
            $category = $request->get_param('category');
            $tag = $request->get_param('tag');
            $author = $request->get_param('author');
            $sort = $request->get_param('sort');

            // Build cache key
            $cache_key = 'fleekdash_plugin_search_' . md5(serialize($request->get_params()));
            $cached = \get_transient($cache_key);

            if ($cached !== false) {
                return \rest_ensure_response($cached);
            }

            // Prepare WordPress.org API arguments
            $api_args = array(
                'page' => $page,
                'per_page' => $per_page,
                'fields' => array(
                    'icons' => true,
                    'banners' => true,
                    'reviews' => true,
                    'downloaded' => true,
                    'active_installs' => true,
                    'short_description' => true,
                    'description' => false, // Full description not needed for search
                    'sections' => false,
                    'tested' => true,
                    'requires' => true,
                    'requires_php' => true,
                    'rating' => true,
                    'ratings' => true,
                    'num_ratings' => true,
                    'homepage' => true,
                    'tags' => true,
                    'versions' => false,
                    'donate_link' => false,
                    'contributors' => true,
                    'last_updated' => true,
                    'added' => true,
                ),
            );

            // Add search query
            if (!empty($query)) {
                $api_args['search'] = $query;
            }

            // Add browse mode
            if (!empty($browse)) {
                $api_args['browse'] = $browse;
            }

            // Add category
            if (!empty($category)) {
                $api_args['category'] = $category;
            }

            // Add tag
            if (!empty($tag)) {
                $api_args['tag'] = $tag;
            }

            // Add author
            if (!empty($author)) {
                $api_args['author'] = $author;
            }

            // Query WordPress.org API
            if (!function_exists('plugins_api')) {
                require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
            }

            $api_response = plugins_api('query_plugins', $api_args);

            if (is_wp_error($api_response)) {
                return new WP_Error(
                    'api_error',
                    'WordPress.org API error: ' . $api_response->get_error_message(),
                    array('status' => 500)
                );
            }

            // Get installed plugins for comparison
            $this->ensureWordPressPluginFunctionsLoaded(true, false);
            $installed_plugins = \get_plugins();
            $active_plugins = \get_option('active_plugins', array());

            // Format results
            $results = array();
            if (!empty($api_response->plugins)) {
                foreach ($api_response->plugins as $plugin) {
                    // Convert array to object if needed (WordPress.org returns arrays)
                    if (is_array($plugin)) {
                        $plugin = (object) $plugin;
                    }

                    $formatted = $this->format_plugin_data($plugin, $installed_plugins, $active_plugins);
                    if ($formatted !== null) {
                        $results[] = $formatted;
                    }
                }
            }

            // Apply sorting if not default
            if ($sort !== 'relevance' && !empty($browse)) {
                $results = $this->sort_results($results, $sort);
            }

            // Build response
            $response_data = array(
                'success' => true,
                'results' => $results,
                'pagination' => array(
                    'page' => $page,
                    'per_page' => $per_page,
                    'total' => isset($api_response->info['results']) ? $api_response->info['results'] : 0,
                    'total_pages' => isset($api_response->info['pages']) ? $api_response->info['pages'] : 0,
                ),
                'filters_applied' => array(
                    'query' => $query,
                    'browse' => $browse,
                    'category' => $category,
                    'tag' => $tag,
                    'author' => $author,
                    'sort' => $sort,
                ),
            );

            // Cache the response
            \set_transient($cache_key, $response_data, self::CACHE_SEARCH_DURATION);

            return \rest_ensure_response($response_data);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Plugin directory search error: ' . $e->getMessage());
            return new WP_Error('search_error', 'Error searching plugins: ' . $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Get plugin details
     */
    public function get_plugin_details(WP_REST_Request $request) // NOSONAR php:S100,php:S1142 — WP REST callback; multiple response paths
    {
        try {
            $auth_check = AuthMiddleware::check('authenticated');
            if (!$auth_check['authenticated']) {
                fleekdash_log_debug('FleekDash: Plugin details access without auth: ' . $auth_check['reason']);
            }

            $slug = $request->get_param('slug');

            // Check cache
            $cache_key = 'fleekdash_plugin_details_' . $slug;
            $cached = \get_transient($cache_key);

            if ($cached !== false) {
                return \rest_ensure_response($cached);
            }

            // Query WordPress.org API
            if (!function_exists('plugins_api')) {
                require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
            }

            $api_args = array(
                'slug' => $slug,
                'fields' => array(
                    'icons' => true,
                    'banners' => true,
                    'reviews' => true,
                    'downloaded' => true,
                    'active_installs' => true,
                    'short_description' => true,
                    'description' => true,
                    'sections' => true, // Installation, FAQ, Changelog
                    'tested' => true,
                    'requires' => true,
                    'requires_php' => true,
                    'rating' => true,
                    'ratings' => true,
                    'num_ratings' => true,
                    'homepage' => true,
                    'tags' => true,
                    'versions' => true,
                    'donate_link' => true,
                    'contributors' => true,
                    'last_updated' => true,
                    'added' => true,
                    'screenshots' => true,
                ),
            );

            $api_response = plugins_api('plugin_information', $api_args);

            if (is_wp_error($api_response)) {
                return new WP_Error(
                    'api_error',
                    'Plugin not found or WordPress.org API error',
                    array('status' => 404)
                );
            }

            // Convert array to object if needed (WordPress.org API returns arrays)
            if (is_array($api_response)) {
                $api_response = (object) $api_response;
            }

            // Get installed plugins for comparison
            $this->ensureWordPressPluginFunctionsLoaded(true, false);
            $installed_plugins = \get_plugins();
            $active_plugins = \get_option('active_plugins', array());

            // Format plugin data
            $formatted = $this->format_plugin_data($api_response, $installed_plugins, $active_plugins, true);

            // Cache the response
            \set_transient($cache_key, array('success' => true, 'plugin' => $formatted), self::CACHE_DETAILS_DURATION);

            return \rest_ensure_response(array(
                'success' => true,
                'plugin' => $formatted,
            ));

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Plugin details error: ' . $e->getMessage());
            return new WP_Error('details_error', 'Error getting plugin details: ' . $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Get plugin categories
     */
    public function get_categories(WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth_check = AuthMiddleware::check('authenticated');
            if (!$auth_check['authenticated']) {
                fleekdash_log_debug('FleekDash: Categories access without auth: ' . $auth_check['reason']);
            }

            // Check cache
            $cache_key = 'fleekdash_plugin_categories';
            $cached = \get_transient($cache_key);

            if ($cached !== false) {
                return \rest_ensure_response($cached);
            }

            // WordPress.org plugin categories (static list)
            $categories = array(
                array('slug' => 'analytics', 'name' => 'Analytics', 'count' => 0),
                array('slug' => 'backup', 'name' => 'Backup', 'count' => 0),
                array('slug' => 'block-editor', 'name' => 'Block Editor', 'count' => 0),
                array('slug' => 'cache', 'name' => 'Cache & Performance', 'count' => 0),
                array('slug' => 'commerce', 'name' => 'E-Commerce', 'count' => 0),
                array('slug' => 'forms', 'name' => 'Forms', 'count' => 0),
                array('slug' => 'gallery', 'name' => 'Gallery', 'count' => 0),
                array('slug' => 'marketing', 'name' => 'Marketing', 'count' => 0),
                array('slug' => 'media', 'name' => 'Media', 'count' => 0),
                array('slug' => 'mobile', 'name' => 'Mobile', 'count' => 0),
                array('slug' => 'page-builder', 'name' => 'Page Builder', 'count' => 0),
                array('slug' => 'payment', 'name' => 'Payment', 'count' => 0),
                array('slug' => 'security', 'name' => 'Security', 'count' => 0),
                array('slug' => 'seo', 'name' => 'SEO', 'count' => 0),
                array('slug' => 'social', 'name' => 'Social Media', 'count' => 0),
                array('slug' => 'widgets', 'name' => 'Widgets', 'count' => 0),
            );

            $response_data = array(
                'success' => true,
                'categories' => $categories,
            );
            $response_data = \apply_filters('fleekdash_plugin_directory_categories', $response_data, $request);

            // Cache for 24 hours
            \set_transient($cache_key, $response_data, self::CACHE_CATEGORIES_DURATION);

            return \rest_ensure_response($response_data);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Categories error: ' . $e->getMessage());
            return new WP_Error('categories_error', 'Error getting categories', array('status' => 500));
        }
    }

    /**
     * Get popular tags
     */
    public function get_tags(WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth_check = AuthMiddleware::check('authenticated');
            if (!$auth_check['authenticated']) {
                fleekdash_log_debug('FleekDash: Tags access without auth: ' . $auth_check['reason']);
            }

            // Check cache
            $cache_key = 'fleekdash_plugin_tags';
            $cached = \get_transient($cache_key);

            if ($cached !== false) {
                return \rest_ensure_response($cached);
            }

            // Popular tags (static list - would ideally come from WordPress.org API)
            $tags = array(
                array('slug' => 'seo', 'name' => 'SEO', 'count' => 0),
                array('slug' => 'analytics', 'name' => 'Analytics', 'count' => 0),
                array('slug' => 'social-media', 'name' => 'Social Media', 'count' => 0),
                array('slug' => 'security', 'name' => 'Security', 'count' => 0),
                array('slug' => 'backup', 'name' => 'Backup', 'count' => 0),
                array('slug' => 'cache', 'name' => 'Cache', 'count' => 0),
                array('slug' => 'ecommerce', 'name' => 'E-Commerce', 'count' => 0),
                array('slug' => 'contact-form', 'name' => 'Contact Form', 'count' => 0),
                array('slug' => 'email', 'name' => 'Email', 'count' => 0),
                array('slug' => 'gallery', 'name' => 'Gallery', 'count' => 0),
                array('slug' => 'slider', 'name' => 'Slider', 'count' => 0),
                array('slug' => 'woocommerce', 'name' => 'WooCommerce', 'count' => 0),
                array('slug' => 'payment', 'name' => 'Payment', 'count' => 0),
                array('slug' => 'booking', 'name' => 'Booking', 'count' => 0),
                array('slug' => 'membership', 'name' => 'Membership', 'count' => 0),
            );

            $response_data = array(
                'success' => true,
                'tags' => $tags,
            );
            $response_data = \apply_filters('fleekdash_plugin_directory_tags', $response_data, $request);

            // Cache for 24 hours
            \set_transient($cache_key, $response_data, self::CACHE_CATEGORIES_DURATION);

            return \rest_ensure_response($response_data);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Tags error: ' . $e->getMessage());
            return new WP_Error('tags_error', 'Error getting tags', array('status' => 500));
        }
    }

    /**
     * Get featured plugins
     */
    public function get_featured(WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth_check = AuthMiddleware::check('authenticated');
            if (!$auth_check['authenticated']) {
                fleekdash_log_debug('FleekDash: Featured plugins access without auth: ' . $auth_check['reason']);
            }

            // Use search with browse=featured
            $request->set_param('browse', 'featured');
            $request->set_param('per_page', 24);
            return $this->search_plugins($request);

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Featured plugins error: ' . $e->getMessage());
            return new WP_Error('featured_error', 'Error getting featured plugins', array('status' => 500));
        }
    }

    /**
     * Install plugin (synchronous in this request — same model as core admin-ajax install-plugin).
     * Job transient is still written for get_install_status / debugging; avoids wp-cron latency.
     */
    public function install_plugin(WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth_check = AuthMiddleware::check('admin');
            if (!$auth_check['authenticated']) {
                return new WP_Error('unauthorized', self::ERROR_MESSAGE_ADMIN_REQUIRED, array('status' => 403));
            }

            $slug = $request->get_param('slug');
            $activate = $request->get_param('activate');

            if (!\is_string($slug) || $slug === '') {
                return new WP_Error('invalid_slug', 'Plugin slug is required', array('status' => 400));
            }

            if (\function_exists('set_time_limit')) {
                @\set_time_limit(600);
            }
            if (\function_exists('ignore_user_abort')) {
                @\ignore_user_abort(true);
            }

            // Generate job ID
            $job_id = 'install_' . $slug . '_' . time();

            // Store initial job status
            $job_status = array(
                'state' => 'downloading',
                'progress' => 0,
                'step' => 'Starting installation for ' . $slug,
                'started_at' => \current_time('mysql'),
                'logs' => array(
                    '[' . \current_time('mysql') . '] Starting installation for ' . $slug,
                ),
                'slug' => $slug,
                'activate' => $activate,
            );

            \set_transient('fleekdash_install_job_' . $job_id, $job_status, 3600);

            PluginDirectoryInstaller::processInstallation($job_id);

            $final = \get_transient('fleekdash_install_job_' . $job_id);
            if ($final === false) {
                return new WP_Error('install_lost', 'Installation finished but job status was not found', array('status' => 500));
            }

            $is_complete = isset($final['state']) && $final['state'] === 'complete';
            $message = $is_complete
                ? ($final['step'] ?? 'Plugin installed successfully')
                : ($final['error'] ?? $final['step'] ?? 'Installation failed');

            return \rest_ensure_response(array(
                'success' => $is_complete,
                'job_id' => $job_id,
                'message' => $message,
                'status' => $final,
            ));

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Install plugin error: ' . $e->getMessage());
            return new WP_Error('install_error', 'Error starting installation: ' . $e->getMessage(), array('status' => 500));
        }
    }

    /**
     * Get installation status
     */
    public function get_install_status(WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth_check = AuthMiddleware::check('authenticated');
            if (!$auth_check['authenticated']) {
                fleekdash_log_debug('FleekDash: Install status access without auth');
            }

            $job_id = $request->get_param('job_id');

            $job_status = \get_transient('fleekdash_install_job_' . $job_id);

            if ($job_status === false) {
                return new WP_Error('job_not_found', 'Installation job not found', array('status' => 404));
            }

            return \rest_ensure_response(array(
                'success' => true,
                'job_id' => $job_id,
                'status' => $job_status,
            ));

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Install status error: ' . $e->getMessage());
            return new WP_Error('status_error', 'Error getting status', array('status' => 500));
        }
    }

    /**
     * Cancel installation
     */
    public function cancel_install(WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth_check = AuthMiddleware::check('admin');
            if (!$auth_check['authenticated']) {
                return new WP_Error('unauthorized', self::ERROR_MESSAGE_ADMIN_REQUIRED, array('status' => 403));
            }

            $job_id = $request->get_param('job_id');

            // Delete the job transient
            \delete_transient('fleekdash_install_job_' . $job_id);

            return \rest_ensure_response(array(
                'success' => true,
                'message' => 'Installation cancelled',
            ));

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Cancel install error: ' . $e->getMessage());
            return new WP_Error('cancel_error', 'Error cancelling installation', array('status' => 500));
        }
    }

    /**
     * Bulk action on plugins
     */
    public function bulk_action(WP_REST_Request $request) // NOSONAR php:S100 — WP REST callback name
    {
        try {
            $auth_check = AuthMiddleware::check('admin');
            if (!$auth_check['authenticated']) {
                return new WP_Error('unauthorized', self::ERROR_MESSAGE_ADMIN_REQUIRED, array('status' => 403));
            }

            $action = $request->get_param('action');
            $plugins = $request->get_param('plugins');

            $this->ensureWordPressPluginFunctionsLoaded(false, true);

            $results = array();

            foreach ($plugins as $plugin_file) {
                try {
                    switch ($action) {
                        case 'activate':
                            $result = \activate_plugin($plugin_file);
                            $success = !is_wp_error($result);
                            break;

                        case 'deactivate':
                            \deactivate_plugins($plugin_file);
                            $success = true;
                            break;

                        case 'update':
                            // Would call update logic
                            $success = false;
                            break;

                        case 'delete':
                            // Would call delete logic
                            $success = false;
                            break;

                        default:
                            $success = false;
                    }

                    $results[] = array(
                        'plugin' => $plugin_file,
                        'success' => $success,
                        'error' => !$success ? 'Action failed' : null,
                    );

                } catch (\Exception $e) {
                    $results[] = array(
                        'plugin' => $plugin_file,
                        'success' => false,
                        'error' => $e->getMessage(),
                    );
                }
            }

            return \rest_ensure_response(array(
                'success' => true,
                'results' => $results,
            ));

        } catch (\Exception $e) {
            fleekdash_log_error('FleekDash: Bulk action error: ' . $e->getMessage());
            return new WP_Error('bulk_error', 'Error performing bulk action', array('status' => 500));
        }
    }

    /**
     * Format plugin data for frontend
     *
     * @param array<string, mixed>|object $plugin WordPress.org API shape (array or object)
     * @param array<string, array<string, string>> $installed_plugins {@see get_plugins()}
     * @param array<int, string> $active_plugins Active plugin basenames from {@see get_option()}
     */
    private function format_plugin_data(array|object $plugin, array $installed_plugins, array $active_plugins, bool $full_details = false) // NOSONAR php:S100,php:S3776 — WP-style helper; normalization branches
    {
        // Convert array to object if needed (WordPress.org API returns arrays)
        if (is_array($plugin)) {
            $plugin = (object) $plugin;
        }

        // Ensure plugin is an object
        if (!is_object($plugin)) {
            return null;
        }

        // Ensure plugin object has required fields
        if (!isset($plugin->slug) || !isset($plugin->name)) {
            return null;
        }

        // Helper to safely get value
        $get = function($key, $default = '') use ($plugin) {
            return isset($plugin->$key) ? $plugin->$key : $default;
        };

        $formatted = array(
            'slug' => $get('slug'),
            'name' => $get('name'),
            'short_description' => $get('short_description'),
            'version' => $get('version'),
            'author' => $get('author'),
            'author_profile' => $get('author_profile'),
            'rating' => isset($plugin->rating) ? (float) $plugin->rating : 0,
            'ratings' => isset($plugin->ratings) ? (array) $plugin->ratings : array(),
            'num_ratings' => isset($plugin->num_ratings) ? (int) $plugin->num_ratings : 0,
            'active_installs' => isset($plugin->active_installs) ? (int) $plugin->active_installs : 0,
            'downloaded' => isset($plugin->downloaded) ? (int) $plugin->downloaded : 0,
            'last_updated' => $get('last_updated'),
            'added' => $get('added'),
            'homepage' => $get('homepage'),
            'download_link' => $get('download_link'),
            'icons' => isset($plugin->icons) ? (array) $plugin->icons : array(),
            'banners' => isset($plugin->banners) ? (array) $plugin->banners : array(),
            'requires' => $get('requires'),
            'requires_php' => $get('requires_php'),
            'tested' => $get('tested'),
            'tags' => isset($plugin->tags) ? array_keys((array) $plugin->tags) : array(),
            'is_installed' => false,
            'is_active' => false,
            'has_update' => false,
        );

        // Check if plugin is installed
        foreach ($installed_plugins as $plugin_file => $plugin_data) {
            $installed_slug = dirname($plugin_file);
            if ($installed_slug === '.' || $installed_slug === '') {
                $installed_slug = basename($plugin_file, '.php');
            }

            if ($installed_slug === $plugin->slug) {
                $formatted['is_installed'] = true;
                $formatted['installed_version'] = $plugin_data['Version'];
                $formatted['installed_file'] = $plugin_file;

                // Check if active
                if (in_array($plugin_file, $active_plugins)) {
                    $formatted['is_active'] = true;
                }

                // Check if has update
                if (version_compare($plugin->version, $plugin_data['Version'], '>')) {
                    $formatted['has_update'] = true;
                }

                break;
            }
        }

        // Add full details if requested
        if ($full_details) {
            $formatted['description'] = isset($plugin->description) ? $plugin->description : '';
            $formatted['sections'] = isset($plugin->sections) ? (array) $plugin->sections : array();
            $formatted['screenshots'] = isset($plugin->screenshots) ? (array) $plugin->screenshots : array();
            $formatted['contributors'] = isset($plugin->contributors) ? array_keys((array) $plugin->contributors) : array();
            $formatted['donate_link'] = isset($plugin->donate_link) ? $plugin->donate_link : '';
            $formatted['versions'] = isset($plugin->versions) ? (array) $plugin->versions : array();
        }

        return $formatted;
    }

    /**
     * Sort results by specified field
     *
     * @param array<int, array<string, mixed>> $results
     */
    private function sort_results(array $results, string $sort) // NOSONAR php:S100,php:S3776 — WP-style helper; usort comparator below
    {
        if (empty($results) || !is_array($results)) {
            return $results;
        }

        usort($results, function ($a, $b) use ($sort) { // NOSONAR php:S1142 — explicit comparator cases
            switch ($sort) {
                case 'popularity':
                    $a_installs = isset($a['active_installs']) ? (int) $a['active_installs'] : 0;
                    $b_installs = isset($b['active_installs']) ? (int) $b['active_installs'] : 0;
                    return $b_installs - $a_installs;

                case 'rating':
                    $a_rating = isset($a['rating']) ? (float) $a['rating'] : 0;
                    $b_rating = isset($b['rating']) ? (float) $b['rating'] : 0;
                    return $b_rating <=> $a_rating;

                case 'updated':
                    $a_time = isset($a['last_updated']) ? strtotime($a['last_updated']) : 0;
                    $b_time = isset($b['last_updated']) ? strtotime($b['last_updated']) : 0;
                    return $b_time - $a_time;

                case 'name':
                    $a_name = isset($a['name']) ? $a['name'] : '';
                    $b_name = isset($b['name']) ? $b['name'] : '';
                    return strcmp($a_name, $b_name);

                default:
                    return 0;
            }
        });

        return $results;
    }

    /**
     * Load wp-admin plugin helpers when core functions are not yet available.
     *
     * @param bool $needsGetPlugins When true, loads if get_plugins() is missing.
     * @param bool $needsActivation When true, loads if activate/deactivate helpers are missing.
     */
    private function ensureWordPressPluginFunctionsLoaded($needsGetPlugins, $needsActivation)
    {
        $needsLoad = ($needsGetPlugins && !\function_exists('get_plugins'))
            || ($needsActivation && (!\function_exists('activate_plugin') || !\function_exists('deactivate_plugins')));
        if (!$needsLoad) {
            return;
        }
        PluginHelper::ensurePluginApiLoaded();
    }
}
