<?php

namespace AIPT\Api;

use AIPT\Api\OpenAI\OpenAIClient;
use AIPT\Api\Gemini\GeminiClient;
use AIPT\Api\OpenRouter\OpenRouterClient;
use AIPT\Api\Services\AIClientFactoryInterface;
use AIPT\Api\Services\RestAPIClientFactory;
use AIPT\Api\Services\SettingsService;
use AIPT\Api\Services\ContentGenerationService;
use AIPT\Api\Services\OnboardingService;
use AIPT\Api\Services\UnifiedContentGenerator;
use AIPT\Core\Activator;
use AIPT\Core\ErrorHandler;
use AIPT\Core\FsManager;
use AIPT\Utils\ApiKeyManager;
use AIPT\Utils\PromptFormatter;
use AIPT\Utils\VariableConverter;
use AIPT\Api\Traits\RateLimitTrait;
use AIPT\Utils\Credentials\CredentialResolver;
use AIPT\Utils\Credentials\CredentialSource;
use AIPT\Core\Services\WordPressRuntimeDetector;

/**
 * Centralized legacy REST endpoints for the wp/v2/aipt namespace.
 *
 * Also registers the aipt/v1/connectors-status endpoint.
 *
 * @since 2.6.0 Validation routes surface credential source; new /connectors-status
 *              endpoint added; env/constant-sourced providers reject writes.
 */
class RestEndpoints {

	use RateLimitTrait;

    private $namespace = 'wp/v2/aipt';

    /**
     * AI Client Factory
     *
     * @var AIClientFactoryInterface
     */
    private $ai_client_factory;

    /**
     * Settings Service
     *
     * @var SettingsService
     */
    private $settings_service;

    /**
     * Content Generation Service
     *
     * @var ContentGenerationService
     */
    private $content_generation_service;

    /**
     * Onboarding Service
     *
     * @var OnboardingService
     */
    private $onboarding_service;

    /**
     * Unified Content Generator
     *
     * @var UnifiedContentGenerator
     */
    private $unified_generator;

    private $settings_fields = [
        'openai_api_key',
        'gemini_api_key',
        'openrouter_api_key',
        'api_provider',
        'system_prompt',
        'user_prompt',
        'short_system_prompt',
        'short_user_prompt',
        'full_system_prompt',
        'full_user_prompt',
        'standard_short_system_prompt',
        'standard_short_user_prompt',
        'standard_full_system_prompt',
        'standard_full_user_prompt',
        'title_additional_prompt',
        'faq_additional_prompt',
        'seo_meta_additional_prompt',
        'taxonomy_additional_prompt',
        'image_alt_additional_prompt',
        'language',
        'writing_style',
        'content_length_preset',
        'short_length_preset',
        'max_tags_count',
        'model',
        'enable_tooltip',
        'metabox_hidden',
        'preserve_content_images',
        'brand_context',
        'allowed_html_tags',
        'disallowed_html_tags',
        'example_short_description',
        'example_description'
    ];

    private $style_descriptions = [
        'Professional' => 'Use clear, concise, and formal language. Focus on features, benefits, and technical details.',
        'Encouraging' => 'Use positive, motivational language that inspires confidence and action.',
        'Exaggerated' => 'Use dramatic and hyperbolic language to create excitement and emphasis.',
        'Friendly' => 'Use warm, conversational language that builds rapport and trust.',
        'Storytelling' => 'Create a narrative that engages readers and connects emotionally.',
        'Minimalist' => 'Use simple, straightforward language focusing on essential details.',
        'Luxurious and Elegant' => 'Use sophisticated, refined language that conveys premium quality and exclusivity.',
        'Adventurous' => 'Use dynamic, exciting language that creates a sense of exploration and discovery.',
        'Educational' => 'Use informative, detailed language that explains and educates.',
        'Humorous' => 'Use light-hearted, playful language with appropriate humor and wit.'
    ];

	public function __construct( ?AIClientFactoryInterface $ai_client_factory = null, ?SettingsService $settings_service = null, ?ContentGenerationService $content_generation_service = null, ?OnboardingService $onboarding_service = null, ?UnifiedContentGenerator $unified_generator = null ) {
		$this->ai_client_factory = $ai_client_factory ?? new RestAPIClientFactory();
		$this->settings_service  = $settings_service ?? new SettingsService(
			$this->settings_fields,
			$this->style_descriptions,
			$this->ai_client_factory
		);
		$this->content_generation_service = $content_generation_service ?? new ContentGenerationService(
			$this->ai_client_factory,
			$this->style_descriptions
		);
		$this->onboarding_service = $onboarding_service ?? new OnboardingService();
		$this->unified_generator  = $unified_generator ?? new UnifiedContentGenerator(
			$this->ai_client_factory,
			$this->style_descriptions
		);
	}

    private function get_ai_client() {
		return $this->ai_client_factory->create();
	}

