<?php
/**
 * ASIN Helper Class
 *
 * Provides plan-aware ASIN storage and retrieval functionality.
 * Supports both standard plan (single ASIN) and premium plan (marketplace-specific ASINs).
 * Includes per-marketplace status, price, and condition storage with in-request caching.
 *
 * @package    MOMCS_Sync
 * @subpackage MOMCS_Sync/includes/common/utils
 * @author     miniOrange
 * @license    Expat
 * @link       https://miniorange.com
 */

declare( strict_types=1 );

namespace MOMCS_Sync\Includes\Common\Utils;

use MOMCS_Sync\Includes\Common\Constants\Plugin_Constants;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * ASIN Helper utility functions.
 *
 * Handles plan-aware ASIN storage:
 * - Standard Plan: Single _momcs_amz_asin meta key
 * - Premium Plan: Marketplace-specific _momcs_amz_asin_MARKETPLACE_ID meta keys
 *
 * Per-marketplace meta storage for:
 * - Status: _momcs_amz_status_{marketplace_id}
 * - Price: _momcs_amz_price_{marketplace_id}
 * - Condition: _momcs_amz_condition_{marketplace_id}
 */
class Asin_Helper {

	/**
	 * In-request cache for marketplace data to avoid repeated DB queries.
	 *
	 * Structure: [ product_id => [ 'status' => [...], 'price' => [...], 'condition' => [...] ] ]
	 *
	 * @var array<int, array<string, array<string, mixed>>>
	 */
	private static array $marketplace_cache = array();

	/**
	 * Meta key prefixes for per-marketplace data.
	 * Fallback values if premium constants not available.
	 */
	private const META_PREFIX_STATUS    = '_momcs_amz_status_';
	private const META_PREFIX_PRICE     = '_momcs_amz_price_';
	private const META_PREFIX_CONDITION = '_momcs_amz_condition_';

	/**
	 * Valid listing status values for validation.
	 */
	private const VALID_STATUSES = array(
		'uploaded',
		'pending',
		'failed',
		'processing',
		'BUYABLE',
		'DISCOVERABLE',
	);

	/**
	 * Get product ASIN in a plan-aware manner.
	 *
	 * @param int         $product_id    The WooCommerce product ID.
	 * @param string|null $marketplace_id The Amazon marketplace ID (e.g., 'ATVPDKIKX0DER').
	 *                                   Only used in premium plan.
	 * @return string The ASIN value, or empty string if not found.
	 */
	public static function get_product_asin( int $product_id, ?string $marketplace_id = null ): string {
		if ( $product_id <= 0 ) {
			return '';
		}

		$meta_key = self::get_asin_meta_key( $marketplace_id );
		$asin     = get_post_meta( $product_id, $meta_key, true );

		return is_string( $asin ) ? trim( $asin ) : '';
	}

	/**
	 * Set product ASIN in a plan-aware manner.
	 *
	 * @param int         $product_id    The WooCommerce product ID.
	 * @param string      $asin          The ASIN value to store.
	 * @param string|null $marketplace_id The Amazon marketplace ID (e.g., 'ATVPDKIKX0DER').
	 *                                   Only used in premium plan.
	 * @return bool True if the meta was updated successfully, false otherwise.
	 */
	public static function set_product_asin( int $product_id, string $asin, ?string $marketplace_id = null ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$meta_key    = self::get_asin_meta_key( $marketplace_id );
		$asin        = trim( $asin );
		$meta_result = update_post_meta( $product_id, $meta_key, $asin );

		// update_post_meta returns meta_id on success, true if value unchanged, false on failure.
		return false !== $meta_result;
	}

	/**
	 * Delete product ASIN in a plan-aware manner.
	 *
	 * @param int         $product_id    The WooCommerce product ID.
	 * @param string|null $marketplace_id The Amazon marketplace ID (e.g., 'ATVPDKIKX0DER').
	 *                                   Only used in premium plan.
	 * @return bool True if the meta was deleted successfully, false otherwise.
	 */
	public static function delete_product_asin( int $product_id, ?string $marketplace_id = null ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$meta_key = self::get_asin_meta_key( $marketplace_id );
		return delete_post_meta( $product_id, $meta_key );
	}

