<?php
/**
 * WooCommerce product search for the label picker (Phase 1).
 *
 * @package PhoenixWP\PriceLabels\Admin
 */

declare(strict_types=1);

namespace PhoenixWP\PriceLabels\Admin;

use WC_Product;

defined( 'ABSPATH' ) || exit;

/**
 * Queries products for admin multi-select.
 */
final class Product_Search {

	private static ?self $instance = null;

	public const AJAX_ACTION = 'phoenix_wp_price_labels_search_products';

	public const NONCE_ACTION = 'phoenix_wp_price_labels_picker';

	public const PER_PAGE = 20;

	public static function instance(): self {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	private function __construct() {}

	private function __clone() {}

	public function init(): void {
		add_action( 'wp_ajax_' . self::AJAX_ACTION, array( $this, 'ajax_search' ) );
	}

	/**
	 * AJAX handler for live product search.
	 */
	public function ajax_search(): void {
		check_ajax_referer( self::NONCE_ACTION, 'nonce' );

		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			wp_send_json_error( array( 'message' => __( 'Permission denied.', 'phoenix-price-labels-for-woocommerce' ) ), 403 );
		}

		$search_raw = filter_input( INPUT_GET, 'search', FILTER_DEFAULT );
		$search     = is_string( $search_raw ) ? sanitize_text_field( $search_raw ) : '';
		$page_raw   = filter_input( INPUT_GET, 'page', FILTER_DEFAULT );
		$page       = null !== $page_raw && '' !== (string) $page_raw ? max( 1, absint( (string) $page_raw ) ) : 1;

		wp_send_json_success(
			array(
				'products' => $this->search( $search, $page ),
				'page'     => $page,
			)
		);
	}

	/**
	 * @return array<int, array<string, int|string>>
	 */
	public function search( string $term, int $page = 1 ): array {
		if ( ! function_exists( 'wc_get_products' ) ) {
			return array();
		}

		$term = trim( $term );

		if ( '' !== $term && ctype_digit( $term ) ) {
			$product = wc_get_product( (int) $term );

			if ( $product instanceof WC_Product && 'publish' === $product->get_status() ) {
				return array( $this->format_product( $product ) );
			}
		}

		$common = array(
			'status'  => 'publish',
			'limit'   => self::PER_PAGE,
			'page'    => max( 1, $page ),
			'orderby' => '' === $term ? 'modified' : 'title',
			'order'   => '' === $term ? 'DESC' : 'ASC',
			'return'  => 'objects',
		);

		if ( '' !== $term ) {
			$by_title = wc_get_products( array_merge( $common, array( 's' => $term ) ) );

			if ( $by_title ) {
				return $this->format_products( $by_title );
			}

			$by_sku = wc_get_products( array_merge( $common, array( 'sku' => $term ) ) );

			if ( $by_sku ) {
				return $this->format_products( $by_sku );
			}

			return array();
		}

		return $this->format_products( wc_get_products( $common ) );
	}

	/**
	 * @param WC_Product[] $products Product objects.
	 * @return array<int, array<string, int|string>>
	 */
	private function format_products( array $products ): array {
		$rows = array();

		foreach ( $products as $product ) {
			if ( $product instanceof WC_Product ) {
				$rows[] = $this->format_product( $product );
			}
		}

		return $rows;
	}

	/**
	 * @return array{id: int, name: string, type: string, sku: string, label: string}
	 */
	private function format_product( WC_Product $product ): array {
		$id   = $product->get_id();
		$name = $product->get_name();
		$sku  = $product->get_sku();
		$type = $product->get_type();

		$label = $name . ' (#' . $id . ')';

		if ( '' !== $sku ) {
			$label .= ' — ' . $sku;
		}

		if ( $product->is_type( 'variable' ) ) {
			$label .= ' · ' . __( 'variable', 'phoenix-price-labels-for-woocommerce' );
		}

		return array(
			'id'    => $id,
			'name'  => $name,
			'type'  => $type,
			'sku'   => $sku,
			'label' => $label,
		);
	}
}
