<?php
/**
 * Class Noesia Cs Admin Search Service.
 *
 * @package Noesia_Commerce_Suite
 */

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

/**
 * Admin-only command search for the Noesia Commerce Suite shell.
 *
 * The service intentionally keeps the MVP search narrow, fast and HPOS-safe:
 * - exact order number / ID lookups;
 * - exact billing email order lookups;
 * - bounded recent-order fallback for customer/order text;
 * - product title/SKU lookups through WordPress/WooCommerce product APIs;
 * - passport results only when an active order token already exists.
 */
class Noesia_CS_Admin_Search_Service {
	/**
	 * Runtime dependency or state value.
	 *
	 * @var mixed
	 */
	private $passport_service;
	/**
	 * Runtime dependency or state value.
	 *
	 * @var mixed
	 */
	private $order_repository;
	/**
	 * Runtime dependency or state value.
	 *
	 * @var mixed
	 */
	private $product_repository;

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $passport_service Passport service.
	 * @param mixed $order_repository Order repository.
	 * @param mixed $product_repository Product repository.
	 */
	public function __construct( Noesia_CS_Passport_Service $passport_service = null, Noesia_CS_Order_Repository $order_repository = null, Noesia_CS_Product_Repository $product_repository = null ) {
		$this->passport_service   = $passport_service ? $passport_service : new Noesia_CS_Passport_Service();
		$this->order_repository   = $order_repository ? $order_repository : new Noesia_CS_Order_Repository();
		$this->product_repository = $product_repository ? $product_repository : new Noesia_CS_Product_Repository();
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $query Query.
	 * @param mixed $limit Limit.
	 */
	public function search( $query, $limit = 5 ) {
		$query  = $this->normalize_query( $query );
		$limit  = max( 1, min( 10, absint( $limit ) ) );

		if ( strlen( $query ) < 2 ) {
			return array(
				'groups'  => array(),
				'note'    => __( 'Type at least two characters to search orders, products and passports.', 'noesia-commerce-suite' ),
			);
		}

		if ( ! class_exists( 'WooCommerce' ) ) {
			return array(
				'groups'  => array(),
				'note'    => __( 'WooCommerce is required for command search results.', 'noesia-commerce-suite' ),
			);
		}

		$order_results     = $this->search_orders( $query, $limit );
		$product_results   = $this->search_products( $query, $limit );
		$passport_results  = $this->build_passport_results( $query, $order_results, $limit );

		$groups = array();
		if ( ! empty( $order_results ) ) {
			$groups[] = array(
				'label'  => __( 'Orders', 'noesia-commerce-suite' ),
				'items'  => array_values( $order_results ),
			);
		}
		if ( ! empty( $passport_results ) ) {
			$groups[] = array(
				'label'  => __( 'Passports', 'noesia-commerce-suite' ),
				'items'  => array_values( $passport_results ),
			);
		}
		if ( ! empty( $product_results ) ) {
			$groups[] = array(
				'label'  => __( 'Products', 'noesia-commerce-suite' ),
				'items'  => array_values( $product_results ),
			);
		}

		return array(
			'groups'  => $groups,
			'note'    => empty( $groups ) ? __( 'No matching orders, passports or products found.', 'noesia-commerce-suite' ) : '',
		);
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $query Query.
	 */
	private function normalize_query( $query ) {
		$query  = sanitize_text_field( wp_unslash( $query ) );
		$query  = preg_replace( '/\s+/', ' ', trim( $query ) );
		return is_string( $query ) ? $query : '';
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $query Query.
	 * @param mixed $limit Limit.
	 */
	private function search_orders( $query, $limit ) {
		if ( ! $this->order_repository->is_available() ) {
			return array();
		}

		$results  = array();
		$orders   = array();
		$numeric  = preg_replace( '/[^0-9]/', '', $query );

		if ( $numeric ) {
			$order = wc_get_order( absint( $numeric ) );
			if ( $order ) {
				$orders[] = $order;
			}
		}

		if ( is_email( $query ) ) {
			$email_orders = wc_get_orders(
				array(
					'limit'          => $limit,
					'orderby'        => 'date',
					'order'          => 'DESC',
					'return'         => 'objects',
					'billing_email'  => sanitize_email( $query ),
				)
			);
			if ( is_array( $email_orders ) ) {
				$orders = array_merge( $orders, $email_orders );
			}
		}

		$recent = $this->order_repository->get_recent_orders( 60 );
		foreach ( $recent as $order ) {
			if ( ! is_a( $order, 'WC_Order' ) ) {
				continue;
			}
			if ( $this->order_matches_query( $order, $query ) ) {
				$orders[] = $order;
			}
		}

		foreach ( $orders as $order ) {
			if ( ! is_a( $order, 'WC_Order' ) ) {
				continue;
			}
			$order_id = absint( $order->get_id() );
			if ( isset( $results[ $order_id ] ) ) {
				continue;
			}
			$results[ $order_id ] = $this->format_order_result( $order );
			if ( count( $results ) >= $limit ) {
				break;
			}
		}

		return $results;
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $order Order.
	 * @param mixed $query Query.
	 */
	private function order_matches_query( $order, $query ) {
		$haystack = array(
			$order->get_order_number(),
			$order->get_billing_first_name(),
			$order->get_billing_last_name(),
			$order->get_billing_company(),
			$order->get_billing_city(),
			$order->get_shipping_city(),
		);

		if ( is_email( $query ) ) {
			$haystack[] = $order->get_billing_email();
		}

		$needle = strtolower( $query );
		foreach ( $haystack as $value ) {
			$value = strtolower( (string) $value );
			if ( '' !== $value && false !== strpos( $value, $needle ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $order Order.
	 */
	private function format_order_result( $order ) {
		$created  = $order->get_date_created();
		$date     = $created ? $created->date_i18n( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ) ) : __( 'Date unavailable', 'noesia-commerce-suite' );
		$status   = function_exists( 'wc_get_order_status_name' ) ? wc_get_order_status_name( $order->get_status() ) : $order->get_status();
		$total   = function_exists( 'wc_price' ) ? wp_strip_all_tags( wc_price( (float) $order->get_total(), array( 'currency' => $order->get_currency() ) ) ) : number_format_i18n( (float) $order->get_total(), 2 );
		$name  = $this->get_order_customer_label( $order );
		$url   = method_exists( $order, 'get_edit_order_url' ) ? $order->get_edit_order_url() : '';

		return array(
			'type'   => 'order',
			'title'  => sprintf(
				/* translators: %s: order number */
				__( 'Order #%s', 'noesia-commerce-suite' ),
				$order->get_order_number()
			),
			'subtitle' => sprintf(
				/* translators: 1: customer label, 2: order total, 3: order status, 4: order date */
				__( '%1$s · %2$s · %3$s · %4$s', 'noesia-commerce-suite' ),
				$name,
				$total,
				$status,
				$date
			),
			'badge'    => __( 'Order', 'noesia-commerce-suite' ),
			'url'      => esc_url_raw( $url ),
			'actions'  => array(
				array(
					'label'  => __( 'Open Order', 'noesia-commerce-suite' ),
					'url'    => esc_url_raw( $url ),
				),
			),
			'order_id' => absint( $order->get_id() ),
		);
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $query Query.
	 * @param mixed $order_results Order results.
	 * @param mixed $limit Limit.
	 */
	private function build_passport_results( $query, $order_results, $limit ) {
		$results = array();

		if ( preg_match( '/^[a-zA-Z0-9]{32,96}$/', $query ) && method_exists( $this->passport_service, 'find_order_by_token' ) ) {
			$order = $this->passport_service->find_order_by_token( $query );
			if ( $order ) {
				$order_results[ absint( $order->get_id() ) ] = $this->format_order_result( $order );
			}
		}

		foreach ( $order_results as $order_result ) {
			$order_id  = absint( $order_result['order_id'] ?? 0 );
			$order     = $order_id ? wc_get_order( $order_id ) : null;
			if ( ! $order || ! $this->passport_service->order_has_active_token( $order ) ) {
				continue;
			}
			$url = $this->passport_service->get_existing_care_url_for_order( $order );
			if ( ! $url ) {
				continue;
			}
			$results[ $order_id ] = array(
				'type'   => 'passport',
				'title'  => sprintf(
					/* translators: %s: order number */
					__( 'Order Care Hub for order #%s', 'noesia-commerce-suite' ),
					$order->get_order_number()
				),
				'subtitle'  => __( 'Secure Order Care Hub with active QR token.', 'noesia-commerce-suite' ),
				'badge'     => __( 'Care Hub', 'noesia-commerce-suite' ),
				'url'       => esc_url_raw( $url ),
				'actions'   => array(
					array(
						'label'   => __( 'View Care Hub', 'noesia-commerce-suite' ),
						'url'     => esc_url_raw( $url ),
						'target'  => '_blank',
					),
					array(
						'label'  => __( 'Copy Care Link', 'noesia-commerce-suite' ),
						'copy'   => esc_url_raw( $url ),
					),
				),
			);

			if ( count( $results ) >= $limit ) {
				break;
			}
		}

		return $results;
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $query Query.
	 * @param mixed $limit Limit.
	 */
	private function search_products( $query, $limit ) {
		if ( ! $this->product_repository->is_available() ) {
			return array();
		}

		$product_ids  = array();
		$sku_id       = function_exists( 'wc_get_product_id_by_sku' ) ? wc_get_product_id_by_sku( $query ) : 0;
		if ( $sku_id ) {
			$product_ids[] = absint( $sku_id );
		}

		$posts = get_posts(
			array(
				'post_type'               => array( 'product', 'product_variation' ),
				'post_status'             => array( 'publish', 'private' ),
				's'                       => $query,
				'posts_per_page'          => $limit,
				'fields'                  => 'ids',
				'no_found_rows'           => true,
				'update_post_meta_cache'  => false,
				'update_post_term_cache'  => false,
			)
		);

		if ( is_array( $posts ) ) {
			$product_ids = array_merge( $product_ids, array_map( 'absint', $posts ) );
		}

		$results = array();
		foreach ( array_unique( array_filter( $product_ids ) ) as $product_id ) {
			$product = wc_get_product( $product_id );
			if ( ! $product ) {
				continue;
			}
			$results[ $product_id ] = $this->format_product_result( $product );
			if ( count( $results ) >= $limit ) {
				break;
			}
		}

		return $results;
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $product Product.
	 */
	private function format_product_result( $product ) {
		$product_id  = absint( $product->get_id() );
		$sku         = $product->get_sku();
		$price       = $product->get_price();
		$stock       = $product->is_in_stock() ? __( 'In stock', 'noesia-commerce-suite' ) : __( 'Out of stock', 'noesia-commerce-suite' );
		$price_text = '' !== $price && function_exists( 'wc_price' ) ? wp_strip_all_tags( wc_price( (float) $price ) ) : __( 'No price', 'noesia-commerce-suite' );
		$url        = get_edit_post_link( $product_id, 'raw' );

		return array(
			'type'      => 'product',
			'title'     => $product->get_name(),
			'subtitle'  => sprintf(
				/* translators: 1: product SKU, 2: product price, 3: stock status */
				__( 'SKU: %1$s · %2$s · %3$s', 'noesia-commerce-suite' ),
				$sku ? $sku : __( 'No SKU', 'noesia-commerce-suite' ),
				$price_text,
				$stock
			),
			'badge'    => __( 'Product', 'noesia-commerce-suite' ),
			'url'      => esc_url_raw( $url ),
			'actions'  => array(
				array(
					'label'  => __( 'Open Product', 'noesia-commerce-suite' ),
					'url'    => esc_url_raw( $url ),
				),
			),
		);
	}

	/**
	 * Handles the related plugin operation.
	 *
	 * @param mixed $order Order.
	 */
	private function get_order_customer_label( $order ) {
		$name = trim( $order->get_billing_first_name() . ' ' . $order->get_billing_last_name() );
		if ( '' !== $name ) {
			return sanitize_text_field( $name );
		}
		$company = $order->get_billing_company();
		if ( $company ) {
			return sanitize_text_field( $company );
		}
		return __( 'Guest customer', 'noesia-commerce-suite' );
	}
}