	/**
	 * Check if a product has ASIN for the given marketplace (or any ASIN in standard plan).
	 *
	 * @param int         $product_id    The WooCommerce product ID.
	 * @param string|null $marketplace_id The Amazon marketplace ID. Only used in premium plan.
	 * @return bool True if product has ASIN, false otherwise.
	 */
	public static function product_has_asin( int $product_id, ?string $marketplace_id = null ): bool {
		$asin = self::get_product_asin( $product_id, $marketplace_id );
		return ! empty( $asin );
	}

	/**
	 * Get the correct meta key for ASIN storage based on current plan.
	 *
	 * @param string|null $marketplace_id The Amazon marketplace ID. Only used in premium plan.
	 * @return string The meta key to use for ASIN storage.
	 */
	private static function get_asin_meta_key( ?string $marketplace_id = null ): string {
		// Standard plan always uses single ASIN meta key.
		if ( ! Utils::is_premium_plan() ) {
			return '_momcs_amz_asin';
		}

		// Premium plan: use marketplace-specific key if marketplace_id provided.
		if ( ! empty( $marketplace_id ) ) {
			return '_momcs_amz_asin_' . $marketplace_id;
		}

		// Premium plan fallback: use standard key if no marketplace specified.
		return '_momcs_amz_asin';
	}


	/**
	 * Get all available meta keys that might contain ASIN values.
	 * Useful for premium plan to find all marketplace-specific ASINs.
	 *
	 * @param int $product_id The WooCommerce product ID.
	 * @return array<string> Array of meta keys that contain ASIN values.
	 */
	public static function get_asin_meta_keys( int $product_id ): array {
		if ( $product_id <= 0 ) {
			return array();
		}

		global $wpdb;
		if ( ! isset( $wpdb ) || ! property_exists( $wpdb, 'postmeta' ) ) {
			return array();
		}

		// Get all meta keys that start with _momcs_amz_asin.
		$meta_keys = $wpdb->get_col( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Always need updated data from database.
			$wpdb->prepare(
				"SELECT DISTINCT meta_key FROM {$wpdb->postmeta} 
				WHERE post_id = %d 
				AND meta_key LIKE %s 
				AND meta_value != ''",
				$product_id,
				'_momcs_amz_asin%'
			)
		);

		return is_array( $meta_keys ) ? $meta_keys : array();
	}

	/**
	 * Get all ASINs for a product across all marketplaces (premium plan only).
	 *
	 * @param int $product_id The WooCommerce product ID.
	 * @return array<string,string> Array of marketplace_id => asin pairs.
	 */
	public static function get_all_product_asins( int $product_id ): array {
		if ( ! Utils::is_premium_plan() || $product_id <= 0 ) {
			return array();
		}

		$asin_meta_keys = self::get_asin_meta_keys( $product_id );
		$asins          = array();

		foreach ( $asin_meta_keys as $meta_key ) {
			$asin = get_post_meta( $product_id, $meta_key, true );

			if ( ! empty( $asin ) ) {
				// Extract marketplace ID from meta key.
				if ( '_momcs_amz_asin' === $meta_key ) {
					// Standard ASIN key (fallback).
					$asins['standard'] = $asin;
				} elseif ( strpos( $meta_key, '_momcs_amz_asin_' ) === 0 ) {
					// Marketplace-specific key.
					$marketplace_id = substr( $meta_key, strlen( '_momcs_amz_asin_' ) );
					if ( ! empty( $marketplace_id ) ) {
						$asins[ $marketplace_id ] = $asin;
					}
				}
			}
		}

		return $asins;
	}

	// =========================================================================
	// Per-Marketplace Status Methods
	// =========================================================================

