<?php
/**
 * REST API: Customer lookup by billing phone for Voice Logica AI
 *
 * Allows the Node.js / WooCommerce API client to search customers by billing
 * phone by passing ?phone_number=... on the customers list endpoint.
 *
 * Performance approach:
 *   1. Query the usermeta table directly for matching user IDs using an indexed
 *      (meta_key, meta_value) lookup – avoids the slow JOIN that meta_query adds.
 *   2. Cache the resolved IDs in the WordPress object cache (60 s TTL) so repeated
 *      lookups for the same number within the same request or across quick retries
 *      do not hit the database again.
 *   3. Pass the resolved IDs via WP_User_Query's `include` parameter, which is a
 *      primary-key IN() lookup and is extremely fast.
 *
 * @package VoiceLogica_AI_WooCommerce
 */

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

/**
 * Class VoiceLogica_AI_REST_Customer_Phone
 */
class VoiceLogica_AI_REST_Customer_Phone {

	/** Cache group used for phone-to-user-ID results. */
	const CACHE_GROUP = 'voicelogica_phone_lookup';

	/** How long (seconds) to keep cached results. */
	const CACHE_TTL = 60;

	/**
	 * Hook into REST API customer query.
	 */
	public function __construct() {
		add_filter( 'woocommerce_rest_customer_query', array( $this, 'filter_customer_query_by_phone' ), 10, 2 );
	}

	/**
	 * Replace meta_query phone filtering with a fast pre-resolved ID list.
	 *
	 * Instead of adding a meta_query JOIN, we:
	 *   - Run one targeted SELECT on wp_usermeta (indexed by meta_key + meta_value).
	 *   - Cache the resulting IDs to skip the DB on repeat calls.
	 *   - Feed the IDs into `include` so WP_User_Query uses a PK-indexed IN() clause.
	 *
	 * @param array           $prepared_args WP_User_Query arguments.
	 * @param WP_REST_Request $request       REST request from the Node.js client.
	 * @return array Modified query args.
	 */
	public function filter_customer_query_by_phone( $prepared_args, $request ) {
		$phone = $request->get_param( 'phone_number' );

		if ( empty( $phone ) || ! is_string( $phone ) ) {
			return $prepared_args;
		}

		$phone = sanitize_text_field( $phone );
		if ( '' === $phone ) {
			return $prepared_args;
		}

		$user_ids = $this->get_user_ids_by_phone( $phone );

		if ( empty( $user_ids ) ) {
			// No match – force zero results without any table scan.
			$prepared_args['include'] = array( 0 );
			return $prepared_args;
		}

		// Merge with any existing `include` restriction (e.g. from other filters).
		if ( ! empty( $prepared_args['include'] ) ) {
			$prepared_args['include'] = array_intersect(
				(array) $prepared_args['include'],
				$user_ids
			);
			if ( empty( $prepared_args['include'] ) ) {
				$prepared_args['include'] = array( 0 );
			}
		} else {
			$prepared_args['include'] = $user_ids;
		}

		return $prepared_args;
	}

	/**
	 * Look up user IDs that have the given billing phone, with object-cache layer.
	 *
	 * @param string $phone Sanitized phone number to search for.
	 * @return int[] Array of user IDs (may be empty).
	 */
	private function get_user_ids_by_phone( $phone ) {
		$cache_key = 'phone_' . md5( $phone );
		$cached    = wp_cache_get( $cache_key, self::CACHE_GROUP );

		if ( false !== $cached ) {
			return $cached;
		}

		global $wpdb;

		// Single indexed query: (meta_key, meta_value) index on wp_usermeta makes
		// this far faster than the JOIN that meta_query would produce.
		// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
		$rows = $wpdb->get_col(
			$wpdb->prepare(
				"SELECT user_id FROM {$wpdb->usermeta} WHERE meta_key = %s AND meta_value = %s",
				'billing_phone',
				$phone
			)
		);

		$user_ids = ! empty( $rows ) ? array_map( 'intval', $rows ) : array();

		wp_cache_set( $cache_key, $user_ids, self::CACHE_GROUP, self::CACHE_TTL );

		return $user_ids;
	}
}
