<?php

/**
 * Module REST API Controller
 *
 * @package ProRank\SEO\Core\RestApi
 * @since   0.1.0
 */

declare(strict_types=1);

namespace ProRank\SEO\Core\RestApi;

use ProRank\SEO\Core\ModuleManager;
use ProRank\SEO\Core\LicenseManager;
use ProRank\SEO\Core\Security\Sanitization;
use ProRank\SEO\Core\Security\Validation;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

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


/**
 * Class ModuleController
 * 
 * Handles REST API endpoints for module management
 */


class ModuleController extends WP_REST_Controller {
    /**
     * Namespace
     *
     * @var string
     */
    protected $namespace = 'prorank-seo/v1';

    /**
     * Rest base
     *
     * @var string
     */
    protected $rest_base = 'modules';

    /**
     * Module manager instance
     *
     * @var ModuleManager
     */
    private ModuleManager $module_manager;

    /**
     * License manager instance
     *
     * @var LicenseManager
     */
    private LicenseManager $license_manager;

    /**
     * Constructor
     *
     * @param ModuleManager  $module_manager  Module manager instance
     * @param LicenseManager $license_manager License manager instance
     */
    public function __construct(ModuleManager $module_manager, LicenseManager $license_manager) {
        $this->module_manager = $module_manager;
        $this->license_manager = $license_manager;
    }

    /**
     * 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, 'get_modules_permissions_check'],
            ],
            'schema' => [$this, 'get_public_item_schema'],
        ]);

        // 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, 'get_modules_permissions_check'],
        ]);

        // Toggle module
        register_rest_route($this->namespace, '/' . $this->rest_base . '/(?P<slug>[a-z0-9-]+)/toggle', [
            'methods'             => WP_REST_Server::CREATABLE,
            'callback'            => [$this, 'toggle_module'],
            'permission_callback' => [$this, 'update_module_permissions_check'],
            'args'                => [
                'slug' => [
                    'description'       => __('Module slug', 'prorank-seo'),
                    'type'              => 'string',
                    'required'          => true,
                    'sanitize_callback' => 'sanitize_text_field',
                ],
                'enabled' => [
                    'description'       => __('Enable or disable the module', 'prorank-seo'),
                    'type'              => 'boolean',
                    'required'          => true,
                ],
            ],
        ]);

        // Toggle module group
        register_rest_route($this->namespace, '/' . $this->rest_base . '/groups/(?P<slug>[a-z0-9-]+)/toggle', [
            'methods'             => WP_REST_Server::CREATABLE,
            'callback'            => [$this, 'toggle_module_group'],
            'permission_callback' => [$this, 'update_module_permissions_check'],
            'args'                => [
                'slug' => [
                    'description'       => __('Module group slug', 'prorank-seo'),
                    'type'              => 'string',
                    'required'          => true,
                    'sanitize_callback' => 'sanitize_text_field',
                ],
                'enabled' => [
                    'description'       => __('Enable or disable the module group', 'prorank-seo'),
                    'type'              => 'boolean',
                    'required'          => true,
                ],
            ],
        ]);
    }

    /**
     * Get all modules
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     */
    public function get_modules($request) {
        $modules = [];
        $all_modules = $this->module_manager->get_modules();

        foreach ($all_modules as $slug => $module) {
            $tier = $module->get_feature_tier();
            $parent_slug = $module->get_parent_slug();
            
            $modules[] = [
                'slug'        => $slug,
                'name'        => $module->get_name(),
                'description' => $module->get_description(),
                'parent_slug' => $parent_slug,
                'tier'        => $tier,
                'enabled'     => $this->module_manager->is_module_enabled($slug),
                'available'   => $this->is_tier_available($tier),
                'icon'        => $this->get_module_icon($slug),
                'settings_component' => $this->get_settings_component($slug),
            ];
        }

        return new WP_REST_Response([
            'modules' => $modules,
            'license' => [
                'tier' => 'free',
                'active_tiers' => ['free'],
            ],
        ], 200);
    }

    /**
     * Get module groups
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     */
    public function get_module_groups($request) {
        $groups = [];
        $top_level_modules = $this->module_manager->get_top_level_modules();
        
        foreach ($top_level_modules as $module) {
            $slug = $module->get_slug();
            $children = $this->module_manager->get_child_modules($slug);
            
            // Count enabled children
            $enabled_count = 0;
            $available_count = 0;
            foreach ($children as $child) {
                if ($this->module_manager->is_module_enabled($child->get_slug())) {
                    $enabled_count++;
                }
                if ($this->is_tier_available($child->get_feature_tier())) {
                    $available_count++;
                }
            }
            
            $groups[] = [
                'slug'            => $slug,
                'name'            => $module->get_name(),
                'description'     => $module->get_description(),
                'tier'            => $module->get_feature_tier(),
                'enabled'         => $this->module_manager->is_module_enabled($slug),
                'available'       => $this->is_tier_available($module->get_feature_tier()),
                'icon'            => $this->get_module_icon($slug),
                'children_count'  => count($children),
                'enabled_count'   => $enabled_count,
                'available_count' => $available_count,
            ];
        }

        return new WP_REST_Response([
            'groups' => $groups,
        ], 200);
    }