	/**
	 * Set product listing status for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $status         The listing status (uploaded, pending, failed, processing, BUYABLE, DISCOVERABLE).
	 * @param string $marketplace_id The Amazon marketplace ID (e.g., 'ATVPDKIKX0DER').
	 * @return bool True if the meta was updated successfully, false otherwise.
	 */
	public static function set_product_status( int $product_id, string $status, string $marketplace_id ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$status      = self::normalize_status( $status );
		$meta_key    = self::META_PREFIX_STATUS . $marketplace_id;
		$meta_result = update_post_meta( $product_id, $meta_key, $status );

		// Invalidate cache for this product.
		self::invalidate_product_cache( $product_id );

		return false !== $meta_result;
	}

	/**
	 * Get product listing status for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return string|null The listing status or null if not found.
	 */
	public static function get_product_status( int $product_id, string $marketplace_id ): ?string {
		if ( $product_id <= 0 ) {
			return null;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return null;
		}

		// Check in-request cache first.
		if ( isset( self::$marketplace_cache[ $product_id ]['status'][ $marketplace_id ] ) ) {
			return self::$marketplace_cache[ $product_id ]['status'][ $marketplace_id ];
		}

		$meta_key = self::META_PREFIX_STATUS . $marketplace_id;
		$status   = get_post_meta( $product_id, $meta_key, true );

		// Cache the result (even if empty).
		if ( ! isset( self::$marketplace_cache[ $product_id ] ) ) {
			self::$marketplace_cache[ $product_id ] = array(
				'status'    => array(),
				'price'     => array(),
				'condition' => array(),
			);
		}

		$result = ! empty( $status ) && is_string( $status ) ? $status : null;
		self::$marketplace_cache[ $product_id ]['status'][ $marketplace_id ] = $result;

		return $result;
	}

	/**
	 * Delete product listing status for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return bool True if the meta was deleted successfully, false otherwise.
	 */
	public static function delete_product_status( int $product_id, string $marketplace_id ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$meta_key = self::META_PREFIX_STATUS . $marketplace_id;
		$result   = delete_post_meta( $product_id, $meta_key );

		self::invalidate_product_cache( $product_id );

		return $result;
	}

	// =========================================================================
	// Per-Marketplace Price Methods
	// =========================================================================

	/**
	 * Set product Amazon price for a specific marketplace.
	 *
	 * Note: This stores the Amazon listing price, NOT the WooCommerce price.
	 * WooCommerce price/stock are never overwritten.
	 *
	 * @param int          $product_id     The WooCommerce product ID.
	 * @param float|string $price          The Amazon listing price.
	 * @param string       $marketplace_id The Amazon marketplace ID.
	 * @return bool True if the meta was updated successfully, false otherwise.
	 */
	public static function set_product_amazon_price( int $product_id, $price, string $marketplace_id ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$price       = self::normalize_price( $price );
		$meta_key    = self::META_PREFIX_PRICE . $marketplace_id;
		$meta_result = update_post_meta( $product_id, $meta_key, $price );

		self::invalidate_product_cache( $product_id );

		return false !== $meta_result;
	}

	/**
	 * Get product Amazon price for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return float|null The Amazon listing price or null if not found.
	 */
	public static function get_product_amazon_price( int $product_id, string $marketplace_id ): ?float {
		if ( $product_id <= 0 ) {
			return null;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return null;
		}

		// Check in-request cache first.
		if ( isset( self::$marketplace_cache[ $product_id ]['price'][ $marketplace_id ] ) ) {
			return self::$marketplace_cache[ $product_id ]['price'][ $marketplace_id ];
		}

		$meta_key = self::META_PREFIX_PRICE . $marketplace_id;
		$price    = get_post_meta( $product_id, $meta_key, true );

		// Initialize cache structure if needed.
		if ( ! isset( self::$marketplace_cache[ $product_id ] ) ) {
			self::$marketplace_cache[ $product_id ] = array(
				'status'    => array(),
				'price'     => array(),
				'condition' => array(),
			);
		}

		$result = ( '' !== $price && false !== $price ) ? (float) $price : null;
		self::$marketplace_cache[ $product_id ]['price'][ $marketplace_id ] = $result;

		return $result;
	}

