<?php

/**
 * Modules REST API Controller
 *
 * Handles module management endpoints
 *
 * @package ProRank\SEO\Core\RestApi
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core\RestApi;

use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use ProRank\SEO\Core\ModuleManager;

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


/**
 * Modules controller class
 */


class ModulesController extends BaseController {
    
    /**
     * Rest base
     *
     * @var string
     */
    protected $rest_base = 'modules';
    
    /**
     * Module manager instance
     *
     * @var ModuleManager|null
     */
    private ?ModuleManager $module_manager = null;
    
    /**
     * Constructor
     */
    public function __construct() {
        // Module manager will be set when routes are registered
    }
    
    /**
     * Set module manager
     *
     * @param ModuleManager $module_manager Module manager instance
     * @return void
     */
    public function set_module_manager(ModuleManager $module_manager): void {
        $this->module_manager = $module_manager;
    }
    /**
     * Check if premium plugin is active
     *
     * @return bool
     */
    private function is_premium_active(): bool {
        if (defined('PRORANK_PREMIUM_VERSION')) {
            return true;
        }

        if (function_exists('is_plugin_active')) {
            return is_plugin_active('prorank-seo-premium/prorank-seo.php')
                || is_plugin_active('prorank-seo-premium/prorank-seo-premium.php');
        }

        return false;
    }

    /**
     * Canonical module group tier map used by group toggles and lock checks.
     *
     * @return array<string, string>
     */
    private function get_module_group_tier_map(): array {
        return [
            'on-page-seo' => 'free',
            'technical-seo' => 'free',
            'performance' => 'free',
            'support' => 'free',
        ];
    }

    /**
     * Canonical free-module allowlist by group.
     *
     * This is a hard safety net for free builds so stale premium files or
     * mismatched metadata cannot leak paid modules into free UI.
     *
     * @return array<string, array<int, string>>
     */
    private function get_free_module_allowlist_by_group(): array {
        return [
            'on-page-seo' => [
                'site-basics',
                'titles-meta',
                'breadcrumbs',
                'schema-markup',
                'content-analysis',
                'internal-linking',
                'podcast-seo',
            ],
            'technical-seo' => [
                'sitemaps',
                'robots-indexing',
                'redirects',
                'url-cleanup',
                'head_cleanup',
            ],
            'performance' => [
                'cache',
                'modern_cache',
                'browser_cache',
                'js_opt',
                'css_opt',
                'js_minify',
                'html_minify',
                'resource_hints',
                'font_optimization',
                'cls_prevention',
                'lcp_beacon',
                'lazyload',
                'image_optimization',
                'database_optimization',
            ],
            'support' => [],
        ];
    }