    /**
     * Toggle a module
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     */
    public function toggle_module($request) {
        $slug = $request->get_param('slug');
        $enabled = $request->get_param('enabled');

        // Check if module exists
        if (!$this->module_manager->has_module($slug)) {
            return new WP_Error(
                'prorank_module_not_found',
                __('Module not found.', 'prorank-seo'),
                ['status' => 404]
            );
        }
        
        $module = $this->module_manager->get_module($slug);
        
        // Check tier requirement
        if (!$this->is_tier_available($module->get_feature_tier())) {
            return new WP_Error(
                'prorank_license_required',
                sprintf(
/* translators: %1$: value */
                    __('This feature requires a %1$s license or higher.', 'prorank-seo'),
                    ucfirst($module->get_feature_tier())
                ),
                ['status' => 403]
            );
        }
        
        // Toggle module
        if ($enabled) {
            // Check parent module
            $parent_slug = $module->get_parent_slug();
            if ($parent_slug && !$this->module_manager->is_module_enabled($parent_slug)) {
                return new WP_Error(
                    'prorank_parent_disabled',
                    __('Parent module must be enabled first.', 'prorank-seo'),
                    ['status' => 400]
                );
            }
            
            $success = $this->module_manager->enable_module($slug);
        } else {
            // Check child modules
            $children = $this->module_manager->get_child_modules($slug);
            $enabled_children = [];
            foreach ($children as $child) {
                if ($this->module_manager->is_module_enabled($child->get_slug())) {
                    $enabled_children[] = $child->get_name();
                }
            }
            
            if (!empty($enabled_children)) {
                return new WP_Error(
                    'prorank_children_enabled',
                    sprintf(
/* translators: %1$: value */
                        __('Cannot disable module. The following child modules are still enabled: %1$s', 'prorank-seo'),
                        implode(', ', $enabled_children)
                    ),
                    ['status' => 400]
                );
            }
            
            $success = $this->module_manager->disable_module($slug);
        }
        
        if (!$success) {
            prorank_log('[ProRank SEO] Failed to toggle module: ' . $slug);
            return new WP_Error(
                'prorank_toggle_failed',
                __('Failed to toggle module.', 'prorank-seo'),
                ['status' => 500]
            );
        }

        // Clear any caches
        do_action('prorank_seo_module_toggled', $slug, $enabled);

        return new WP_REST_Response([
            'success' => true,
            'module'  => [
                'slug'    => $slug,
                'enabled' => $enabled,
            ],
        ], 200);
    }

    /**
     * Toggle a module group
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return WP_REST_Response|WP_Error Response object on success, or WP_Error object on failure.
     */
    public function toggle_module_group($request) {
        $group_slug = $request->get_param('slug');
        $enabled = $request->get_param('enabled');
        
        // Check if group module exists
        if (!$this->module_manager->has_module($group_slug)) {
            return new WP_Error(
                'prorank_group_not_found',
                __('Module group not found.', 'prorank-seo'),
                ['status' => 404]
            );
        }
        
        $group_module = $this->module_manager->get_module($group_slug);
        
        // Check tier requirement for group
        if (!$this->is_tier_available($group_module->get_feature_tier())) {
            return new WP_Error(
                'prorank_license_required',
                sprintf(
/* translators: %1$: value */
                    __('This module group requires a %1$s license or higher.', 'prorank-seo'),
                    ucfirst($group_module->get_feature_tier())
                ),
                ['status' => 403]
            );
        }
        
        // Get all child modules
        $children = $this->module_manager->get_child_modules($group_slug);
        $toggled = [];
        $errors = [];
        
        if ($enabled) {
            // Enable group module first
            $this->module_manager->enable_module($group_slug);
            $toggled[] = $group_slug;
            
            // Enable all available child modules
            foreach ($children as $child) {
                $child_slug = $child->get_slug();
                if ($this->is_tier_available($child->get_feature_tier())) {
                    if ($this->module_manager->enable_module($child_slug)) {
                        $toggled[] = $child_slug;
                    } else {
                        $errors[] = $child->get_name();
                    }
                }
            }
        } else {
            // Disable all child modules first
            foreach ($children as $child) {
                $child_slug = $child->get_slug();
                if ($this->module_manager->is_module_enabled($child_slug)) {
                    if ($this->module_manager->disable_module($child_slug)) {
                        $toggled[] = $child_slug;
                    } else {
                        $errors[] = $child->get_name();
                    }
                }
            }
            
            // Disable group module
            if (empty($errors)) {
                $this->module_manager->disable_module($group_slug);
                $toggled[] = $group_slug;
            }
        }
        
        if (!empty($errors)) {
            return new WP_Error(
                'prorank_partial_toggle',
                sprintf(
/* translators: %1$: value */
                    __('Some modules could not be toggled: %1$s', 'prorank-seo'),
                    implode(', ', $errors)
                ),
                ['status' => 500]
            );
        }

        // Clear any caches
        do_action('prorank_seo_module_group_toggled', $group_slug, $enabled);

        return new WP_REST_Response([
            'success' => true,
            'group'   => [
                'slug'    => $group_slug,
                'enabled' => $enabled,
                'toggled' => $toggled,
            ],
        ], 200);
    }

