<?php
/**
 * Product descriptor service.
 *
 * @package Ugcify\AI
 */

namespace Ugcify\AI;

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

/**
 * Class ProductDescriptorService
 */
class ProductDescriptorService {
	public const META_DESCRIPTOR  = '_ugcify_ai_catalog_descriptor';
	public const META_FINGERPRINT = '_ugcify_ai_catalog_fingerprint';
	public const META_UPDATED_AT  = '_ugcify_ai_catalog_updated_at';

	/**
	 * Get or build a descriptor.
	 *
	 * @param \WC_Product $product Product.
	 * @return string
	 */
	public function get_descriptor( $product ): string {
		if ( ! $product || ! is_object( $product ) || ! method_exists( $product, 'get_id' ) ) {
			return '';
		}

		$product_id  = (int) $product->get_id();
		$fingerprint = $this->build_fingerprint( $product );
		$stored_hash = (string) get_post_meta( $product_id, self::META_FINGERPRINT, true );
		$stored      = (string) get_post_meta( $product_id, self::META_DESCRIPTOR, true );

		if ( $stored && $stored_hash === $fingerprint ) {
			return $stored;
		}

		$descriptor = $this->build_descriptor( $product );
		update_post_meta( $product_id, self::META_DESCRIPTOR, $descriptor );
		update_post_meta( $product_id, self::META_FINGERPRINT, $fingerprint );
		update_post_meta( $product_id, self::META_UPDATED_AT, current_time( 'mysql' ) );

		return $descriptor;
	}

	/**
	 * Build descriptor text.
	 *
	 * @param \WC_Product $product Product.
	 * @return string
	 */
	private function build_descriptor( $product ): string {
		$parts = array(
			(string) $product->get_name(),
			(string) $product->get_sku(),
			wp_strip_all_tags( (string) $product->get_short_description() ),
		);

		$parts = array_merge( $parts, $this->get_term_names( (int) $product->get_id(), 'product_cat' ) );
		$parts = array_merge( $parts, $this->get_term_names( (int) $product->get_id(), 'product_tag' ) );
		$parts = array_merge( $parts, $this->get_attribute_values( $product ) );

		return trim( preg_replace( '/\s+/', ' ', implode( ' ', array_filter( array_map( 'strval', $parts ) ) ) ) );
	}

	/**
	 * Build fingerprint.
	 *
	 * @param \WC_Product $product Product.
	 * @return string
	 */
	private function build_fingerprint( $product ): string {
		$data = array(
			$product->get_name(),
			$product->get_sku(),
			$product->get_short_description(),
			$product->get_image_id(),
			$product->get_gallery_image_ids(),
			$this->get_term_names( (int) $product->get_id(), 'product_cat' ),
			$this->get_term_names( (int) $product->get_id(), 'product_tag' ),
			$this->get_attribute_values( $product ),
		);

		return hash( 'sha256', wp_json_encode( $data ) );
	}

	/**
	 * Get term names.
	 *
	 * @param int    $product_id Product ID.
	 * @param string $taxonomy Taxonomy.
	 * @return array<int,string>
	 */
	private function get_term_names( int $product_id, string $taxonomy ): array {
		$terms = get_the_terms( $product_id, $taxonomy );
		if ( empty( $terms ) || is_wp_error( $terms ) ) {
			return array();
		}

		return array_values(
			array_filter(
				array_map(
					static function ( $term ) {
						return isset( $term->name ) ? (string) $term->name : '';
					},
					$terms
				)
			)
		);
	}

	/**
	 * Get product attribute values.
	 *
	 * @param \WC_Product $product Product.
	 * @return array<int,string>
	 */
	private function get_attribute_values( $product ): array {
		$values = array();

		foreach ( $product->get_attributes() as $attribute ) {
			if ( is_object( $attribute ) && method_exists( $attribute, 'get_options' ) ) {
				$values = array_merge( $values, array_map( 'strval', (array) $attribute->get_options() ) );
			}
		}

		return array_values( array_unique( array_filter( $values ) ) );
	}
}