    /**
     * Check if a module slug is allowed for free build output.
     *
     * @param string      $slug
     * @param string|null $parent_slug
     * @return bool
     */
    private function is_allowed_free_module_slug(string $slug, ?string $parent_slug = null): bool {
        $allowlist = $this->get_free_module_allowlist_by_group();

        if ($parent_slug !== null) {
            if (!isset($allowlist[$parent_slug])) {
                return false;
            }

            return in_array($slug, $allowlist[$parent_slug], true);
        }

        foreach ($allowlist as $group_slugs) {
            if (in_array($slug, $group_slugs, true)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Resolve a module group tier from its slug.
     *
     * @param string $group_slug
     * @return string
     */
    private function get_module_group_tier(string $group_slug): string {
        $map = $this->get_module_group_tier_map();
        return $map[$group_slug] ?? 'free';
    }

    /**
     * Determine if a tier is locked for the current installation.
     *
     * @param string $tier
     * @return bool
     */
    private function is_tier_locked(string $tier): bool {
        if ($tier === 'core') {
            $tier = 'pro';
        }

        if ($tier === 'free') {
            return false;
        }

        // Free build policy: non-free tiers are not available.
        return true;
    }

    /**
     * Persist module group enabled state in both group-state and active-modules options.
     *
     * @param string $group_slug
     * @param bool   $enabled
     * @return void
     */
    private function save_module_group_state(string $group_slug, bool $enabled): void {
        $group_states = get_option('prorank_seo_module_groups', []);
        if (!is_array($group_states)) {
            $group_states = [];
        }
        $group_states[$group_slug] = $enabled;
        update_option('prorank_seo_module_groups', $group_states);

        $settings = get_option('prorank_settings', []);
        if (!is_array($settings)) {
            $decoded = json_decode((string) $settings, true);
            $settings = is_array($decoded) ? $decoded : [];
        }
        if (!isset($settings['active_modules']) || !is_array($settings['active_modules'])) {
            $settings['active_modules'] = [];
        }
        $settings['active_modules'][$group_slug] = $enabled;
        update_option('prorank_settings', $settings);
    }

    
    /**
     * Register routes
     *
     * @return void
     */
    public function register_routes(): void {
        // Get all modules
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base,
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_modules'],
                    'permission_callback' => [$this, 'check_permission'],
                ],
            ]
        );
        
        // Get module groups
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/groups',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_module_groups'],
                    'permission_callback' => [$this, 'check_permission'],
                ],
            ]
        );
        
        // Toggle module group status
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/groups/(?P<group>[a-zA-Z0-9_-]+)/status',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'toggle_module_group'],
                    'permission_callback' => [$this, 'check_permission'],
                    'args'                => [
                        'group' => [
                            'required'          => true,
                            'sanitize_callback' => 'sanitize_key',
                        ],
                        'enabled' => [
                            'required'          => true,
                            'type'              => 'boolean',
                        ],
                    ],
                ],
            ]
        );
        
        // Toggle module
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/(?P<module>[a-zA-Z0-9_-]+)/toggle',
            [
                [
                    'methods'             => WP_REST_Server::CREATABLE,
                    'callback'            => [$this, 'toggle_module'],
                    'permission_callback' => [$this, 'check_permission'],
                    'args'                => [
                        'module' => [
                            'required'          => true,
                            'sanitize_callback' => 'sanitize_key',
                        ],
                        'enabled' => [
                            'required'          => true,
                            'type'              => 'boolean',
                        ],
                    ],
                ],
            ]
        );
        
        // Get module status
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/(?P<module>[a-zA-Z0-9_-]+)/status',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_module_status'],
                    'permission_callback' => [$this, 'check_permission'],
                    'args'                => [
                        'module' => [
                            'required'          => true,
                            'sanitize_callback' => 'sanitize_key',
                        ],
                    ],
                ],
            ]
        );
        
        // Dashboard module status (simplified)
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/status',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_modules_status'],
                    'permission_callback' => [$this, 'check_permission'],
                ],
            ]
        );

        // Get modules by parent group
        register_rest_route(
            $this->namespace,
            '/' . $this->rest_base . '/by-group/(?P<group>[a-zA-Z0-9_-]+)',
            [
                [
                    'methods'             => WP_REST_Server::READABLE,
                    'callback'            => [$this, 'get_modules_by_group'],
                    'permission_callback' => [$this, 'check_permission'],
                    'args'                => [
                        'group' => [
                            'required'          => true,
                            'sanitize_callback' => 'sanitize_key',
                        ],
                    ],
                ],
            ]
        );
    }
    
    /**
     * Get all modules
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_modules(WP_REST_Request $request) {
        if (!$this->module_manager) {
            return $this->get_error_response(
                __('Module manager not available', 'prorank-seo'),
                500
            );
        }
        
        try {
            $modules = $this->module_manager->get_modules();
            $module_data = [];
            $manifest_data = $this->get_module_manifest_data();
            
            
            foreach ($modules as $slug => $module) {
                $manifest_info = $manifest_data[$slug] ?? null;
                $is_enabled = $this->module_manager->is_module_enabled($slug);
                $tier = $module->get_feature_tier();
                if ($tier === 'core') {
                    $tier = 'pro';
                }
                if ($tier !== 'free') {
                    continue;
                }

                $parent_slug = $module->get_parent_slug();
                if (!$this->is_allowed_free_module_slug((string) $slug, $parent_slug)) {
                    continue;
                }
                $category = $manifest_info['category'] ?? ($parent_slug ? $parent_slug : __('General', 'prorank-seo'));
                $module_data[] = [
                    'slug' => $slug,
                    'name' => $module->get_name(),
                    'description' => $module->get_description(),
                    'tier' => $tier,
                    'parent_slug' => $parent_slug,
                    'category' => $category,
                    'icon' => (is_array($manifest_info) && !empty($manifest_info['icon_token'])) ? $this->get_icon_class($manifest_info['icon_token']) : 'dashicons-admin-generic',
                    'enabled' => $is_enabled,
                    'available' => true,
                    'features' => [],
                    'recommended' => (bool)($manifest_info['recommended'] ?? false),
                    'core' => (bool)($manifest_info['core'] ?? false),
                ];
            }

            // Also include any free modules from catalog that are not loaded.
            $all_modules = $module_data;
            foreach ($manifest_data as $slug => $manifest_module) {
                $manifest_tier = (string) ($manifest_module['tier'] ?? 'free');
                if ($manifest_tier === 'core') {
                    $manifest_tier = 'pro';
                }
                if ($manifest_tier !== 'free') {
                    continue;
                }
                $manifest_parent = $manifest_module['parent_slug'] ?? ($manifest_module['parent'] ?? null);
                if (!$this->is_allowed_free_module_slug((string) $slug, $manifest_parent)) {
                    continue;
                }
                // Check if this is a parent module not in the loaded modules
                if (!isset($modules[$slug])) {
                    $category = $manifest_module['category'] ?? __('General', 'prorank-seo');
                    $all_modules[] = [
                        'slug' => $slug,
                        'name' => $manifest_module['name'] ?? $slug,
                        'description' => $manifest_module['description'] ?? '',
                        'tier' => 'free',
                        'parent_slug' => $manifest_parent,
                        'category' => $category,
                        'icon' => (!empty($manifest_module['icon_token']) ? $this->get_icon_class($manifest_module['icon_token']) : 'dashicons-admin-generic'),
                        'enabled' => empty($manifest_module['parent_slug'] ?? ($manifest_module['parent'] ?? null)),
                        'available' => true,
                        'features' => [],
                        'recommended' => (bool)($manifest_module['recommended'] ?? false),
                        'core' => (bool)($manifest_module['core'] ?? false),
                    ];
                }
            }
            
            // Log what we're returning
            $technical_modules_count = count(array_filter($all_modules, function($m) { 
                return $m['parent_slug'] === 'technical-seo';
            }));
            $on_page_modules_count = count(array_filter($all_modules, function($m) { 
                return $m['parent_slug'] === 'on-page-seo';
            }));

            if (defined('WP_DEBUG') && WP_DEBUG) {
                prorank_log("[ProRank SEO] Returning total modules: " . count($all_modules));
                prorank_log("[ProRank SEO] Technical SEO child modules: " . $technical_modules_count);
                prorank_log("[ProRank SEO] On-Page SEO child modules: " . $on_page_modules_count);
            }

            // Only include free-tier modules in the free plugin
            $free_modules = array_values(array_filter($all_modules, function($module) {
                $tier = $module['tier'] ?? 'free';
                return $tier === 'free' || $tier === 'core';
            }));

            foreach ($free_modules as &$module) {
                $module['available'] = true;
                unset($module['locked']);
            }
            unset($module);

            return rest_ensure_response([
                'modules' => $free_modules,
                'total' => count($free_modules),
            ]);

        } catch (\Exception $e) {
            return $this->get_error_response(
                sprintf(
                    /* translators: %s: error message */
                    __('Failed to get modules: %1$s', 'prorank-seo'),
                    esc_html($e->getMessage())
                ),
                500
            );
        }
    }
    
    /**
     * Toggle module activation
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function toggle_module(WP_REST_Request $request) {
        $requested_slug = sanitize_key((string) $request->get_param('module'));
        $module_slug = $this->normalize_module_slug($requested_slug);
        $enabled = rest_sanitize_boolean($request->get_param('enabled'));

        if (!$this->module_manager) {
            return $this->get_error_response(
                __('Module manager not available', 'prorank-seo'),
                500
            );
        }

        try {
            // Check if this is a module group slug (used by Module Manager UI)
            $group_slugs = array_keys($this->get_module_group_tier_map());
            if (in_array($module_slug, $group_slugs, true)) {
                $group_tier = $this->get_module_group_tier($module_slug);
                if ($this->is_tier_locked($group_tier)) {
                    return $this->get_error_response(
                        __('This module group is not available on your current plan.', 'prorank-seo'),
                        403
                    );
                }

                // Toggle the module group state
                $this->save_module_group_state((string) $module_slug, (bool) $enabled);

                // Also toggle the top-level module if it exists
                $modules = $this->module_manager->get_modules();
                if (isset($modules[$module_slug])) {
                    if ($enabled) {
                        $this->module_manager->activate_module($module_slug);
                    } else {
                        $this->module_manager->deactivate_module($module_slug);
                    }
                }

                // Toggle child modules in this group
                foreach ($modules as $slug => $module) {
                    if (!is_object($module) || !method_exists($module, 'get_parent_slug')) {
                        continue;
                    }
                    if ($module->get_parent_slug() === $module_slug) {
                        if ($enabled) {
                            $this->module_manager->activate_module($slug);
                        } else {
                            $this->module_manager->deactivate_module($slug);
                        }
                    }
                }

                do_action('prorank_seo_module_toggled', $module_slug, $enabled);

                return rest_ensure_response([
                    'success' => true,
                    'message' => sprintf(
                        /* translators: 1: Module slug, 2: enable/disable status text. */
                        __('Module group "%1$s" %2$s successfully', 'prorank-seo'),
                        $module_slug,
                        $enabled ? 'enabled' : 'disabled'
                    ),
                    'module' => $module_slug,
                    'active' => $enabled,
                ]);
            }

            // Check if module exists as individual module
            $modules = $this->module_manager->get_modules();
            $resolved_slug = $this->resolve_registered_module_slug($module_slug, $modules);
            if ($resolved_slug === null) {
                return $this->get_error_response(
                    sprintf(
                        /* translators: %1$s: Requested module slug. */
                        __('Module "%1$s" not found', 'prorank-seo'),
                        $requested_slug
                    ),
                    404
                );
            }
            $module_slug = $resolved_slug;
            $module = $modules[$module_slug];

            $module_tier = method_exists($module, 'get_feature_tier')
                ? (string) $module->get_feature_tier()
                : 'free';
            if ($this->is_tier_locked($module_tier)) {
                return $this->get_error_response(
                    __('This module is not available on your current plan.', 'prorank-seo'),
                    403
                );
            }

            // Toggle individual module
            if ($enabled) {
                $this->module_manager->activate_module($module_slug);
            } else {
                $this->module_manager->deactivate_module($module_slug);
            }

            // Trigger action
            do_action('prorank_seo_module_toggled', $module_slug, $enabled);

            return rest_ensure_response([
                'success' => true,
                'message' => sprintf(
                    /* translators: 1: Requested module slug, 2: activation status text. */
                    __('Module "%1$s" %2$s successfully', 'prorank-seo'),
                    $requested_slug,
                    $enabled ? 'activated' : 'deactivated'
                ),
                'module' => $requested_slug,
                'resolved_module' => $module_slug,
                'active' => $enabled,
            ]);

        } catch (\Throwable $e) {
            prorank_log('ProRank SEO - Module toggle error: ' . $e->getMessage());
            if (defined('WP_DEBUG') && WP_DEBUG) {
                prorank_log('ProRank SEO - Module toggle trace: ' . $e->getTraceAsString());
            }
            return $this->get_error_response(
                sprintf(
                    /* translators: %1$s: Throwable error message. */
                    __('Failed to toggle module: %1$s', 'prorank-seo'),
                    esc_html($e->getMessage())
                ),
                500
            );
        }
    }
    
    /**
     * Get module status
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_module_status(WP_REST_Request $request) {
        $requested_slug = sanitize_key((string) $request->get_param('module'));
        $module_slug = $this->normalize_module_slug($requested_slug);
        
        if (!$this->module_manager) {
            return $this->get_error_response(
                __('Module manager not available', 'prorank-seo'),
                500
            );
        }
        
        try {
            // Check if module exists
            $modules = $this->module_manager->get_modules();
            $resolved_slug = $this->resolve_registered_module_slug($module_slug, $modules);
            if ($resolved_slug === null) {
                return $this->get_error_response(
                    sprintf(
                        /* translators: %s: module slug */
                        __('Module "%1$s" not found', 'prorank-seo'),
                        $requested_slug
                    ),
                    404
                );
            }
            $module_slug = $resolved_slug;
            
            $module = $modules[$module_slug];
            $config = method_exists($module, 'get_config') ? $module->get_config() : [];
            
            $parent_slug = $config['parent']
                ?? ($config['parent_slug'] ?? (method_exists($module, 'get_parent_slug') ? $module->get_parent_slug() : null));
            $module_name = $config['name'] ?? (method_exists($module, 'get_name') ? $module->get_name() : $module_slug);
            $module_tier = $config['tier'] ?? (method_exists($module, 'get_feature_tier') ? $module->get_feature_tier() : 'free');

            return rest_ensure_response([
                'slug' => $module_slug,
                'requested_slug' => $requested_slug,
                'active' => $this->module_manager->is_active($module_slug),
                'name' => $module_name,
                'tier' => $module_tier,
                'parent' => $parent_slug,
                'parent_active' => $parent_slug ? $this->module_manager->is_active((string) $parent_slug) : true,
            ]);
            
        } catch (\Throwable $e) {
            return $this->get_error_response(
                sprintf(
                    /* translators: %s: error message */
                    __('Failed to get module status: %1$s', 'prorank-seo'),
                    esc_html($e->getMessage())
                ),
                500
            );
        }
    }
    
    /**
     * Get module manifest data
     *
     * In production we can ship a static module catalog (generated at build/release time)
     * to describe available free modules.
     *
     * @return array<string, array<string, mixed>>
     */
    private function get_module_manifest_data(): array {
        $manifest_file = PRORANK_PLUGIN_DIR . 'config/module-catalog.json';

        if (!file_exists($manifest_file)) {
            return [];
        }

        $raw = file_get_contents($manifest_file);
        if ($raw === false) {
            return [];
        }

        $decoded = json_decode($raw, true);
        if (!is_array($decoded) || !isset($decoded['modules']) || !is_array($decoded['modules'])) {
            return [];
        }

        return $decoded['modules'];
    }

    /**
     * Normalize known legacy or UI-only module aliases to runtime module slugs.
     *
     * @param string $slug
     * @return string
     */
    private function normalize_module_slug(string $slug): string {
        return $slug;
    }

    /**
     * Resolve a module slug against registered module keys and module->get_slug().
     *
     * @param string $slug
     * @param array  $modules
     * @return string|null
     */
    private function resolve_registered_module_slug(string $slug, array $modules): ?string {
        if (isset($modules[$slug])) {
            return $slug;
        }

        foreach ($modules as $id => $mod) {
            if (is_object($mod) && method_exists($mod, 'get_slug') && $mod->get_slug() === $slug) {
                return (string) $id;
            }
        }

        return null;
    }

    /**
     * Get module groups
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_module_groups(WP_REST_Request $request) {
        if (!$this->module_manager) {
            return $this->get_error_response(
                __('Module manager not available', 'prorank-seo'),
                500
            );
        }
        
        try {
            // Define main module groups
            $groups = [
                [
                    'slug' => 'on-page-seo',
                    'name' => __('On-Page SEO', 'prorank-seo'),
                    'description' => __('Content optimization, readability analysis, and internal linking', 'prorank-seo'),
                    'tier' => 'free',
                    'enabled' => $this->is_module_group_enabled('on-page-seo'),
                ],
                [
                    'slug' => 'technical-seo',
                    'name' => __('Technical SEO', 'prorank-seo'),
                    'description' => __('Sitemaps, redirects, robots.txt, and URL cleanup', 'prorank-seo'),
                    'tier' => 'free',
                    'enabled' => $this->is_module_group_enabled('technical-seo'),
                ],
                [
                    'slug' => 'performance',
                    'name' => __('Performance', 'prorank-seo'),
                    'description' => __('Speed optimization, caching, and critical CSS', 'prorank-seo'),
                    'tier' => 'free',
                    'enabled' => $this->is_module_group_enabled('performance'),
                ],
                [
                    'slug' => 'support',
                    'name' => __('Support & Tools', 'prorank-seo'),
                    'description' => __('Documentation, diagnostics, and priority support', 'prorank-seo'),
                    'tier' => 'free',
                    'enabled' => $this->is_module_group_enabled('support'),
                ],
            ];

            // Only include free-tier groups in the free plugin
            $free_groups = array_values(array_filter($groups, function($group) {
                $tier = $group['tier'] ?? 'free';
                return $tier === 'free' || $tier === 'core';
            }));

            foreach ($free_groups as &$group) {
                $group['available'] = true;
                unset($group['locked']);
            }
            unset($group);

            return rest_ensure_response([
                'groups' => $free_groups,
                'total' => count($free_groups),
            ]);
            
        } catch (\Exception $e) {
            return $this->get_error_response(
                sprintf(
                    /* translators: %s: error message */
                    __('Failed to get module groups: %1$s', 'prorank-seo'),
                    esc_html($e->getMessage())
                ),
                500
            );
        }
    }
    
    /**
     * Toggle module group status
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function toggle_module_group(WP_REST_Request $request) {
        $group_slug = $request->get_param('group');
        $enabled = rest_sanitize_boolean($request->get_param('enabled'));
        
        if (!$this->module_manager) {
            return $this->get_error_response(
                __('Module manager not available', 'prorank-seo'),
                500
            );
        }

        $group_tier = $this->get_module_group_tier((string) $group_slug);
        if ($this->is_tier_locked($group_tier)) {
            return $this->get_error_response(
                __('This module group is not available on your current plan.', 'prorank-seo'),
                403
            );
        }
        
        try {
            // Get all modules in this group
            $modules = $this->module_manager->get_modules();
            $affected_modules = [];
            
            foreach ($modules as $slug => $module) {
                if (!is_object($module) || !method_exists($module, 'get_parent_slug')) {
                    continue;
                }
                if ($module->get_parent_slug() === $group_slug) {
                    if ($enabled) {
                        $this->module_manager->activate_module($slug);
                    } else {
                        $this->module_manager->deactivate_module($slug);
                    }
                    $affected_modules[] = $slug;
                }
            }
            
            // Save group state
            $this->save_module_group_state((string) $group_slug, (bool) $enabled);

            do_action('prorank_seo_module_group_toggled', (string) $group_slug, (bool) $enabled);
            
            return rest_ensure_response([
                'success' => true,
                'message' => sprintf(
                    /* translators: 1: module group slug, 2: status (enabled/disabled) */
                    __('Module group "%1$s" %2$s successfully', 'prorank-seo'),
                    $group_slug,
                    $enabled ? 'enabled' : 'disabled'
                ),
                'group' => $group_slug,
                'enabled' => $enabled,
                'affected_modules' => $affected_modules,
            ]);
            
        } catch (\Exception $e) {
            return $this->get_error_response(
                sprintf(
                    /* translators: %s: error message */
                    __('Failed to toggle module group: %1$s', 'prorank-seo'),
                    esc_html($e->getMessage())
                ),
                500
            );
        }
    }
    
    /**
     * Check if module group is enabled
     *
     * @param string $group_slug Group slug
     * @return bool
     */
    private function is_module_group_enabled(string $group_slug): bool {
        $group_states = get_option('prorank_seo_module_groups', []);
        
        // Default enabled groups when no explicit state exists yet.
        // Performance is opt-in by default to avoid unexpected frontend mutations.
        if (!isset($group_states[$group_slug])) {
            return in_array($group_slug, ['on-page-seo', 'technical-seo'], true);
        }
        
        return (bool) $group_states[$group_slug];
    }
    
    /**
     * Get modules by parent group
     *
     * Returns modules for the requested group.
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_modules_by_group(WP_REST_Request $request) {
        $group_slug = $request->get_param('group');

        if (!$this->module_manager) {
            return $this->get_error_response(
                __('Module manager not available', 'prorank-seo'),
                500
            );
        }

        try {
            $loaded_modules = $this->module_manager->get_modules();
            $manifest_data = $this->get_module_manifest_data();

            $group_modules = [];

            // Prefer manifest-driven list when available.
            if (!empty($manifest_data)) {
                foreach ($manifest_data as $slug => $manifest_module) {
                    if (!is_array($manifest_module)) {
                        continue;
                    }

                    $parent_slug = $manifest_module['parent_slug'] ?? ($manifest_module['parent'] ?? null);
                    if ($parent_slug !== $group_slug) {
                        continue;
                    }

                    $module = $loaded_modules[$slug] ?? null;

                    $tier = (string) ($manifest_module['tier'] ?? 'free');
                    $name = (string) ($manifest_module['name'] ?? $slug);
                    $description = (string) ($manifest_module['description'] ?? '');
                    if ($tier === 'core') {
                        $tier = 'pro';
                    }
                    if ($tier !== 'free') {
                        continue;
                    }
                    if (!$this->is_allowed_free_module_slug((string) $slug, is_string($group_slug) ? $group_slug : null)) {
                        continue;
                    }

                    $is_enabled = false;
                    if (is_object($module)) {
                        $tier = (string) $module->get_feature_tier();
                        if ($tier === 'core') {
                            $tier = 'pro';
                        }
                        if ($tier !== 'free') {
                            continue;
                        }
                        $name = (string) $module->get_name();
                        $description = (string) $module->get_description();
                        $is_enabled = $this->module_manager->is_module_enabled($slug);
                    }

                    $icon = (!empty($manifest_module['icon_token'])
                        ? $this->get_icon_class($manifest_module['icon_token'])
                        : 'dashicons-admin-generic'
                    );

                    $group_modules[] = [
                        'slug' => $slug,
                        'name' => $name,
                        'description' => $description,
                        'tier' => $tier,
                        'parent_slug' => $group_slug,
                        'icon' => $icon,
                        'enabled' => $is_enabled,
                        'features' => [],
                    ];
                }
            } else {
                // Fallback: legacy behavior based on loaded modules only.
                foreach ($loaded_modules as $slug => $module) {
                    if (!is_object($module) || !method_exists($module, 'get_parent_slug')) {
                        continue;
                    }
                    $parent_slug = $module->get_parent_slug();
                    if ($parent_slug !== $group_slug) {
                        continue;
                    }

                    $tier = (string) $module->get_feature_tier();
                    if ($tier === 'core') {
                        $tier = 'pro';
                    }
                    if ($tier !== 'free') {
                        continue;
                    }
                    if (!$this->is_allowed_free_module_slug((string) $slug, is_string($parent_slug) ? $parent_slug : null)) {
                        continue;
                    }

                    $group_modules[] = [
                        'slug' => $slug,
                        'name' => (string) $module->get_name(),
                        'description' => (string) $module->get_description(),
                        'tier' => $tier,
                        'parent_slug' => $parent_slug,
                        'icon' => 'dashicons-admin-generic',
                        'enabled' => $this->module_manager->is_module_enabled($slug),
                        'features' => [],
                    ];
                }
            }

            // Only include free-tier modules
            $group_modules = array_values(array_filter($group_modules, function($module) {
                $tier = $module['tier'] ?? 'free';
                return $tier === 'free' || $tier === 'core';
            }));

            foreach ($group_modules as &$module) {
                $module['available'] = true;
                unset($module['locked']);
            }
            unset($module);

            // Get group info
            $group_info = null;
            $groups_response = $this->get_module_groups(new WP_REST_Request());
            $groups = is_object($groups_response) && isset($groups_response->data['groups']) ? $groups_response->data['groups'] : [];
            foreach ($groups as $group) {
                if (($group['slug'] ?? null) === $group_slug) {
                    $group_info = $group;
                    break;
                }
            }

            return rest_ensure_response([
                'group' => $group_info,
                'modules' => $group_modules,
                'total' => count($group_modules),
            ]);

        } catch (\Exception $e) {
            return $this->get_error_response(
                sprintf(
                    /* translators: %s: error message */
                    __('Failed to get modules by group: %1$s', 'prorank-seo'),
                    esc_html($e->getMessage())
                ),
                500
            );
        }
    }

    /**
     * Get module groups status for dashboard overview
     *
     * Returns high-level module groups with counts of enabled child modules
     *
     * @param WP_REST_Request $request Request object
     * @return WP_REST_Response|WP_Error
     */
    public function get_modules_status(WP_REST_Request $request) {
        if (!$this->module_manager) {
            return $this->get_error_response(
                __('Module manager not available', 'prorank-seo'),
                500
            );
        }

        try {
            $modules = $this->module_manager->get_modules();

            // Define main module groups
            $groups = [
                'on-page-seo' => [
                    'slug' => 'on-page-seo',
                    'name' => __('On-Page SEO', 'prorank-seo'),
                    'description' => __('Meta tags, schema, internal linking', 'prorank-seo'),
                    'total' => 0,
                    'enabled_count' => 0,
                ],
                'technical-seo' => [
                    'slug' => 'technical-seo',
                    'name' => __('Technical SEO', 'prorank-seo'),
                    'description' => __('Sitemaps, redirects, robots.txt', 'prorank-seo'),
                    'total' => 0,
                    'enabled_count' => 0,
                ],
                'performance' => [
                    'slug' => 'performance',
                    'name' => __('Performance', 'prorank-seo'),
                    'description' => __('Caching, optimization, Core Web Vitals', 'prorank-seo'),
                    'total' => 0,
                    'enabled_count' => 0,
                ],
            ];

            // Count modules per group
            foreach ($modules as $slug => $module) {
                try {
                    if (!is_object($module) || !method_exists($module, 'get_parent_slug')) {
                        continue;
                    }
                    $parent_slug = $module->get_parent_slug();

                    // Skip parent modules themselves
                    if (empty($parent_slug)) {
                        continue;
                    }

                    if (method_exists($module, 'get_feature_tier')) {
                        $tier = (string) $module->get_feature_tier();
                        if ($tier === 'core') {
                            $tier = 'pro';
                        }
                        if ($tier !== 'free') {
                            continue;
                        }
                    }

                    // Map parent slugs to groups
                    $group_key = $parent_slug;

                    if (isset($groups[$group_key])) {
                        $groups[$group_key]['total']++;
                        if ($this->module_manager->is_module_enabled($slug)) {
                            $groups[$group_key]['enabled_count']++;
                        }
                    }
                } catch (\Exception $e) {
                    continue;
                }
            }

            // Convert to array and calculate enabled status
            $module_groups = [];
            foreach ($groups as $group) {
                // Only include groups that have modules
                if ($group['total'] > 0) {
                    $group['enabled'] = $group['enabled_count'] > 0;
                    $module_groups[] = $group;
                }
            }

            // Sort by enabled count descending
            usort($module_groups, function ($a, $b) {
                return $b['enabled_count'] - $a['enabled_count'];
            });

            return rest_ensure_response([
                'modules' => $module_groups,
            ]);
        } catch (\Exception $e) {
            return $this->get_error_response(
                sprintf(
                    /* translators: %s: error message */
                    __('Failed to get module status: %1$s', 'prorank-seo'),
                    esc_html($e->getMessage())
                ),
                500
            );
        }
    }

    /**
     * Convert icon token to dashicon class
     *
     * @param string $icon_token Icon token from manifest
     * @return string Dashicon class
     */
    private function get_icon_class(string $icon_token): string {
        // Map icon tokens to dashicon classes
        $icon_map = [
            '--pr-icon-dashboard' => 'dashicons-dashboard',
            '--pr-icon-on-page' => 'dashicons-edit',
            '--pr-icon-titles-meta' => 'dashicons-tag',
            '--pr-icon-content-analysis' => 'dashicons-analytics',
            '--pr-icon-schema' => 'dashicons-editor-code',
            '--pr-icon-schema-advanced' => 'dashicons-editor-expand',
            '--pr-icon-technical' => 'dashicons-admin-tools',
            '--pr-icon-sitemap' => 'dashicons-networking',
            '--pr-icon-author-sitemap' => 'dashicons-admin-users',
            '--pr-icon-video-sitemap' => 'dashicons-video-alt3',
            '--pr-icon-redirects' => 'dashicons-randomize',
            '--pr-icon-redirect-log' => 'dashicons-text-page',
            '--pr-icon-performance' => 'dashicons-performance',
            '--pr-icon-cache' => 'dashicons-database',
            '--pr-icon-critical-css' => 'dashicons-art',
            '--pr-icon-analytics' => 'dashicons-chart-area',
            '--pr-icon-search-console' => 'dashicons-google',
            '--pr-icon-local' => 'dashicons-location',
            '--pr-icon-ai' => 'dashicons-lightbulb',
            '--pr-icon-ai-content' => 'dashicons-welcome-write-blog',
            '--pr-icon-ai-verify' => 'dashicons-yes-alt',
            '--pr-icon-woocommerce' => 'dashicons-cart',
            '--pr-icon-product-schema' => 'dashicons-products',
            '--pr-icon-social' => 'dashicons-share',
            '--pr-icon-tools' => 'dashicons-admin-tools',
            '--pr-icon-support' => 'dashicons-sos',
            '--pr-icon-white-label' => 'dashicons-admin-appearance',
            '--pr-icon-podcast' => 'dashicons-microphone',
            '--pr-icon-podcast-advanced' => 'dashicons-playlist-audio',
        ];
        
        return $icon_map[$icon_token] ?? 'dashicons-admin-generic';
    }
}
