<?php
/**
 * POS Product Visibility Sync class.
 *
 * @package Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog
 */

declare(strict_types=1);

namespace Automattic\WooCommerce\Internal\ProductFeed\Integrations\POSCatalog;

use Automattic\WooCommerce\Enums\ProductType;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Handles syncing pos_product_visibility taxonomy to products and variations.
 *
 * When a variable product is marked as hidden from POS, all its variations
 * should also be marked as hidden. This class ensures that:
 * - Products and their variations have the correct pos-hidden term
 * - New variations inherit the pos-hidden term from their parent
 *
 * @since 10.5.0
 */
class POSProductVisibilitySync {

	/**
	 * Register hooks for syncing POS visibility.
	 *
	 * @since 10.5.0
	 *
	 * @return void
	 */
	public function register_hooks(): void {
		add_action( 'woocommerce_new_product_variation', array( $this, 'inherit_parent_pos_visibility' ), 10, 2 );
	}

	/**
	 * Whether POS visibility can be managed for the given product.
	 *
	 * Only simple and variable products that are not downloadable support the
	 * "Available for POS" option; this is the single definition used by both the
	 * product data meta box UI and the save logic.
	 *
	 * @since 11.0.0
	 *
	 * @param \WC_Product $product The product to check.
	 * @return bool True if the product type supports POS visibility.
	 */
	public function is_product_supported( \WC_Product $product ): bool {
		return $product->is_type( array( ProductType::SIMPLE, ProductType::VARIABLE ) ) && ! $product->is_downloadable();
	}

	/**
	 * Set POS visibility for a product and its variations.
	 *
	 * This method sets or removes the pos-hidden term on the product,
	 * and if it's a variable product, syncs the visibility to all variations.
	 *
	 * @since 10.5.0
	 *
	 * @param int  $product_id     The product ID.
	 * @param bool $visible_in_pos Whether the product should be visible in POS.
	 * @return void
	 */
	public function set_product_pos_visibility( int $product_id, bool $visible_in_pos ): void {
		$is_currently_visible = ! has_term( 'pos-hidden', 'pos_product_visibility', $product_id );

		if ( $is_currently_visible === $visible_in_pos ) {
			return; // No change detected.
		}

		if ( $visible_in_pos ) {
			wp_remove_object_terms( $product_id, 'pos-hidden', 'pos_product_visibility' );
		} else {
			wp_set_object_terms( $product_id, 'pos-hidden', 'pos_product_visibility' );
		}

		$product = wc_get_product( $product_id );
		if ( $product && $product->is_type( 'variable' ) ) {
			$this->sync_pos_visibility_to_variations( $product, $visible_in_pos );
		}
	}

	/**
	 * Sync POS visibility to all variations of a variable product.
	 *
	 * @since 10.5.0
	 *
	 * @param \WC_Product $product        The variable product.
	 * @param bool        $visible_in_pos Whether the product should be visible in POS.
	 * @return void
	 */
	private function sync_pos_visibility_to_variations( \WC_Product $product, bool $visible_in_pos ): void {
		$variation_ids = $product->get_children();
		foreach ( $variation_ids as $variation_id ) {
			if ( $visible_in_pos ) {
				wp_remove_object_terms( $variation_id, 'pos-hidden', 'pos_product_visibility' );
			} else {
				wp_set_object_terms( $variation_id, 'pos-hidden', 'pos_product_visibility' );
			}

			// Save variation to update date_modified.
			$variation = wc_get_product( $variation_id );
			if ( $variation ) {
				$variation->save();
			}
		}
	}

	/**
	 * Inherit POS visibility from parent when a new variation is created.
	 *
	 * When a new variation is created, check if the parent product has the
	 * pos-hidden term and apply it to the variation if so.
	 *
	 * @since 10.5.0
	 *
	 * @param int                        $variation_id The variation ID.
	 * @param \WC_Product_Variation|null $variation    The variation object.
	 * @return void
	 */
	public function inherit_parent_pos_visibility( $variation_id, $variation ): void {
		if ( ! $variation instanceof \WC_Product_Variation ) {
			return;
		}

		$parent_id = $variation->get_parent_id();
		if ( has_term( 'pos-hidden', 'pos_product_visibility', $parent_id ) ) {
			wp_set_object_terms( $variation_id, 'pos-hidden', 'pos_product_visibility' );
		}
	}
}