    /**
     * Determine whether a tier is available in the free package.
     *
     * @param string $tier Feature tier.
     * @return bool
     */
    private function is_tier_available(string $tier): bool {
        return $tier === 'free';
    }

    /**
     * Get module icon
     *
     * @param string $slug Module slug
     * @return string Icon class
     */
    private function get_module_icon(string $slug): string {
        $icons = [
            'technical-seo'     => 'dashicons-admin-tools',
            'sitemaps'          => 'dashicons-location-alt',
            'redirects'         => 'dashicons-undo',
            'url-cleanup'       => 'dashicons-admin-links',
            'robots-indexing'   => 'dashicons-shield',
            'head-cleanup'      => 'dashicons-media-code',
            'content-seo'       => 'dashicons-edit-page',
            'schema'            => 'dashicons-media-code',
            'analytics'         => 'dashicons-chart-line',
            'tools'             => 'dashicons-admin-tools',
        ];
        
        return $icons[$slug] ?? 'dashicons-admin-generic';
    }

    /**
     * Get settings component name
     *
     * @param string $slug Module slug
     * @return string|null Component name
     */
    private function get_settings_component(string $slug): ?string {
        $components = [
            'sitemaps'        => 'SitemapSettings',
            'redirects'       => 'RedirectSettings',
            'url-cleanup'     => 'UrlCleanupSettings',
            'robots-indexing' => 'RobotsIndexingSettings',
            'head-cleanup'    => 'HeadCleanupSettings',
            'schema'          => 'SchemaSettings',
        ];
        
        return $components[$slug] ?? null;
    }

    /**
     * Check if a given request has access to get modules
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return true|WP_Error True if the request has read access, WP_Error object otherwise.
     */
    public function get_modules_permissions_check($request) {
        return current_user_can('manage_options');
    }

    /**
     * Check if a given request has access to update modules
     *
     * @param WP_REST_Request $request Full details about the request.
     * @return true|WP_Error True if the request has access to update modules, WP_Error object otherwise.
     */
    public function update_module_permissions_check($request) {
        return current_user_can('manage_options');
    }

    /**
     * Get schema for modules
     *
     * @return array
     */
    public function get_item_schema(): array {
        if ($this->schema) {
            return $this->add_additional_fields_schema($this->schema);
        }

        $schema = [
            '$schema'    => 'http://json-schema.org/draft-04/schema#',
            'title'      => 'module',
            'type'       => 'object',
            'properties' => [
                'slug' => [
                    'description' => __('Module slug.', 'prorank-seo'),
                    'type'        => 'string',
                    'context'     => ['view', 'edit'],
                    'readonly'    => true,
                ],
                'name' => [
                    'description' => __('Module name.', 'prorank-seo'),
                    'type'        => 'string',
                    'context'     => ['view', 'edit'],
                    'readonly'    => true,
                ],
                'description' => [
                    'description' => __('Module description.', 'prorank-seo'),
                    'type'        => 'string',
                    'context'     => ['view', 'edit'],
                    'readonly'    => true,
                ],
                'parent_slug' => [
                    'description' => __('Parent module slug.', 'prorank-seo'),
                    'type'        => ['string', 'null'],
                    'context'     => ['view', 'edit'],
                    'readonly'    => true,
                ],
                'tier' => [
                    'description' => __('Required license tier.', 'prorank-seo'),
                    'type'        => 'string',
                    'enum'        => ['free', 'pro', 'business', 'agency'],
                    'context'     => ['view', 'edit'],
                    'readonly'    => true,
                ],
                'enabled' => [
                    'description' => __('Whether module is enabled.', 'prorank-seo'),
                    'type'        => 'boolean',
                    'context'     => ['view', 'edit'],
                ],
                'available' => [
                    'description' => __('Whether module is available with current license.', 'prorank-seo'),
                    'type'        => 'boolean',
                    'context'     => ['view'],
                    'readonly'    => true,
                ],
                'icon' => [
                    'description' => __('Module icon class.', 'prorank-seo'),
                    'type'        => 'string',
                    'context'     => ['view'],
                    'readonly'    => true,
                ],
            ],
        ];

        $this->schema = $schema;

        return $this->add_additional_fields_schema($this->schema);
    }
}
