<?php

namespace CelerSearch\Autocomplete;

defined( 'ABSPATH' ) || exit;

use CelerSearch\DataTransfer\IndexResponses\SearchResponse;
use CelerSearch\Factories\IndexFactory;
use CelerSearch\Indices\BaseIndex;
use CelerSearch\Interfaces\IRegistrable;
use WP_Error;
use WP_REST_Request;
use WP_REST_Response;
use WP_REST_Server;

/**
 * REST API endpoint for autocomplete search
 */
class RestApi implements IRegistrable {

	/**
	 * API namespace
	 */
	const NAMESPACE = 'celersearch/v1';

	/**
	 * Register hooks
	 *
	 * @return void
	 */
	public function register(): void {
		add_action( 'rest_api_init', [ $this, 'register_routes' ] );
	}

	/**
	 * Register REST API routes
	 *
	 * @return void
	 */
	public function register_routes(): void {
		register_rest_route( self::NAMESPACE, '/autocomplete', [
			'methods'             => WP_REST_Server::READABLE,
			'callback'            => [ $this, 'handle_search' ],
			'permission_callback' => [ $this, 'check_permission' ],
			'args'                => [
				'q'        => [
					'required'          => true,
					'type'              => 'string',
					'sanitize_callback' => 'sanitize_text_field',
					'description'       => __( 'Search query string', 'celersearch' ),
				],
				'index_id' => [
					'required'          => false,
					'type'              => 'integer',
					'default'           => 0,
					'sanitize_callback' => 'absint',
					'description'       => __( 'Index ID to search', 'celersearch' ),
				],
				'limit'    => [
					'required'          => false,
					'type'              => 'integer',
					'default'           => 5,
					'minimum'           => 1,
					'maximum'           => 20,
					'sanitize_callback' => 'absint',
					'description'       => __( 'Maximum number of results', 'celersearch' ),
				],
				'context'  => [
					'required' => false,
					'type'     => 'string',
					'default'  => 'frontend',
					'enum'     => [ 'frontend', 'admin' ],
				],
			],
		] );
	}

	/**
	 * Check if request has permission
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return bool|WP_Error
	 */
	public function check_permission( WP_REST_Request $request ) {
		$context = $request->get_param( 'context' );

		// Admin context requires edit_posts capability
		if ( $context === 'admin' ) {
			if ( ! current_user_can( 'edit_posts' ) ) {
				return new WP_Error(
					'rest_forbidden',
					__( 'You do not have permission to access admin search.', 'celersearch' ),
					[ 'status' => 403 ]
				);
			}
		}

		// Check if search is enabled
		$settings = get_option( 'celersearch_settings', [] );
		if ( empty( $settings['enable_search'] ) ) {
			return new WP_Error(
				'search_disabled',
				__( 'CelerSearch is not enabled.', 'celersearch' ),
				[ 'status' => 400 ]
			);
		}

		return true;
	}

	/**
	 * Handle autocomplete search request
	 *
	 * @param WP_REST_Request $request
	 *
	 * @return WP_REST_Response|WP_Error
	 */
	public function handle_search( WP_REST_Request $request ) {
		$query    = $request->get_param( 'q' );
		$index_id = $request->get_param( 'index_id' );
		$limit    = $request->get_param( 'limit' );
		$context  = $request->get_param( 'context' );

		// If no index specified, try to get default
		if ( empty( $index_id ) ) {
			$settings = get_option( 'celersearch_settings', [] );
			$index_id = $settings['default_index_id'] ?? 0;

			if ( empty( $index_id ) ) {
				return new WP_Error(
					'no_index',
					__( 'No search index configured.', 'celersearch' ),
					[ 'status' => 400 ]
				);
			}
		}

		try {
			// Create index instance
			$index = IndexFactory::create( $index_id );

			// Build search params
			$params = [
				'limit'        => $limit,
				'highlighting' => [
					'enabled'  => true,
					'fields'   => [ 'title', 'content' ],
					'pre_tag'  => '<em class="celersearch-highlight">',
					'post_tag' => '</em>',
				],
			];

			// Add status filter based on context and index type
			$status_filter = $this->get_status_filter( $context, $index );
			if ( ! empty( $status_filter ) ) {
				$params['filters'] = [ $status_filter ];
			}

			// Allow filtering params
			$params = apply_filters( 'celersearch_autocomplete_search_params', $params, $query, $index, $context );

			// Perform search
			$response = $index->search( $query, $params );

			// Check for errors
			if ( $response->is_error_response() ) {
				return new WP_Error(
					'search_error',
					__( 'Search failed.', 'celersearch' ),
					[ 'status' => 500 ]
				);
			}

			// Format hits for autocomplete
			$hits = $this->format_hits( $response->get_hits(), $index );

			return new WP_REST_Response( [
				'success' => true,
				'data'    => [
					'hits'  => $hits,
					'total' => $response->get_total_hits(),
					'query' => $query,
				],
			] );

		} catch ( \Exception $e ) {
			return new WP_Error(
				'search_exception',
				$e->getMessage(),
				[ 'status' => 500 ]
			);
		}
	}

	/**
	 * Get status filter from the index
	 *
	 * @param string    $context
	 * @param BaseIndex $index
	 *
	 * @return array|null
	 */
	private function get_status_filter( string $context, BaseIndex $index ): ?array {
		return $index->get_autocomplete_status_filter( $context );
	}

	/**
	 * Format search hits for autocomplete response
	 *
	 * @param array     $hits  Raw hits from search index
	 * @param BaseIndex $index The index that produced the hits
	 *
	 * @return array
	 */
	private function format_hits( array $hits, BaseIndex $index ): array {
		$formatted = [];

		foreach ( $hits as $hit ) {
			$formatted_hit = $index->format_autocomplete_hit( $hit );

			if ( $formatted_hit ) {
				$formatted[] = apply_filters( 'celersearch_autocomplete_hit', $formatted_hit, $hit, $index );
			}
		}

		return $formatted;
	}
}
