<?php
/**
 * Postomatic Plugin - WooCommerce Product Source.
 *
 * PHP Version 5.6
 *
 * @package  Postomatic
 * @category Plugin
 * @license  GPL-2.0-or-later https://www.gnu.org/licenses/gpl-2.0.html
 * @link     https://buildomatics.com/postomatics
 * @since    1.3.0
 */

namespace Postomatic\Api;

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

/**
 * Product_Source_Woocommerce.
 *
 * Reads products from WooCommerce using its own public API
 * (`wc_get_products()`, `WC_Product`), never a raw `WP_Query`. This avoids
 * clashing with unrelated plugins/themes that may also register a post type
 * literally named "product".
 *
 * @since 1.3.0
 */
class Product_Source_Woocommerce extends Product_Source_Abstract {

	const PLATFORM_KEY = 'woocommerce';

	/**
	 * {@inheritDoc}
	 */
	public static function is_active(): bool {
		// WC_PLUGIN_FILE / WC() are defined by WooCommerce itself once fully
		// loaded; function_exists( 'wc_get_products' ) is the documented,
		// stable way plugins are expected to detect WooCommerce.
		return function_exists( 'wc_get_products' ) && class_exists( 'WooCommerce' );
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_platform_key(): string {
		return self::PLATFORM_KEY;
	}

	/**
	 * {@inheritDoc}
	 */
	public function get_platform_label(): string {
		return 'WooCommerce';
	}

	/**
	 * {@inheritDoc}
	 */
	public function has_products(): bool {
		if ( ! self::is_active() ) {
			return false;
		}

		$products = wc_get_products(
			array(
				'status' => 'publish',
				'limit'  => 1,
				'return' => 'ids',
			)
		);

		return ! empty( $products );
	}

	/**
	 * {@inheritDoc}
	 *
	 * @param string $search   Optional search term to filter by product name.
	 * @param int    $page     Page number (1-indexed).
	 * @param int    $per_page Number of products per page.
	 */
	public function get_products( string $search = '', int $page = 1, int $per_page = 20 ): array {
		if ( ! self::is_active() ) {
			return $this->empty_result( $page, $per_page );
		}

		$args = array(
			'status' => 'publish',
			'limit'  => $per_page,
			'page'   => $page,
		);

		if ( '' !== $search ) {
			$args['s'] = $search;
		}

		$wc_products = wc_get_products( $args );

		$total_ids = wc_get_products(
			array_merge(
				$args,
				array(
					'limit'  => -1,
					'page'   => 1,
					'return' => 'ids',
				)
			)
		);
		$total     = count( $total_ids );

		$products = array();
		foreach ( $wc_products as $product ) {
			$products[] = $this->format_product( $product );
		}

		return array(
			'products'   => $products,
			'pagination' => $this->build_pagination( $total, $page, $per_page ),
		);
	}

	/**
	 * Normalize a single WC_Product into Postomatic's shared product shape.
	 *
	 * @param \WC_Product $product WooCommerce product object.
	 *
	 * @return array<string, mixed>
	 */
	private function format_product( $product ): array {
		$product_id = $product->get_id();

		$image_ids  = array();
		$image_urls = array();

		$main_image_id = $product->get_image_id();
		if ( $main_image_id ) {
			$image_ids[]          = $main_image_id;
			$main_image_url       = wp_get_attachment_url( $main_image_id );
			$main_image_large     = wp_get_attachment_image_src( $main_image_id, 'large' );
			$main_image_large_url = $main_image_large ? $main_image_large[0] : '';
		} else {
			$main_image_url       = '';
			$main_image_large_url = '';
		}

		$gallery_image_ids  = $product->get_gallery_image_ids();
		$article_image_ids  = array();
		$article_image_urls = array();

		if ( ! empty( $gallery_image_ids ) ) {
			$image_ids         = array_merge( $image_ids, $gallery_image_ids );
			$article_image_ids = $gallery_image_ids;

			foreach ( $gallery_image_ids as $gallery_image_id ) {
				$gallery_image_url = wp_get_attachment_url( $gallery_image_id );
				if ( $gallery_image_url ) {
					$image_urls[]         = $gallery_image_url;
					$article_image_urls[] = $gallery_image_url;

					$large_image = wp_get_attachment_image_src( $gallery_image_id, 'large' );
					if ( $large_image ) {
						$image_urls[]         = $large_image[0];
						$article_image_urls[] = $large_image[0];
					}
				}
			}
		}

		$related_products = array();
		$related_ids      = wc_get_related_products( $product_id, 5 );

		foreach ( $related_ids as $related_id ) {
			$related_product = wc_get_product( $related_id );
			if ( $related_product ) {
				$related_products[] = array(
					'id'    => $related_id,
					'name'  => $related_product->get_name(),
					'url'   => get_permalink( $related_id ),
					'image' => wp_get_attachment_url( $related_product->get_image_id() ),
				);
			}
		}

		$product_meta = array(
			'id'                 => $product_id,
			'platform'           => self::PLATFORM_KEY,
			'name'               => $product->get_name(),
			'sku'                => $product->get_sku() ? $product->get_sku() : '',
			'price'              => $product->get_price(),
			'regular_price'      => $product->get_regular_price(),
			'sale_price'         => $product->get_sale_price(),
			'price_html'         => $product->get_price_html(),
			'on_sale'            => $product->is_on_sale(),
			'stock_status'       => $product->get_stock_status(),
			'stock_quantity'     => $product->get_stock_quantity(),
			'short_description'  => $product->get_short_description(),
			'description'        => $product->get_description(),
			'permalink'          => get_permalink( $product_id ),
			'categories'         => $this->get_product_categories( $product ),
			'tags'               => $this->get_product_tags( $product ),
			'attributes'         => $this->get_product_attributes( $product ),
			'dimensions'         => array(
				'length' => $product->get_length(),
				'width'  => $product->get_width(),
				'height' => $product->get_height(),
			),
			'weight'             => $product->get_weight(),
			'average_rating'     => $product->get_average_rating(),
			'review_count'       => $product->get_review_count(),
			'image_ids'          => $image_ids,
			'image_urls'         => array_unique( $image_urls ),
			'article_image_ids'  => $article_image_ids,
			'article_image_urls' => array_unique( $article_image_urls ),
			'main_image'         => $main_image_url,
			'main_image_large'   => $main_image_large_url,
			'related_products'   => $related_products,
		);

		return $this->build_list_item(
			$product_id,
			$product->get_name(),
			$product->get_price_html(),
			$product->get_short_description(),
			get_permalink( $product_id ),
			$main_image_url,
			$product_meta
		);
	}

	/**
	 * Get product categories.
	 *
	 * @param \WC_Product $product The product object.
	 *
	 * @return array An array of product categories.
	 */
	private function get_product_categories( $product ) {
		$categories = array();
		$terms      = get_the_terms( $product->get_id(), 'product_cat' );

		if ( $terms && ! is_wp_error( $terms ) ) {
			foreach ( $terms as $term ) {
				$categories[] = $term->name;
			}
		}

		return $categories;
	}

	/**
	 * Get product tags.
	 *
	 * @param \WC_Product $product The product object.
	 *
	 * @return array An array of product tags.
	 */
	private function get_product_tags( $product ) {
		$tags  = array();
		$terms = get_the_terms( $product->get_id(), 'product_tag' );

		if ( $terms && ! is_wp_error( $terms ) ) {
			foreach ( $terms as $term ) {
				$tags[] = $term->name;
			}
		}

		return $tags;
	}

	/**
	 * Get product attributes.
	 *
	 * @param \WC_Product $product The product object.
	 *
	 * @return array An array of product attributes.
	 */
	private function get_product_attributes( $product ) {
		$attributes         = array();
		$product_attributes = $product->get_attributes();

		if ( ! empty( $product_attributes ) ) {
			foreach ( $product_attributes as $attribute_name => $attribute ) {
				$name   = wc_attribute_label( $attribute_name );
				$values = array();

				if ( $attribute->is_taxonomy() ) {
					$attribute_values = wc_get_product_terms( $product->get_id(), $attribute->get_name(), array( 'fields' => 'all' ) );

					foreach ( $attribute_values as $attribute_value ) {
						$values[] = $attribute_value->name;
					}
				} else {
					$values = $attribute->get_options();
				}

				$attributes[ $name ] = implode( ', ', $values );
			}
		}

		return $attributes;
	}
}