	/**
	 * Delete product Amazon price for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return bool True if the meta was deleted successfully, false otherwise.
	 */
	public static function delete_product_amazon_price( int $product_id, string $marketplace_id ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$meta_key = self::META_PREFIX_PRICE . $marketplace_id;
		$result   = delete_post_meta( $product_id, $meta_key );

		self::invalidate_product_cache( $product_id );

		return $result;
	}

	// =========================================================================
	// Per-Marketplace Condition Methods
	// =========================================================================

	/**
	 * Set product condition for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $condition      The product condition (e.g., 'new_new', 'used_good').
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return bool True if the meta was updated successfully, false otherwise.
	 */
	public static function set_product_condition( int $product_id, string $condition, string $marketplace_id ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$condition   = sanitize_text_field( $condition );
		$meta_key    = self::META_PREFIX_CONDITION . $marketplace_id;
		$meta_result = update_post_meta( $product_id, $meta_key, $condition );

		self::invalidate_product_cache( $product_id );

		return false !== $meta_result;
	}

	/**
	 * Get product condition for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return string|null The product condition or null if not found.
	 */
	public static function get_product_condition( int $product_id, string $marketplace_id ): ?string {
		if ( $product_id <= 0 ) {
			return null;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return null;
		}

		// Check in-request cache first.
		if ( isset( self::$marketplace_cache[ $product_id ]['condition'][ $marketplace_id ] ) ) {
			return self::$marketplace_cache[ $product_id ]['condition'][ $marketplace_id ];
		}

		$meta_key  = self::META_PREFIX_CONDITION . $marketplace_id;
		$condition = get_post_meta( $product_id, $meta_key, true );

		// Initialize cache structure if needed.
		if ( ! isset( self::$marketplace_cache[ $product_id ] ) ) {
			self::$marketplace_cache[ $product_id ] = array(
				'status'    => array(),
				'price'     => array(),
				'condition' => array(),
			);
		}

		$result = ! empty( $condition ) && is_string( $condition ) ? $condition : null;
		self::$marketplace_cache[ $product_id ]['condition'][ $marketplace_id ] = $result;

		return $result;
	}

	/**
	 * Delete product condition for a specific marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return bool True if the meta was deleted successfully, false otherwise.
	 */
	public static function delete_product_condition( int $product_id, string $marketplace_id ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$meta_key = self::META_PREFIX_CONDITION . $marketplace_id;
		$result   = delete_post_meta( $product_id, $meta_key );

		self::invalidate_product_cache( $product_id );

		return $result;
	}

	// =========================================================================
	// Aggregate Methods
	// =========================================================================

