<?php
/**
 * Knowledge Search AJAX Relay Handler
 *
 * Receives browser search requests (nonce auth), embeds the query via
 * middleware /api/knowledge/embed-query, then does local cosine similarity
 * search. Used by voice chat DataChannel relay for mid-conversation RAG.
 *
 * @since 1.8.0
 */

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

class SiteStaffr_Knowledge_Search_Handler {

	/**
	 * Handle AJAX knowledge search relay.
	 */
	public static function ajax_knowledge_search() {
		check_ajax_referer( 'sitestaffr_knowledge_search', 'nonce' );

		$query       = isset( $_POST['query'] ) ? sanitize_text_field( wp_unslash( $_POST['query'] ) ) : '';
		$max_results = isset( $_POST['max_results'] ) ? intval( wp_unslash( $_POST['max_results'] ) ) : 5;
		$post_id     = isset( $_POST['post_id'] ) ? absint( wp_unslash( $_POST['post_id'] ) ) : null;
		if ( $post_id === 0 ) {
			$post_id = null;
		}

		if ( empty( $query ) || strlen( $query ) < 3 ) {
			wp_send_json_error( array( 'message' => 'Query too short' ), 400 );
		}

		if ( $max_results < 1 || $max_results > 10 ) {
			$max_results = 5;
		}

		// Step 1: Get embedding from middleware.
		$embedding = self::get_query_embedding( $query );
		if ( is_wp_error( $embedding ) ) {
			wp_send_json_error( array( 'message' => $embedding->get_error_message() ), 502 );
		}

		// Step 2: Search locally (hybrid vector+keyword, same path as text chat).
		require_once SITESTAFFR_PLUGIN_DIR . 'includes/class-sitestaffr-knowledge-manager.php';
		$chunks = SiteStaffr_Knowledge_Manager::search_hybrid( $embedding, $query, $max_results, $post_id );

		// Increment hit counts for returned chunks (hot knowledge tracking).
		if ( ! empty( $chunks ) ) {
			$chunk_ids = array();
			foreach ( $chunks as $chunk ) {
				if ( isset( $chunk['id'] ) ) {
					$chunk_ids[] = (int) $chunk['id'];
				}
			}
			if ( ! empty( $chunk_ids ) ) {
				SiteStaffr_Knowledge_Manager::increment_hit_counts( $chunk_ids );
			}
		}

		wp_send_json_success( array( 'chunks' => $chunks ) );
	}

	/**
	 * Call middleware /api/knowledge/embed-query to generate embedding vector.
	 *
	 * Uses the same HMAC auth pattern as knowledge sync (trait-sitestaffr-admin-knowledge-ajax.php).
	 *
	 * @param string $query Search query text.
	 * @return array|WP_Error Embedding vector or error.
	 */
	private static function get_query_embedding( $query ) {
		if ( ! defined( 'SITESTAFFR_MIDDLEWARE_URL' ) || empty( SITESTAFFR_MIDDLEWARE_URL ) ) {
			return new \WP_Error( 'no_middleware', 'Middleware not configured.' );
		}

		// Per-site secret first, then global fallback (same as admin knowledge sync).
		$api_secret = get_option( 'sitestaffr_site_api_secret', '' );
		if ( empty( $api_secret ) ) {
			$api_secret = get_option( 'sitestaffr_api_secret', '' );
		}
		if ( empty( $api_secret ) ) {
			return new \WP_Error( 'no_secret', 'API secret not configured.' );
		}

		$url       = rtrim( SITESTAFFR_MIDDLEWARE_URL, '/' ) . '/api/knowledge/embed-query';
		$body      = wp_json_encode( array( 'query' => $query ) );
		$timestamp = (string) time();
		$signature = base64_encode( hash_hmac( 'sha256', $timestamp . '.' . $body, $api_secret, true ) );

		$response = wp_remote_post(
			$url,
			array(
				'timeout' => 8,
				'headers' => array(
					'Content-Type'           => 'application/json',
					'X-SiteStaffr-Signature' => $signature,
					'X-SiteStaffr-Timestamp' => $timestamp,
					'X-SiteStaffr-Site-URL'  => esc_url_raw( get_site_url() ),
				),
				'body'    => $body,
			)
		);

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$code = wp_remote_retrieve_response_code( $response );
		$raw  = wp_remote_retrieve_body( $response );
		$data = json_decode( $raw, true );

		if ( 200 !== $code || empty( $data['success'] ) || empty( $data['embedding'] ) ) {
			$msg = isset( $data['message'] ) ? $data['message'] : 'Embedding request failed (HTTP ' . $code . ')';
			return new \WP_Error( 'embed_failed', $msg );
		}

		return $data['embedding'];
	}
}