    private function get_default_model_for_provider(string $provider): string {
		return $this->ai_client_factory->getDefaultModel( $provider );
	}

    private function normalize_model_for_provider(string $provider, ?string $model): string {
		return $this->ai_client_factory->normalizeModel( $provider, $model );
	}

    public function register_routes(): void {
        register_rest_route($this->namespace, '/generate-description', [
            'methods' => 'POST',
            'callback' => [$this, 'generate_description'],
            'permission_callback' => [$this, 'check_permissions'],
            'args' => [
                'product_id' => [
                    'required' => true,
                    'type' => 'integer',
                ],
                'is_short' => [
                    'required' => false,
                    'type' => 'boolean',
                    'default' => false,
                ],
                'system_prompt' => [
                    'required' => true,
                    'type' => 'string',
                ],
                'user_prompt' => [
                    'required' => true,
                    'type' => 'string',
                ],
            ],
        ]);

        register_rest_route($this->namespace, '/generate-title', [
            'methods' => 'POST',
            'callback' => [$this, 'generate_title'],
            'permission_callback' => [$this, 'check_permissions'],
            'args' => [
                'product_id' => [
                    'required' => true,
                    'type' => 'integer',
                ],
                'system_prompt' => [
                    'required' => false,
                    'type' => 'string',
                ],
                'user_prompt' => [
                    'required' => false,
                    'type' => 'string',
                ],
                'mode' => [
                    'required' => false,
                    'type' => 'string',
                    'default' => 'rewrite',
                    'enum' => ['rewrite', 'improve']
                ],
                'tone' => [
                    'required' => false,
                    'type' => 'string',
                    'default' => 'SEO-Focused'
                ],
                'max_length' => [
                    'required' => false,
                    'type' => 'integer',
                    'default' => 60
                ],
                'keywords' => [
                    'required' => false,
                    'type' => 'string',
                    'default' => ''
                ],
            ],
        ]);

        register_rest_route($this->namespace, '/generate-tags', [
            'methods' => 'POST',
            'callback' => [$this, 'generate_tags'],
            'permission_callback' => [$this, 'check_permissions'],
            'args' => [
                'product_id' => [
                    'required' => true,
                    'type' => 'integer',
                ],
                'system_prompt' => [
                    'required' => false,
                    'type' => 'string',
                ],
                'user_prompt' => [
                    'required' => false,
                    'type' => 'string',
                ],
                'max_tags' => [
                    'required' => false,
                    'type' => 'integer',
                    'default' => 5
                ],
                'keep_existing' => [
                    'required' => false,
                    'type' => 'boolean',
                    'default' => false
                ],
            ],
        ]);

        register_rest_route($this->namespace, '/generate-unified', [
            'methods' => 'POST',
            'callback' => [$this, 'generate_unified'],
            'permission_callback' => [$this, 'check_permissions'],
            'args' => [
                'product_id' => [
                    'required' => true,
                    'type' => 'integer',
                ],
                'content_types' => [
                    'required' => true,
                    'type' => 'array',
                    'items' => ['type' => 'string'],
                ],
                'options' => [
                    'required' => false,
                    'type' => 'object',
                    'default' => [],
                ],
            ],
        ]);

        register_rest_route($this->namespace, '/apply-description', [
            'methods' => 'POST',
            'callback' => [$this, 'apply_description'],
            'permission_callback' => [$this, 'check_permissions'],
            'args' => [
                'product_id' => [
                    'required' => true,
                    'type' => 'integer',
                ],
                'description' => [
                    'required' => true,
                    'type' => 'string',
                ],
            ],
        ]);

        register_rest_route($this->namespace, '/settings', [
            [
                'methods' => 'GET',
                'callback' => [$this, 'get_settings'],
                'permission_callback' => [$this, 'check_permissions'],
            ],
            [
                'methods' => 'POST',
                'callback' => [$this, 'update_settings'],
                'permission_callback' => [$this, 'check_permissions'],
                'args' => [
                    'openai_api_key' => [
                        'required' => false,
                        'type' => 'string',
                    ],
                    'gemini_api_key' => [
                        'required' => false,
                        'type' => 'string',
                    ],
                    'openrouter_api_key' => [
                        'required' => false,
                        'type' => 'string',
                    ],
                    'api_provider' => [
                        'required' => true,
                        'type' => 'string',
                        'enum' => ['openai', 'gemini', 'openrouter', 'claude']
                    ],
                    'system_prompt' => [
                        'required' => true,
                        'type' => 'string',
                    ],
                    'user_prompt' => [
                        'required' => true,
                        'type' => 'string',
                    ],
                    'short_system_prompt' => [
                        'required' => false,
                        'type' => 'string',
                    ],
                    'short_user_prompt' => [
                        'required' => false,
                        'type' => 'string',
                    ],
                    'full_system_prompt' => [
                        'required' => false,
                        'type' => 'string',
                    ],
                    'full_user_prompt' => [
                        'required' => false,
                        'type' => 'string',
                    ],
                    'language' => [
                        'required' => true,
                        'type' => 'string',
                    ],
                    'writing_style' => [
                        'required' => true,
                        'type' => 'string',
                    ],
                    'content_length_preset' => [
                        'required' => true,
                        'type' => 'string',
                        'enum' => ['short', 'medium', 'long', 'very_long']
                    ],
                    'short_length_preset' => [
                        'required' => true,
                        'type' => 'string',
                        'enum' => ['brief', 'standard', 'detailed']
                    ],
                    'max_tags_count' => [
                        'required' => true,
                        'type' => 'string',
                    ],
                    'model' => [
                        'required' => true,
                        'type' => 'string',
                    ],
                    'enable_tooltip' => [
                        'required' => false,
                        'type' => 'boolean',

                        'sanitize_callback' => 'rest_sanitize_boolean',
                    ],
                    'preserve_content_images' => [
                        'required' => false,
                        'type' => 'boolean',
                        'sanitize_callback' => 'rest_sanitize_boolean',
                    ],
                ],
            ],
        ]);

        register_rest_route($this->namespace, '/validate-api-key', [
            'methods' => 'POST',
            'callback' => [$this, 'validate_api_key'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route($this->namespace, '/check-api-keys', [
            'methods' => 'GET',
            'callback' => [$this, 'check_api_keys'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route($this->namespace, '/complete-setup', [
            'methods' => 'POST',
            'callback' => [$this, 'complete_setup'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route($this->namespace, '/onboarding-status', [
            'methods' => 'GET',
            'callback' => [$this, 'get_onboarding_status'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route($this->namespace, '/snooze-onboarding', [
            'methods' => 'POST',
            'callback' => [$this, 'snooze_onboarding'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route($this->namespace, '/skip-setup', [
            'methods' => 'POST',
            'callback' => [$this, 'skip_setup'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route($this->namespace, '/quickstart-progress', [
            'methods' => 'POST',
            'callback' => [$this, 'update_quickstart_progress'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route($this->namespace, '/get-available-models', [
            'methods' => 'GET',
            'callback' => [$this, 'get_available_models'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route('wp/v2/aipt', '/limits', [
            'methods' => 'GET',
            'callback' => [$this, 'get_limits'],
            'permission_callback' => [$this, 'check_admin_permissions']
        ]);

        register_rest_route($this->namespace, '/encryption-status', [
            'methods' => 'GET',
            'callback' => [$this, 'get_encryption_status'],
            'permission_callback' => [$this, 'check_permissions']
        ]);

        register_rest_route( 'aipt/v1', '/connectors-status', [
            'methods'             => \WP_REST_Server::READABLE,
            'callback'            => [ $this, 'get_connectors_status' ],
            'permission_callback' => [ $this, 'check_permissions' ],
        ] );

        register_rest_route( 'aipt/v1', '/migrate-keys-to-connectors', [
            'methods'             => \WP_REST_Server::CREATABLE,
            'callback'            => [ $this, 'migrate_keys_to_connectors' ],
            'permission_callback' => [ $this, 'check_permissions_write' ],
            'args'                => [
                'providers' => [
                    'type'              => 'array',
                    'required'          => true,
                    'sanitize_callback' => function ( $value ) {
                        if ( ! is_array( $value ) ) {
                            return [];
                        }
                        return array_values( array_map( 'sanitize_text_field', $value ) );
                    },
                ],
            ],
        ] );

        register_rest_route( 'aipt/v1', '/migration-notice/dismiss', [
            'methods'             => \WP_REST_Server::CREATABLE,
            'callback'            => [ $this, 'dismiss_migration_notice' ],
            'permission_callback' => [ $this, 'check_permissions_write' ],
            'args'                => [
                'mode' => [
                    'type'              => 'string',
                    'required'          => true,
                    'enum'              => [ 'snooze', 'permanent' ],
                    'sanitize_callback' => 'sanitize_text_field',
                ],
            ],
        ] );

        $this->register_automation_jobs_routes();

		( new \AIPT\Api\AiAvailability\AiAvailabilityController() )->register_routes();

    }

    /**
     * Register automation jobs REST API routes
     */
    private function register_automation_jobs_routes() {
        try {

            $job_manager = new \AIPT\Api\AutomationJobs\AutomationJobManager();
            $logger = new \AIPT\Api\AutomationJobs\JobLogger();
            $executor = new \AIPT\Api\AutomationJobs\JobExecutor($job_manager, $logger);
            $scheduler = new \AIPT\Api\AutomationJobs\JobScheduler($job_manager, $logger);

            $controller = new \AIPT\Api\AutomationJobs\AutomationJobsController(
                $job_manager,
                $executor,
                $scheduler,
                $logger
            );

            $controller->register_routes();

            $draft_controller = new \AIPT\Api\AutomationJobs\DraftContentController();
            $draft_controller->register_routes();

        } catch (\Exception $e) {

        }
    }

    public function check_permissions() {
        return current_user_can('manage_options');
    }

    /**
     * Write-side permission check: validates wp_rest nonce + manage_options.
     *
     * Used by mutating REST routes (e.g., /migrate-keys-to-connectors,
     * /migration-notice/dismiss) per project convention. Mirrors the pattern
     * established in ChatbotController::check_permissions_write().
     *
     * @since 2.6.0
     *
     * @param \WP_REST_Request $request Incoming REST request.
     * @return bool|\WP_Error True on success, WP_Error(403) on invalid nonce, false on capability fail.
     */
    public function check_permissions_write( \WP_REST_Request $request ) {
        $nonce = $request->get_header( 'X-WP-Nonce' );
        if ( empty( $nonce ) ) {
            $nonce = $request->get_param( '_wpnonce' );
        }
        $nonce = is_string( $nonce ) ? sanitize_text_field( wp_unslash( $nonce ) ) : '';

        if ( empty( $nonce ) || ! wp_verify_nonce( $nonce, 'wp_rest' ) ) {
            return new \WP_Error(
                'rest_forbidden_nonce',
                __( 'Invalid security token. Please refresh and try again.', 'ai-product-tools' ),
                [ 'status' => 403 ]
            );
        }

        return current_user_can( 'manage_options' );
    }

    public function generate_description($request) {

		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}
		return $this->content_generation_service->generateDescription( $request->get_params() );
	}

    public function generate_title($request) {

		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}
		return $this->content_generation_service->generateTitle( $request->get_params() );
	}

    public function generate_tags($request) {

		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}
		return $this->content_generation_service->generateTags( $request->get_params() );
	}

	public function generate_unified($request) {

		$ai_gate = \AIPT\Core\Services\AiSupportGate::guard();
		if ( $ai_gate instanceof \WP_Error ) {
			return $ai_gate;
		}
		$params        = $request->get_params();
		$product_id    = absint( $params['product_id'] );
		$content_types = isset( $params['content_types'] ) ? (array) $params['content_types'] : [];
		$options       = isset( $params['options'] ) ? (array) $params['options'] : [];

		return $this->unified_generator->generate( $product_id, $content_types, $options );
	}

    /**
     * Prompt içeriğini temizleyen ve değişkenleri formatlayan metod
     *
     * @param string $content Formatlama yapılacak içerik
     * @param array $productData Ürün verilerini içeren dizi (opsiyonel)
     * @return string Temizlenmiş ve formatlanmış içerik
     */
    private function clean_prompt_content(string $content, array $productData = []): string {
        if (!empty($productData)) {

            return PromptFormatter::formatProductVariables($content, $productData);
        }
        

        return PromptFormatter::cleanContent($content);
    }

    /**
     * AI'dan gelen metni WordPress editörü için düzgün formatlama
     * 
     * @param string $text AI'dan gelen ham metin
     * @return string WordPress editörü için formatlanmış metin
     */
    private function format_ai_response_for_wordpress($text) {
        return PromptFormatter::formatAiResponseForWordPress($text);
    }

    public function apply_description($request) {
		$params = $request->get_params();
		$type = isset( $params['type'] ) ? $params['type'] : 'full';
		return $this->content_generation_service->applyContent( $params['product_id'], $params['description'], $type );
	}

    public function get_settings() {
		return $this->settings_service->getSettings();
	}

    public function update_settings($request) {
		return $this->settings_service->updateSettings( $request->get_params() );
	}

    private function get_product_info($product) {

        $product_info = [];
        

        $product_info['name'] = sanitize_text_field($product->get_name());
        $product_info['sku'] = sanitize_text_field($product->get_sku());
        

        $product_info['regular_price'] = $product->get_regular_price();
        $product_info['sale_price'] = $product->get_sale_price();
        $product_info['price'] = $product->get_price();
        $product_info['currency'] = get_woocommerce_currency();
        

        $product_info['short_description'] = $product->get_short_description();
        

        $categories = wp_get_post_terms($product->get_id(), 'product_cat', ['fields' => 'names']);
        if (!is_wp_error($categories) && !empty($categories)) {
            $product_info['categories'] = array_map(function($category) {
                return html_entity_decode(sanitize_text_field($category), ENT_QUOTES, 'UTF-8');
            }, $categories);
        } else {
            $product_info['categories'] = [];
        }
        

        $tags = wp_get_post_terms($product->get_id(), 'product_tag', ['fields' => 'names']);
        if (!is_wp_error($tags) && !empty($tags)) {
            $product_info['tags'] = array_map('sanitize_text_field', $tags);
        } else {
            $product_info['tags'] = [];
        }
        

        $product_info['attributes'] = [];
        $attributes = $product->get_attributes();
        
        if (!empty($attributes)) {
            foreach ($attributes as $attribute) {
                if ($attribute->get_visible()) {
                    $name = sanitize_text_field(wc_attribute_label($attribute->get_name()));
                    $values = [];
                    
                    if ($attribute->is_taxonomy()) {
                        $terms = wp_get_post_terms($product->get_id(), $attribute->get_name(), ['fields' => 'names']);
                        if (!is_wp_error($terms)) {

                            $values = array_map('sanitize_text_field', $terms);
                        }
                    } else {

                        $options = $attribute->get_options();
                        $values = array_map('sanitize_text_field', $options);
                    }
                    
                    if (!empty($values)) {

                        $safe_values = implode(', ', $values);

                        $product_info['attributes'][$name] = wp_kses($safe_values, []);
                    }
                }
            }
        }
        
        return $product_info;
    }

    public function validate_api_key($request) {
		$params       = $request->get_json_params();
		$api_key      = sanitize_text_field( $params['api_key'] );
		$api_provider = sanitize_text_field( $params['api_provider'] ?? 'openai' );

		$supported_providers = \AIPT\Utils\ProviderNameMapper::aiptProviders();
		if ( ! in_array( $api_provider, $supported_providers, true ) ) {
			return new \WP_Error(
				'aipt_invalid_provider',
				esc_html(
					sprintf(
						/* translators: %s: comma-separated list of supported AI provider ids. */
						__( 'Unknown API provider. Must be one of: %s.', 'ai-product-tools' ),
						implode( ', ', $supported_providers )
					)
				),
				[ 'status' => 400 ]
			);
		}

		$resolver = CredentialResolver::instance();
		$source   = $resolver->getSource( $api_provider );
		if ( in_array( $source, [ CredentialSource::ENV, CredentialSource::CONSTANT ], true ) ) {

			return new \WP_Error(
				'aipt_provider_immutable',
				esc_html__( "This provider's API key is managed by an environment variable / PHP constant and cannot be edited here. Update it in your hosting environment or wp-config.php.", 'ai-product-tools'),
				[ 'status' => 403, 'source' => $source ]
			);
		}

		$result = $this->settings_service->validateApiKey( $api_key, $api_provider );

		if ( ! is_wp_error( $result ) ) {
			if ( $result instanceof \WP_REST_Response ) {
				$data           = (array) $result->get_data();
				$data['source'] = CredentialSource::DATABASE_LOCAL;
				$result->set_data( $data );
			} elseif ( is_array( $result ) ) {
				$result['source'] = CredentialSource::DATABASE_LOCAL;
			}
		}

		return $result;
	}

    public function complete_setup($request) {
		$params = $request->get_json_params();
		return $this->onboarding_service->completeSetup( $params );
	}

    public function get_available_models($request) {
        try {
            $api_provider = get_option('aipt_api_provider', 'openai');

            $source = CredentialResolver::instance()->getSource( $api_provider );

            if ($api_provider === 'openai') {
                $client = new OpenAIClient('dummy-key');
            } elseif ($api_provider === 'openrouter') {
                $client = new OpenRouterClient('dummy-key');
            } elseif ($api_provider === 'claude') {
                $client = new \AIPT\Api\Claude\ClaudeClient('dummy-key');
            } else {
                $client = new GeminiClient('dummy-key');
            }

            return [
                'models' => $client->get_available_models(),
                'source' => $source,
            ];
        } catch (\Exception $e) {

            $message = $e->getMessage();
            $status  = ErrorHandler::extract_http_status_from_message($message, 500);
            return new \WP_Error('models_fetch_failed', esc_html($message), ['status' => $status]);
        }
    }

    public function get_limits(): \WP_REST_Response {
        try {

            $script_path = AIPT_PLUGIN_DIR . 'dist/js/settings.js';
            if (!file_exists($script_path)) {
                throw new Exception('Settings file not found');
            }

            require_once(ABSPATH . 'wp-admin/includes/file.php');
            WP_Filesystem();
            global $wp_filesystem;
            
            if (!$wp_filesystem) {
                throw new Exception('WP Filesystem not available');
            }

            $script_content = $wp_filesystem->get_contents($script_path);
            if ($script_content === false) {
                throw new Exception('Could not read settings file');
            }

            if (!preg_match('/window\.aiptLimits\s*=\s*{[^}]+}/', $script_content, $matches)) {
                throw new Exception('Limit configuration not found in settings');
            }

            preg_match_all("/[fp]l:\s*['\"]([^'\"]+)['\"]/", $matches[0], $limitMatches);
            
            if (empty($limitMatches[1])) {
                throw new Exception('Invalid limit configuration format');
            }

            $limits = [];
            foreach ($limitMatches[1] as $encrypted) {

                $firstDecode = base64_decode($encrypted);
                if ($firstDecode === false) {
                    continue;
                }
                $secondDecode = base64_decode($firstDecode);
                if ($secondDecode === false) {
                    continue;
                }

                $value = intval($secondDecode);
                if ($value === 500) {
                    $limits['fl'] = $value;
                } elseif ($value === 5000) {
                    $limits['pl'] = $value;
                }
            }

            if (empty($limits) || !isset($limits['fl']) || !isset($limits['pl'])) {
                throw new Exception('Could not decode limit values');
            }
            return new \WP_REST_Response($limits, 200);
        } catch (Exception $e) {

            return new \WP_REST_Response([
                'error' => esc_html($e->getMessage()),
            ], 500);
        }
    }

    private function decode_limit(string $key): int {
        if (!in_array($key, ['fl', 'pl'])) {
            return 0;
        }

        try {
            $script_path = AIPT_PLUGIN_DIR . 'dist/js/settings.js';
            
            if (!file_exists($script_path)) {
                return 0;
            }

            require_once(ABSPATH . 'wp-admin/includes/file.php');
            WP_Filesystem();
            global $wp_filesystem;
            
            if (!$wp_filesystem) {
                return 0;
            }

            $script_content = $wp_filesystem->get_contents($script_path);
            if ($script_content === false) {
                return 0;
            }

            if (!preg_match('/window\.aiptLimits\s*=\s*{[^}]+}/', $script_content, $matches)) {
                return 0;
            }

            preg_match("/$key:\s*['\"]([^'\"]+)['\"]/", $matches[0], $limitMatch);
            
            if (empty($limitMatch[1])) {
                return 0;
            }

            $firstDecode = base64_decode($limitMatch[1]);
            if ($firstDecode === false) {
                return 0;
            }

            $secondDecode = base64_decode($firstDecode);
            if ($secondDecode === false) {
                return 0;
            }

            $value = intval($secondDecode);
            return ($key === 'fl' && $value === 500) || ($key === 'pl' && $value === 5000) ? $value : 0;
        } catch (Exception $e) {
            return 0;
        }
    }

    public function check_api_keys() {
        if (!current_user_can('manage_options')) {
            return new \WP_Error(
                'rest_forbidden',
                esc_html__('Sorry, you are not allowed to do that.', 'ai-product-tools'),
                ['status' => 401]
            );
        }

        $resolver        = CredentialResolver::instance();
        $status          = $resolver->getStatus();
        $provider_sources = [];
        foreach ( $status as $provider_id => $provider_data ) {
            $provider_sources[ $provider_id ] = [
                'source' => $provider_data['source'],
            ];
        }

        return [
            'hasApiKey' => ApiKeyManager::has_any_api_key(),
            'providers' => $provider_sources,
        ];
    }

    public function get_encryption_status() {
        if (!current_user_can('manage_options')) {
            return new \WP_Error(
                'rest_forbidden',
                esc_html__('Sorry, you are not allowed to do that.', 'ai-product-tools'),
                ['status' => 401]
            );
        }

        return ApiKeyManager::get_encryption_status();
    }

    private function sanitize_api_key(string $key): string {
		return $this->settings_service->sanitizeApiKey( $key );
	}

    private function sanitize_multiline_text($text) {
        if (empty($text)) {
            return '';
        }
        

        $text = preg_replace('/^\s*```[a-zA-Z]*\s*\n/', '', $text); 
        $text = preg_replace('/\n\s*```\s*$/', '', $text); 
        $text = preg_replace('/```[a-zA-Z]*/', '', $text); 
        $text = preg_replace('/```/', '', $text); 
        

        $containsHtml = preg_match('/<([a-z][a-z0-9]*)\b[^>]*>(.*?)<\/\1>/is', $text);
        
        if ($containsHtml) {

            $text = preg_replace('/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/mi', '', $text);
            $text = preg_replace('/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/mi', '', $text);
            $text = preg_replace('/<object\b[^<]*(?:(?!<\/object>)<[^<]*)*<\/object>/mi', '', $text);
            $text = preg_replace('/<embed\b[^<]*(?:(?!<\/embed>)<[^<]*)*<\/embed>/mi', '', $text);
            

            $text = preg_replace('/\s*on\w+\s*=\s*["\'][^"\']*["\']/i', '', $text);
            $text = preg_replace('/\s*javascript\s*:/i', '', $text);
            

            $text = wp_kses_post($text);
            

            $text = preg_replace('/\xE2\x80\x8B|\x{200B}/u', '', $text);
            

            $text = str_replace("\r\n", "\n", $text);
            $text = str_replace("\r", "\n", $text);
            
            return $text;
        }
        

        $text = preg_replace('/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/mi', '', $text);
        $text = preg_replace('/\s*on\w+\s*=\s*["\'][^"\']*["\']/i', '', $text);
        $text = preg_replace('/\s*javascript\s*:/i', '', $text);
        

        $text = preg_replace('/\xE2\x80\x8B|\x{200B}/u', '', $text);
        

        $text = str_replace("\r\n", "\n", $text);
        $text = str_replace("\r", "\n", $text);
        

        $lines = explode("\n", $text);
        $clean_lines = [];
        
        foreach ($lines as $line) {

            $clean_lines[] = sanitize_text_field(trim($line));
        }
        

        return implode("\n", $clean_lines);
    }

    /**
	 * Get onboarding status
	 * Determines if onboarding popup should be shown
	 */
	public function get_onboarding_status(\WP_REST_Request $request): \WP_REST_Response {
		try {
			$status = $this->onboarding_service->getStatus();
			return new \WP_REST_Response( $status, 200 );
		} catch ( \Exception $e ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'message' => 'Failed to get onboarding status: ' . esc_html($e->getMessage()),
				),
				500
			);
		}
	}

    /**
	 * Snooze onboarding popup for 1 hour
	 * Sets a timestamp for when onboarding should be shown again
	 */
	public function snooze_onboarding(\WP_REST_Request $request): \WP_REST_Response {
		try {
			$result = $this->onboarding_service->snooze();
			return new \WP_REST_Response( $result, 200 );
		} catch ( \Exception $e ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'message' => 'Failed to snooze onboarding: ' . esc_html($e->getMessage()),
				),
				500
			);
		}
	}

    /**
	 * Skip setup process
	 * Marks setup as skipped and completed
	 */
	public function skip_setup(\WP_REST_Request $request): \WP_REST_Response {
		try {
			$result = $this->onboarding_service->skipSetup();
			return new \WP_REST_Response( $result, 200 );
		} catch ( \Exception $e ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'message' => 'Failed to skip setup: ' . esc_html($e->getMessage()),
				),
				500
			);
		}
	}

	/**
	 * Update quick start guide progress
	 *
	 * Handles complete_step, dismiss, and reset actions via single endpoint.
	 *
	 * @param \WP_REST_Request $request Request with 'action' and optional 'step_id'
	 * @return \WP_REST_Response Updated quick start state
	 */
	public function update_quickstart_progress( \WP_REST_Request $request ): \WP_REST_Response {
		try {
			$params  = $request->get_json_params();
			$action  = isset( $params['action'] ) ? sanitize_text_field( $params['action'] ) : '';
			$step_id = isset( $params['step_id'] ) ? sanitize_text_field( $params['step_id'] ) : '';

			switch ( $action ) {
				case 'complete_step':
					$result = $this->onboarding_service->completeQuickStartStep( $step_id );
					break;
				case 'dismiss':
					$result = $this->onboarding_service->dismissQuickStart();
					break;
				case 'reset':
					$result = $this->onboarding_service->resetQuickStart();
					break;
				default:
					return new \WP_REST_Response(
						array(
							'success' => false,
							'message' => 'Invalid action. Use: complete_step, dismiss, or reset.',
						),
						400
					);
			}

			if ( is_wp_error( $result ) ) {
				/** @var \WP_Error $result */
				$error_data   = $result->get_error_data();
				$status_code  = is_array( $error_data ) && isset( $error_data['status'] ) ? (int) $error_data['status'] : 400;
				return new \WP_REST_Response(
					array(
						'success' => false,
						'message' => $result->get_error_message(),
					),
					$status_code
				);
			}

			return new \WP_REST_Response(
				array(
					'success'    => true,
					'quickstart' => $result,
				),
				200
			);
		} catch ( \Exception $e ) {
			return new \WP_REST_Response(
				array(
					'success' => false,
					'message' => 'Failed to update quick start progress: ' . esc_html( $e->getMessage() ),
				),
				500
			);
		}
	}

    /**
     * GET /aipt/v1/connectors-status — Returns aggregate connector credential status.
     *
     * Rate-limited to 30 requests per 60 seconds per user.
     * Requires manage_options capability (enforced by permission_callback).
     *
     * @since 2.6.0
     *
     * @return \WP_REST_Response|\WP_Error Connector status payload or rate-limit error.
     */
    public function get_connectors_status() {
        $rate_check = $this->checkRateLimit( get_current_user_id(), 'connectors_status', 30, 60 );
        if ( ! $rate_check['allowed'] ) {
            return $this->rateLimitResponse( $rate_check );
        }

        $resolver  = CredentialResolver::instance();
        $providers = $resolver->getStatus();

        $connectors_managed = array_filter(
            $providers,
            static fn( $p ) => ! empty( $p['isConnectorsManaged'] )
        );

        $payload = [
            'connectorsApiAvailable'  => WordPressRuntimeDetector::supportsConnectorsApi(),
            'connectorsAdminUrl'      => admin_url( 'options-connectors.php' ),
            'hasAnyConfigured'        => $resolver->hasAnyConfiguredProvider(),
            'providers'               => $providers,
            'hasAnyConnectorsManaged' => ! empty( $connectors_managed ),
            'connectorsManagedCount'  => count( $connectors_managed ),
        ];

        return rest_ensure_response( $payload );
    }

    /**
     * POST /aipt/v1/migrate-keys-to-connectors — Copy local plaintext keys into
     * Connectors DB options so users can switch to Connectors-managed UX without
     * losing access. Never overwrites env/constant-backed keys or existing
     * Connectors DB entries.
     *
     * Rate-limited to 5 requests per 60 seconds per user.
     *
     * @since 2.6.0
     *
     * @param \WP_REST_Request $request REST request carrying `providers` array.
     * @return \WP_REST_Response|\WP_Error Per-provider migration results or rate-limit error.
     */
    public function migrate_keys_to_connectors( \WP_REST_Request $request ) {
        $rate_check = $this->checkRateLimit( get_current_user_id(), 'migrate_keys', 5, 60 );
        if ( ! $rate_check['allowed'] ) {
            return $this->rateLimitResponse( $rate_check );
        }

        $providers_input = (array) $request->get_param( 'providers' );
        $allowed         = \AIPT\Utils\ProviderNameMapper::aiptProviders();

        $allowed         = array_values( array_diff( $allowed, array( 'openrouter' ) ) );
        $providers       = array_values( array_intersect( $providers_input, $allowed ) );

        if ( empty( $providers ) ) {
            return new \WP_Error(
                'aipt_migrate_invalid_providers',
                esc_html__( 'No valid providers supplied for migration.', 'ai-product-tools' ),
                [ 'status' => 400 ]
            );
        }

        $local_provider = new \AIPT\Utils\Credentials\LocalCredentialProvider();
        $resolver       = CredentialResolver::instance();
        $results        = [];
        $migrated_count = 0;

        foreach ( $providers as $aipt_provider ) {
            $source       = $resolver->getSource( $aipt_provider );
            $connector_id = \AIPT\Utils\ProviderNameMapper::toConnectorId( $aipt_provider );
            $option_name  = 'connectors_ai_' . $connector_id . '_api_key';

            if ( CredentialSource::ENV === $source ) {
                $results[] = [ 'provider' => $aipt_provider, 'status' => 'skipped_env' ];
                continue;
            }
            if ( CredentialSource::CONSTANT === $source ) {
                $results[] = [ 'provider' => $aipt_provider, 'status' => 'skipped_constant' ];
                continue;
            }
            $existing_connectors_value = get_option( $option_name, '' );
            if ( ! empty( $existing_connectors_value ) ) {
                $results[] = [ 'provider' => $aipt_provider, 'status' => 'skipped_already_set' ];
                continue;
            }

            $local_key = $local_provider->getKey( $aipt_provider );
            if ( null === $local_key || '' === $local_key ) {
                $results[] = [ 'provider' => $aipt_provider, 'status' => 'skipped_no_local' ];
                continue;
            }

            $saved = update_option( $option_name, $local_key, false );
            if ( $saved ) {
                $results[] = [ 'provider' => $aipt_provider, 'status' => 'migrated' ];
                $migrated_count++;
            } else {
                $results[] = [ 'provider' => $aipt_provider, 'status' => 'failed_write' ];
            }
        }

        if ( $migrated_count > 0 ) {
            $resolver->flushMemoization();
            \AIPT\Api\AiAvailability\AiAvailabilityController::clearCache();
        }

        return rest_ensure_response( [ 'results' => $results ] );
    }

    /**
     * POST /aipt/v1/migration-notice/dismiss — Hide the migration banner.
     *
     * Both modes are stored per-user so one admin closing the banner never hides
     * it from a co-admin who still needs to see it.
     *
     *   - 'snooze' writes a 7-day expiry timestamp to the current user's meta;
     *     the banner resurfaces once the timestamp has passed.
     *   - 'permanent' writes a flag that the current user never wants to see it
     *     again.
     *
     * @since 2.6.0
     *
     * @param \WP_REST_Request $request REST request carrying `mode`.
     * @return \WP_REST_Response Acknowledgement payload.
     */
    public function dismiss_migration_notice( \WP_REST_Request $request ) {
        $mode    = (string) $request->get_param( 'mode' );
        $user_id = get_current_user_id();

        if ( 'snooze' === $mode ) {
            update_user_meta( $user_id, 'aipt_migration_notice_snoozed_until', time() + ( 7 * DAY_IN_SECONDS ) );
        } elseif ( 'permanent' === $mode ) {
            update_user_meta( $user_id, 'aipt_connectors_migration_dismissed', 1 );
        }

        return rest_ensure_response( [ 'dismissed' => true, 'mode' => $mode ] );
    }

}