	/**
	 * Get all marketplace data for a product.
	 *
	 * Returns an associative array keyed by marketplace ID with ASIN, status, price, and condition.
	 * Optimized to fetch all meta in a single query for UI chip rendering.
	 *
	 * @param int $product_id The WooCommerce product ID.
	 * @return array<string, array{asin: string|null, status: string|null, price: float|null, condition: string|null}>
	 *         Array of marketplace data keyed by marketplace ID.
	 */
	public static function get_all_marketplace_data( int $product_id ): array {
		if ( $product_id <= 0 ) {
			return array();
		}

		global $wpdb;
		if ( ! isset( $wpdb ) || ! property_exists( $wpdb, 'postmeta' ) ) {
			return array();
		}

		// Fetch all marketplace-related meta in a single optimized query.
		$meta_rows = $wpdb->get_results( //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Performance critical, need fresh data.
			$wpdb->prepare(
				"SELECT meta_key, meta_value FROM {$wpdb->postmeta} 
				WHERE post_id = %d 
				AND (
					meta_key LIKE %s OR
					meta_key LIKE %s OR
					meta_key LIKE %s OR
					meta_key LIKE %s
				)
				AND meta_value != ''",
				$product_id,
				'_momcs_amz_asin_%',
				'_momcs_amz_status_%',
				'_momcs_amz_price_%',
				'_momcs_amz_condition_%'
			),
			ARRAY_A
		);

		if ( empty( $meta_rows ) || ! is_array( $meta_rows ) ) {
			return array();
		}

		$marketplace_data = array();
		$prefixes         = array(
			'asin'      => '_momcs_amz_asin_',
			'status'    => self::META_PREFIX_STATUS,
			'price'     => self::META_PREFIX_PRICE,
			'condition' => self::META_PREFIX_CONDITION,
		);

		foreach ( $meta_rows as $row ) {
			$meta_key   = $row['meta_key'];
			$meta_value = $row['meta_value'];

			// Determine which type this is and extract marketplace ID.
			foreach ( $prefixes as $type => $prefix ) {
				if ( strpos( $meta_key, $prefix ) === 0 ) {
					$marketplace_id = substr( $meta_key, strlen( $prefix ) );

					// Skip if no marketplace ID (standard key without suffix).
					if ( empty( $marketplace_id ) ) {
						continue;
					}

					// Initialize marketplace entry if needed.
					if ( ! isset( $marketplace_data[ $marketplace_id ] ) ) {
						$marketplace_data[ $marketplace_id ] = array(
							'asin'      => null,
							'status'    => null,
							'price'     => null,
							'condition' => null,
						);
					}

					// Store value with appropriate type conversion.
					if ( 'price' === $type ) {
						$marketplace_data[ $marketplace_id ][ $type ] = (float) $meta_value;
					} else {
						$marketplace_data[ $marketplace_id ][ $type ] = $meta_value;
					}

					break;
				}
			}
		}

		// Populate in-request cache for subsequent single-value calls.
		foreach ( $marketplace_data as $mp_id => $data ) {
			if ( ! isset( self::$marketplace_cache[ $product_id ] ) ) {
				self::$marketplace_cache[ $product_id ] = array(
					'status'    => array(),
					'price'     => array(),
					'condition' => array(),
				);
			}
			if ( null !== $data['status'] ) {
				self::$marketplace_cache[ $product_id ]['status'][ $mp_id ] = $data['status'];
			}
			if ( null !== $data['price'] ) {
				self::$marketplace_cache[ $product_id ]['price'][ $mp_id ] = $data['price'];
			}
			if ( null !== $data['condition'] ) {
				self::$marketplace_cache[ $product_id ]['condition'][ $mp_id ] = $data['condition'];
			}
		}

		return $marketplace_data;
	}

	/**
	 * Set all marketplace data for a product in a single batch operation.
	 *
	 * Optimized for sync operations that update multiple fields at once.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @param array  $data           Array with optional keys: asin, status, price, condition.
	 * @return bool True if at least one field was updated successfully.
	 */
	public static function set_marketplace_data( int $product_id, string $marketplace_id, array $data ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$updated = false;

		// Update ASIN if provided.
		if ( isset( $data['asin'] ) ) {
			if ( self::set_product_asin( $product_id, (string) $data['asin'], $marketplace_id ) ) {
				$updated = true;
			}
		}

		// Update status if provided.
		if ( isset( $data['status'] ) ) {
			$meta_key = self::META_PREFIX_STATUS . $marketplace_id;
			$status   = self::normalize_status( (string) $data['status'] );
			if ( false !== update_post_meta( $product_id, $meta_key, $status ) ) {
				$updated = true;
			}
		}

		// Update price if provided.
		if ( isset( $data['price'] ) ) {
			$meta_key = self::META_PREFIX_PRICE . $marketplace_id;
			$price    = self::normalize_price( $data['price'] );
			if ( false !== update_post_meta( $product_id, $meta_key, $price ) ) {
				$updated = true;
			}
		}

		// Update condition if provided.
		if ( isset( $data['condition'] ) ) {
			$meta_key  = self::META_PREFIX_CONDITION . $marketplace_id;
			$condition = sanitize_text_field( (string) $data['condition'] );
			if ( false !== update_post_meta( $product_id, $meta_key, $condition ) ) {
				$updated = true;
			}
		}

		// Invalidate cache after batch update.
		if ( $updated ) {
			self::invalidate_product_cache( $product_id );
		}

		return $updated;
	}

