<?php
/**
 * Variation expansion handler.
 *
 * @package Kramar
 * @since   1.0.0
 */

declare( strict_types=1 );

namespace Kramar\Modules\Marketing;

// Prevent direct access.
defined( 'ABSPATH' ) || exit;

/**
 * Expands WooCommerce products into the set of feed items to output.
 *
 * - Simple product  → [simple product]
 * - Variable + mode 'all'         → all published, in-catalog variations
 * - Variable + mode 'default'     → default variation (or first if no default)
 * - Variable + mode 'parent_only' → [variable product parent]
 *
 * @since 1.0.0
 */
final class Variation_Handler {

	/**
	 * Constructor.
	 *
	 * @since 1.0.0
	 *
	 * @param Feed_Config $cfg Module configuration.
	 */
	public function __construct( private Feed_Config $cfg ) {}

	/**
	 * Return feed items for a product.
	 *
	 * @since 1.0.0
	 *
	 * @param \WC_Product $product Product object.
	 * @return array<\WC_Product> One or more product/variation objects.
	 */
	public function get_items( \WC_Product $product ): array {
		if ( ! $product->is_type( 'variable' ) ) {
			return [ $product ];
		}

		$mode = $this->cfg->get_variation_mode();

		if ( 'parent_only' === $mode ) {
			return [ $product ];
		}

		/** @var \WC_Product_Variable $product */
		$variation_ids = $product->get_visible_children();

		if ( empty( $variation_ids ) ) {
			// No purchasable variations — output the parent.
			return [ $product ];
		}

		if ( 'default' === $mode ) {
			$default_attrs = $product->get_default_attributes();
			// Try to find the variation matching the default attributes.
			$default_id = $product->get_matching_variation( $default_attrs );
			if ( $default_id ) {
				$variation = wc_get_product( $default_id );
				if ( $variation instanceof \WC_Product ) {
					return [ $variation ];
				}
			}
			// Fall back to first visible variation.
			$first = wc_get_product( reset( $variation_ids ) );
			return $first instanceof \WC_Product ? [ $first ] : [ $product ];
		}

		// Mode 'all': return all visible (in-catalog) variations.
		$items = [];
		foreach ( $variation_ids as $vid ) {
			$variation = wc_get_product( $vid );
			if ( $variation instanceof \WC_Product && $this->passes_stock_filter( $variation ) ) {
				$items[] = $variation;
			}
		}
		return ! empty( $items ) ? $items : [ $product ];
	}

	/**
	 * Whether a variation may appear in the feed given the module's own
	 * "include out-of-stock products" setting.
	 *
	 * The parent-level query filters on the variable product's own _stock_status,
	 * which WooCommerce reports as "instock" as soon as ANY one variation is in
	 * stock — so an out-of-stock variation always slipped through with its
	 * parent. get_visible_children() is no help either: it only drops
	 * out-of-stock variations when the site-wide "Hide out of stock items from
	 * the catalog" option happens to be on, which is a completely separate
	 * setting this module does not control. Apply our own setting explicitly.
	 *
	 * @since 1.0.2
	 */
	private function passes_stock_filter( \WC_Product $variation ): bool {
		if ( $this->cfg->include_out_of_stock() ) {
			return true;
		}

		return $variation->is_in_stock();
	}
}
