<?php

namespace WPDRMS\ASP\AI;

use Exception;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use RuntimeException;
use WPDRMS\ASP\AI\ORM\AIInteraction;
use WPDRMS\ASP\AI\ORM\AIOptions;
use WPDRMS\ASP\Misc\PluginLicense;
use WPDRMS\ASP\AI\Service\AIDiagnosticService;
use WPDRMS\ASP\AI\AIInsufficientDataException;
use WPDRMS\ASP\AI\Service\AIKeywordSuggestionsService;
use WPDRMS\ASP\AI\Service\AIPrioritiesAdvisorService;
use WPDRMS\ASP\AI\Service\AIQualityReportService;
use WPDRMS\ASP\AI\Service\AIStopwordService;
use WPDRMS\ASP\AI\Service\AISynonymService;
use WPDRMS\ASP\AI\Service\AIWizardService;
use WPDRMS\PluginCore\Rest\AbstractRest;

if ( ! defined( 'ABSPATH' ) ) {
	die( '-1' );
}

class AIRoute extends AbstractRest {
	/**
	 * AI feature flags (every AIOptions field) that require an active license to enable.
	 *
	 * @var string[]
	 */
	private const FEATURE_FLAGS = array(
		'diagnostic',
		'synonym_discover',
		'quality_report',
		'config_wizard',
		'priorities_advisor',
		'stopword_detector',
		'ai_suggestions',
	);