	/**
	 * Delete all marketplace data for a product and specific marketplace.
	 *
	 * Removes ASIN, status, price, and condition for the given marketplace.
	 *
	 * @param int    $product_id     The WooCommerce product ID.
	 * @param string $marketplace_id The Amazon marketplace ID.
	 * @return bool True if at least one field was deleted.
	 */
	public static function delete_marketplace_data( int $product_id, string $marketplace_id ): bool {
		if ( $product_id <= 0 ) {
			return false;
		}

		$marketplace_id = self::sanitize_marketplace_id( $marketplace_id );
		if ( empty( $marketplace_id ) ) {
			return false;
		}

		$deleted = false;

		// Delete all marketplace-specific meta.
		$deleted = self::delete_product_asin( $product_id, $marketplace_id ) || $deleted;
		$deleted = delete_post_meta( $product_id, self::META_PREFIX_STATUS . $marketplace_id ) || $deleted;
		$deleted = delete_post_meta( $product_id, self::META_PREFIX_PRICE . $marketplace_id ) || $deleted;
		$deleted = delete_post_meta( $product_id, self::META_PREFIX_CONDITION . $marketplace_id ) || $deleted;

		self::invalidate_product_cache( $product_id );

		return $deleted;
	}

	/**
	 * Get all marketplace IDs that have data for a product.
	 *
	 * @param int $product_id The WooCommerce product ID.
	 * @return array<string> Array of marketplace IDs.
	 */
	public static function get_product_marketplace_ids( int $product_id ): array {
		$all_data = self::get_all_marketplace_data( $product_id );
		return array_keys( $all_data );
	}

	// =========================================================================
	// Cache Management Methods
	// =========================================================================

	/**
	 * Clear the entire in-request cache.
	 *
	 * Call this at the start of batch operations or when memory is a concern.
	 *
	 * @return void
	 */
	public static function clear_cache(): void {
		self::$marketplace_cache = array();
	}

	/**
	 * Invalidate cache for a specific product.
	 *
	 * @param int $product_id The WooCommerce product ID.
	 * @return void
	 */
	public static function invalidate_product_cache( int $product_id ): void {
		unset( self::$marketplace_cache[ $product_id ] );
	}

	/**
	 * Warm the cache for multiple products at once.
	 *
	 * Optimized for bulk UI rendering - fetches all marketplace data for
	 * multiple products in a single query.
	 *
	 * @param array<int> $product_ids Array of WooCommerce product IDs.
	 * @return void
	 */
	public static function warm_cache_for_products( array $product_ids ): void {
		if ( empty( $product_ids ) ) {
			return;
		}

		// Filter valid IDs.
		$product_ids = array_filter( array_map( 'intval', $product_ids ), fn( $id ) => $id > 0 );
		if ( empty( $product_ids ) ) {
			return;
		}

		global $wpdb;
		if ( ! isset( $wpdb ) || ! property_exists( $wpdb, 'postmeta' ) ) {
			return;
		}

		// Build placeholders for IN clause.
		$placeholders = implode( ',', array_fill( 0, count( $product_ids ), '%d' ) );

		// Fetch all marketplace-related meta for all products in one query.
		$query = $wpdb->prepare(
			"SELECT post_id, meta_key, meta_value FROM {$wpdb->postmeta} 
			WHERE post_id IN ({$placeholders}) 
			AND (
				meta_key LIKE %s OR
				meta_key LIKE %s OR
				meta_key LIKE %s OR
				meta_key LIKE %s
			)
			AND meta_value != ''",
			array_merge(
				$product_ids,
				array(
					'_momcs_amz_asin_%',
					'_momcs_amz_status_%',
					'_momcs_amz_price_%',
					'_momcs_amz_condition_%',
				)
			)
		);

		$meta_rows = $wpdb->get_results( $query, ARRAY_A ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- Prepared above, performance critical.

		if ( empty( $meta_rows ) || ! is_array( $meta_rows ) ) {
			return;
		}

		$prefixes = array(
			'status'    => self::META_PREFIX_STATUS,
			'price'     => self::META_PREFIX_PRICE,
			'condition' => self::META_PREFIX_CONDITION,
		);

		foreach ( $meta_rows as $row ) {
			$product_id = (int) $row['post_id'];
			$meta_key   = $row['meta_key'];
			$meta_value = $row['meta_value'];

			// Initialize cache structure if needed.
			if ( ! isset( self::$marketplace_cache[ $product_id ] ) ) {
				self::$marketplace_cache[ $product_id ] = array(
					'status'    => array(),
					'price'     => array(),
					'condition' => array(),
				);
			}

			// Determine type and extract marketplace ID.
			foreach ( $prefixes as $type => $prefix ) {
				if ( strpos( $meta_key, $prefix ) === 0 ) {
					$marketplace_id = substr( $meta_key, strlen( $prefix ) );
					if ( ! empty( $marketplace_id ) ) {
						if ( 'price' === $type ) {
							self::$marketplace_cache[ $product_id ][ $type ][ $marketplace_id ] = (float) $meta_value;
						} else {
							self::$marketplace_cache[ $product_id ][ $type ][ $marketplace_id ] = $meta_value;
						}
					}
					break;
				}
			}
		}
	}

	// =========================================================================
	// Validation & Sanitization Helpers
	// =========================================================================

	/**
	 * Sanitize marketplace ID.
	 *
	 * Amazon marketplace IDs are alphanumeric strings (e.g., 'ATVPDKIKX0DER').
	 *
	 * @param string $marketplace_id Raw marketplace ID.
	 * @return string Sanitized marketplace ID or empty string if invalid.
	 */
	private static function sanitize_marketplace_id( string $marketplace_id ): string {
		$marketplace_id = trim( $marketplace_id );

		// Allow only alphanumeric characters (Amazon marketplace IDs are uppercase alphanumeric).
		if ( ! preg_match( '/^[A-Z0-9]+$/i', $marketplace_id ) ) {
			return '';
		}

		return strtoupper( $marketplace_id );
	}

	/**
	 * Normalize listing status to a known value.
	 *
	 * @param string $status Raw status value.
	 * @return string Normalized status (defaults to 'pending' if invalid).
	 */
	private static function normalize_status( string $status ): string {
		$status = trim( $status );

		// Check if it's a known status (case-insensitive for lowercase values).
		foreach ( self::VALID_STATUSES as $valid ) {
			if ( strcasecmp( $status, $valid ) === 0 ) {
				// Preserve case for Amazon API statuses (BUYABLE, DISCOVERABLE).
				return ctype_upper( $valid[0] ) ? $valid : strtolower( $valid );
			}
		}

		// Default to 'pending' for unknown statuses.
		return 'pending';
	}

	/**
	 * Normalize price to float.
	 *
	 * @param mixed $price Raw price value (string, int, or float).
	 * @return float Normalized price (0.0 if invalid or negative).
	 */
	private static function normalize_price( $price ): float {
		if ( is_numeric( $price ) ) {
			$normalized = (float) $price;
			return $normalized >= 0 ? $normalized : 0.0;
		}

		return 0.0;
	}

	/**
	 * Check if a status is considered "active" (product is listed on Amazon).
	 *
	 * @param string|null $status The listing status.
	 * @return bool True if the product is actively listed.
	 */
	public static function is_active_status( ?string $status ): bool {
		if ( null === $status ) {
			return false;
		}

		$active_statuses = array( 'uploaded', 'BUYABLE', 'DISCOVERABLE' );
		return in_array( $status, $active_statuses, true );
	}

	/**
	 * Check if a product is listed on any marketplace.
	 *
	 * @param int $product_id The WooCommerce product ID.
	 * @return bool True if product is listed on at least one marketplace.
	 */
	public static function is_listed_on_any_marketplace( int $product_id ): bool {
		$marketplace_data = self::get_all_marketplace_data( $product_id );

		foreach ( $marketplace_data as $data ) {
			if ( self::is_active_status( $data['status'] ) ) {
				return true;
			}
		}

		return false;
	}
}