	public function registerRoutes( string $route_namespace ): void {
		register_rest_route(
			$route_namespace,
			'ai/options',
			array(
				array(
					'methods'             => 'GET',
					'callback'            => array( $this, 'getOptions' ),
					'permission_callback' => array( $this, 'allowOnlyAdmins' ),
				),
				array(
					'methods'             => 'POST',
					'callback'            => array( $this, 'saveOptions' ),
					'permission_callback' => array( $this, 'allowOnlyAdmins' ),
				),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/interactions',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'getInteractions' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/usage',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'getUsage' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/synonym-discover',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'synonymDiscover' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/synonym-apply',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'synonymApply' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/synonyms/generate',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'synonymsGenerate' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/synonyms/bulk-apply',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'synonymsBulkApply' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/wizard/generate',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'wizardGenerate' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/instance/create',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'instanceCreate' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/quality-report',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'qualityReport' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/cache/purge',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'purgeCache' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/diagnostic/start',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'diagnosticStart' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/diagnostic/message',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'diagnosticMessage' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/instance-suggestions/generate',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'instanceSuggestionsGenerate' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/instance-suggestions/status',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'instanceSuggestionsStatus' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/instance-suggestions/clear',
			array(
				'methods'             => 'DELETE',
				'callback'            => array( $this, 'instanceSuggestionsClear' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/instance-suggestions/remove-word',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'instanceSuggestionsRemoveWord' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/priorities-advisor',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'prioritiesAdvisor' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/stopword-detector',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'stopwordDetector' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);

		register_rest_route(
			$route_namespace,
			'ai/stopword-detector/remove',
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'stopwordRemove' ),
				'permission_callback' => array( $this, 'allowOnlyAdmins' ),
			)
		);
	}

	/** @return WP_Error|WP_REST_Response */
	public function getOptions() {
		try {
			return new WP_REST_Response( AIOptions::instance(), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_options_get', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function saveOptions( WP_REST_Request $request ) {
		try {
			$params = $request->get_json_params();
			$params = is_array( $params ) ? $params : array();

			// Enabling any AI feature requires an active license. Without one, force every
			// feature flag off before saving so no client path — the per-panel "Enable"
			// shortcut, the Settings toggles, or a raw REST POST — can turn a feature on that
			// the gateway will reject anyway. This is the authoritative gate; the admin UI
			// only mirrors it for UX.
			if ( PluginLicense::isActivated() === false ) {
				foreach ( self::FEATURE_FLAGS as $flag ) {
					$params[ $flag ] = array( 'value' => false );
				}
			}

			$options = AIOptions::instance();
			$options->setArgs( $params )->save()->load();
			return new WP_REST_Response( $options, 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_options_save', $e->getMessage() );
		}
	}

	/** @return WP_Error|WP_REST_Response */
	public function purgeCache() {
		try {
			global $wpdb;
			// Increment the cache generation number. AIService::generate() includes this value in
			// every transient key, so all existing cached values become unreachable immediately —
			// even when a persistent object cache (Redis/Memcached) is active.
			update_option( 'asp_ai_cache_gen', (int) get_option( 'asp_ai_cache_gen', 1 ) + 1 );
			// Also delete orphaned transient rows from the DB for sites without an object cache.
			$wpdb->query( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.DirectQuery
				$wpdb->prepare(
					"DELETE FROM `{$wpdb->options}` WHERE `option_name` LIKE %s OR `option_name` LIKE %s", // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
					$wpdb->esc_like( '_transient_asp_ai_' ) . '%',
					$wpdb->esc_like( '_transient_timeout_asp_ai_' ) . '%'
				)
			);
			return new WP_REST_Response( array( 'success' => true ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_cache_purge', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function getInteractions( WP_REST_Request $request ) {
		try {
			$page     = max( 1, (int) ( $request->get_param( 'page' ) ?? 1 ) );
			$per_page = min( 100, max( 10, (int) ( $request->get_param( 'per_page' ) ?? 25 ) ) );
			$offset   = ( $page - 1 ) * $per_page;
			$feature  = sanitize_key( (string) ( $request->get_param( 'feature' ) ?? '' ) );

			$conditions = $feature !== '' ? array( 'feature' => $feature ) : array();
			$rows       = AIInteraction::findBy( $conditions, $per_page, $offset, 'id', 'DESC' );
			$total      = AIInteraction::countAll( $feature );

			return new WP_REST_Response(
				array(
					'items'    => $rows,
					'page'     => $page,
					'per_page' => $per_page,
					'total'    => $total,
					'features' => AIInteraction::distinctFeatures(),
				),
				200
			);
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_interactions_get', $e->getMessage() );
		}
	}

	/** @return WP_Error|WP_REST_Response */
	public function getUsage() {
		try {
			$usage = AIService::instance()->getUsage();
			// Compose the gateway's authoritative totals with a local per-feature breakdown
			// (from the interaction log) so the UI can show where tokens are being spent.
			$usage['feature_breakdown'] = AIInteraction::tokenUsageByFeature( 30 );
			return new WP_REST_Response( $usage, 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_usage_get', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function synonymDiscover( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->synonym_discover->value ) {
			return new WP_Error( 'feature_disabled', __( 'Synonym discovery feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$phrase = sanitize_text_field( strtolower( (string) $request->get_param( 'phrase' ) ) );
			$lang   = sanitize_text_field( (string) $request->get_param( 'lang' ) );

			if ( $phrase === '' ) {
				return new WP_Error( 'invalid_phrase', __( 'A phrase is required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			return new WP_REST_Response( AISynonymService::instance()->discover( $phrase, $lang ), 200 );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_synonym_discover', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function synonymApply( WP_REST_Request $request ) {
		try {
			$params  = $request->get_json_params();
			$keyword = sanitize_text_field( (string) ( $params['keyword'] ?? '' ) );
			$synonym = sanitize_text_field( (string) ( $params['synonym'] ?? '' ) );
			$lang    = sanitize_text_field( (string) ( $params['lang'] ?? '' ) );

			if ( $keyword === '' || $synonym === '' ) {
				return new WP_Error( 'invalid_params', __( 'Keyword and synonym are required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			if ( strcasecmp( $keyword, $synonym ) === 0 ) {
				return new WP_Error( 'asp_ai_synonym_self', __( 'Synonym cannot be identical to the keyword.', 'ajax-search-pro' ), array( 'status' => 422 ) );
			}

			return new WP_REST_Response( AISynonymService::instance()->apply( $keyword, $synonym, $lang ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_synonym_apply', $e->getMessage() );
		}
	}

	/**
	 * POST ai/synonyms/generate — bulk-generates synonyms for the top-N popular index keywords.
	 *
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function synonymsGenerate( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->synonym_discover->value ) {
			return new WP_Error( 'feature_disabled', __( 'Synonym discovery feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params = $request->get_json_params();
			$count  = isset( $params['count'] ) ? (int) $params['count'] : 25;
			$lang   = sanitize_text_field( (string) ( $params['lang'] ?? '' ) );

			return new WP_REST_Response( AISynonymService::instance()->generateBulk( $count, $lang ), 200 );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_synonyms_generate', $e->getMessage() );
		}
	}

	/**
	 * POST ai/synonyms/bulk-apply — applies an accepted set of generated synonyms.
	 *
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function synonymsBulkApply( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->synonym_discover->value ) {
			return new WP_Error( 'feature_disabled', __( 'Synonym discovery feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params = $request->get_json_params();
			$lang   = sanitize_text_field( (string) ( $params['lang'] ?? '' ) );
			$items  = isset( $params['items'] ) && is_array( $params['items'] ) ? $params['items'] : array();

			return new WP_REST_Response( AISynonymService::instance()->applyBulk( $items, $lang ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_synonyms_bulk_apply', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function diagnosticStart( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->diagnostic->value ) {
			return new WP_Error( 'feature_disabled', __( 'The search diagnostic feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params = $request->get_json_params();
			$phrase = sanitize_text_field( (string) ( $params['phrase'] ?? '' ) );
			$asp_id = (int) ( $params['asp_id'] ?? 0 );
			$force  = ! empty( $params['force'] );

			if ( $phrase === '' ) {
				return new WP_Error( 'invalid_phrase', __( 'A phrase is required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			if ( empty( wd_asp()->instances->get( $asp_id ) ) ) {
				return new WP_Error( 'invalid_instance', __( 'Search instance not found.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			return new WP_REST_Response( AIDiagnosticService::instance()->start( $phrase, $asp_id, $force ), 200 );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_diagnostic_start', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function diagnosticMessage( WP_REST_Request $request ) {
		try {
			$params          = $request->get_json_params();
			$conversation_id = sanitize_text_field( (string) ( $params['conversation_id'] ?? '' ) );
			$message         = sanitize_textarea_field( (string) ( $params['message'] ?? '' ) );

			if ( $conversation_id === '' || $message === '' ) {
				return new WP_Error( 'invalid_params', __( 'conversation_id and message are required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			return new WP_REST_Response( AIDiagnosticService::instance()->sendMessage( $conversation_id, $message ), 200 );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_diagnostic_message', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function wizardGenerate( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->config_wizard->value ) {
			return new WP_Error( 'feature_disabled', __( 'The AI setup wizard is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params = $request->get_json_params();

			$answers = array(
				'site_type'           => sanitize_key( (string) ( $params['site_type'] ?? 'mixed' ) ),
				'content_types'       => is_array( $params['content_types'] ?? null ) ? array_map( 'sanitize_key', $params['content_types'] ) : array( 'post', 'page' ),
				'include_users'       => ! empty( $params['include_users'] ),
				'include_attachments' => ! empty( $params['include_attachments'] ),
				'engine'              => in_array( $params['engine'] ?? 'regular', array( 'regular', 'index' ), true ) ? $params['engine'] : 'regular',
				'search_terms'        => ! empty( $params['search_terms'] ),
				'keyword_logic'       => in_array( $params['keyword_logic'] ?? 'and', array( 'and', 'or' ), true ) ? $params['keyword_logic'] : 'and',
				'search_in_content'   => isset( $params['search_in_content'] ) ? (bool) $params['search_in_content'] : true,
				'show_descriptions'   => isset( $params['show_descriptions'] ) ? (bool) $params['show_descriptions'] : true,
				'language'            => sanitize_key( (string) ( $params['language'] ?? 'english' ) ),
			);

			return new WP_REST_Response( AIWizardService::instance()->generate( $answers ), 200 );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_wizard_generate', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function instanceCreate( WP_REST_Request $request ) {
		try {
			$params = $request->get_json_params();
			$name   = sanitize_text_field( (string) ( $params['name'] ?? '' ) );

			if ( $name === '' ) {
				return new WP_Error( 'invalid_name', __( 'Instance name is required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			return new WP_REST_Response(
				AIWizardService::instance()->createInstance(
					mb_substr( $name, 0, 100 ),
					in_array( $params['engine'] ?? 'regular', array( 'regular', 'index' ), true ) ? (string) $params['engine'] : 'regular',
					is_array( $params['content_types'] ?? null ) ? array_map( 'sanitize_key', $params['content_types'] ) : array(),
					is_array( $params['options'] ?? null ) ? $params['options'] : array(),
					! empty( $params['search_terms'] ),
					is_array( $params['index_custom_fields'] ?? null ) ? array_map( 'sanitize_text_field', $params['index_custom_fields'] ) : array(),
					! empty( $params['index_pdf'] )
				),
				200
			);
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_instance_create', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function qualityReport( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->quality_report->value ) {
			return new WP_Error( 'feature_disabled', __( 'The search quality report feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params = $request->get_params();
			$asp_id = (int) ( $params['asp_id'] ?? 0 );
			$days   = max( 7, min( 90, (int) ( $params['days'] ?? 30 ) ) );
			$force  = ! empty( $params['force'] );

			return new WP_REST_Response( AIQualityReportService::instance()->generate( $asp_id, $days, $force ), 200 );
		} catch ( AIInsufficientDataException $e ) {
			return new WP_Error( 'insufficient_data', $e->getMessage(), array( 'status' => 422 ) );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_quality_report', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function instanceSuggestionsGenerate( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->ai_suggestions->value ) {
			return new WP_Error( 'feature_disabled', __( 'The AI suggestions feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params        = $request->get_json_params();
			$max           = max( 10, min( 1000, (int) ( $params['max_suggestions'] ?? 50 ) ) );
			$asp_ids_param = $params['asp_ids'] ?? 'all';

			if ( $asp_ids_param === 'all' || empty( $asp_ids_param ) ) {
				$instances = wd_asp()->instances->get();
			} else {
				$instances = array();
				foreach ( (array) $asp_ids_param as $raw_id ) {
					$instance = wd_asp()->instances->get( (int) $raw_id );
					if ( ! empty( $instance ) ) {
						$instances[] = $instance;
					}
				}
			}

			if ( empty( $instances ) ) {
				return new WP_Error( 'no_instances', __( 'No valid search instances found.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			return new WP_REST_Response(
				array( 'results' => AIKeywordSuggestionsService::instance()->generate( (array) $instances, $max ) ),
				200
			);
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_suggestions_generate', $e->getMessage() );
		}
	}

	/** @return WP_Error|WP_REST_Response */
	public function instanceSuggestionsStatus() {
		try {
			return new WP_REST_Response( AIKeywordSuggestionsService::instance()->getStatus(), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_suggestions_status', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function instanceSuggestionsClear( WP_REST_Request $request ) {
		try {
			$params = $request->get_json_params();
			$asp_id = (int) ( $params['asp_id'] ?? 0 );

			if ( $asp_id === 0 ) {
				return new WP_Error( 'invalid_params', __( 'asp_id is required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			AIKeywordSuggestionsService::instance()->clear( $asp_id );
			return new WP_REST_Response( array( 'success' => true ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_suggestions_clear', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function instanceSuggestionsRemoveWord( WP_REST_Request $request ) {
		try {
			$params = $request->get_json_params();
			$asp_id = (int) ( $params['asp_id'] ?? 0 );
			$word   = sanitize_text_field( (string) ( $params['word'] ?? '' ) );

			if ( $asp_id === 0 || $word === '' ) {
				return new WP_Error( 'invalid_params', __( 'asp_id and word are required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			return new WP_REST_Response( AIKeywordSuggestionsService::instance()->removeWord( $asp_id, $word ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_suggestions_remove_word', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function prioritiesAdvisor( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->priorities_advisor->value ) {
			return new WP_Error( 'feature_disabled', __( 'The priorities advisor feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params = $request->get_params();
			$asp_id = (int) ( $params['asp_id'] ?? 0 );
			$force  = ! empty( $params['force'] );

			return new WP_REST_Response( AIPrioritiesAdvisorService::instance()->analyze( $asp_id, $force ), 200 );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_priorities_advisor', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function stopwordDetector( WP_REST_Request $request ) {
		if ( ! AIOptions::instance()->stopword_detector->value ) {
			return new WP_Error( 'feature_disabled', __( 'The stopword detector feature is not enabled.', 'ajax-search-pro' ), array( 'status' => 403 ) );
		}
		try {
			$params = $request->get_params();
			$asp_id = (int) ( $params['asp_id'] ?? 0 );
			$days   = max( 7, min( 90, (int) ( $params['days'] ?? 30 ) ) );
			$force  = ! empty( $params['force'] );

			return new WP_REST_Response( AIStopwordService::instance()->analyze( $asp_id, $days, $force ), 200 );
		} catch ( RuntimeException $e ) {
			return new WP_Error( 'ai_stopword_detector', $e->getMessage() );
		}
	}

	/**
	 * @param WP_REST_Request $request
	 * @return WP_Error|WP_REST_Response
	 */
	public function stopwordRemove( WP_REST_Request $request ) {
		try {
			$params = $request->get_json_params();
			$word   = strtolower( sanitize_text_field( (string) ( $params['word'] ?? '' ) ) );

			if ( $word === '' ) {
				return new WP_Error( 'invalid_params', __( 'word is required.', 'ajax-search-pro' ), array( 'status' => 400 ) );
			}

			return new WP_REST_Response( AIStopwordService::instance()->removeWord( $word ), 200 );
		} catch ( Exception $e ) {
			return new WP_Error( 'ai_stopword_remove', $e->getMessage() );
		}
	}
}
