<?php

/**
 * Compatibility layer for third-party "Ajax add to cart" plugins that submit
 * form.cart straight to WooCommerce's native wc-ajax=add_to_cart endpoint,
 * bypassing the widget's own submit handler and dedicated AJAX endpoint.
 *
 * @link       https://nudgesells.com
 * @since      1.0.0
 *
 * @package    NudgeSells
 * @subpackage NudgeSells/includes
 */

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

/**
 * NudgeSells_Native_Add_To_Cart
 *
 * Reads a hidden selection field kept in sync by nudgesells-public.js and
 * adds the matching add-ons/upgrade via WooCommerce's own woocommerce_add_to_cart
 * action, so the selection survives regardless of which plugin submits the form.
 *
 * @since      1.0.0
 * @package    NudgeSells
 * @subpackage NudgeSells/includes
 * @author     NudgeSells <support@nudgesells.com>
 */
class NudgeSells_Native_Add_To_Cart
{

	/**
	 * Reentrancy guard against the addon/upgrade adds below re-triggering this same handler.
	 *
	 * @var bool
	 */
	private static $processing = false;

	/**
	 * Handle.
	 *
	 * Fires after WooCommerce adds a cart line, for every add-to-cart
	 * pathway. Only acts when the request carries our own hidden selection
	 * field for this exact product.
	 *
	 * @param string $cart_item_key
	 * @param int    $product_id
	 * @param int    $quantity
	 * @param int    $variation_id
	 * @param array  $variation
	 * @param array  $cart_item_data
	 *
	 * @return void
	 * @since 1.0.0
	 */
	public function handle($cart_item_key, $product_id, $quantity, $variation_id, $variation, $cart_item_data)
	{
		if (self::$processing) {
			return;
		}

		// Already one of ours (either the dedicated wc_ajax_nudgesells_add_to_cart
		// endpoint, or a line this same method just added below) - nothing to do.
		if (! empty($cart_item_data['nudgesells_role'])) {
			return;
		}

		if (empty($_POST['nudgesells_selection'])) {
			return;
		}

		if (empty($_POST['nudgesells_selection_nonce']) || ! wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['nudgesells_selection_nonce'])), 'nudgesells_frontend')) {
			return;
		}

		$selection = json_decode(wp_unslash($_POST['nudgesells_selection']), true);
		if (! is_array($selection)) {
			return;
		}

		$host_id = absint($selection['host_id'] ?? 0);
		if (! $host_id || $host_id !== (int) $product_id) {
			// This add-to-cart event isn't for the widget's own host product
			// (e.g. an unrelated related-products button on the same page).
			return;
		}

		$addons_raw = is_array($selection['addons'] ?? null) ? $selection['addons'] : array();
		$upgrade_id = absint($selection['upgrade_id'] ?? 0);
		$upgrade_variation_id = absint($selection['upgrade_variation_id'] ?? 0);

		if (! $addons_raw && ! $upgrade_id) {
			return;
		}

		$rules = NudgeSells_Rules_Repository::get_rules($host_id, $variation_id);
		if ($rules['offer_id'] && ! NudgeSells_Offer_Repository::meets_min_qty($rules['offer_id'], $quantity)) {
			// Selection no longer qualifies (e.g. the widget hadn't refreshed
			// yet after a quantity change) - skip rather than add an offer
			// that shouldn't apply.
			return;
		}

		$addon_rules_by_id = array();
		foreach ($rules['addons'] as $r) {
			$addon_rules_by_id[$r['product_id']] = $r;
		}

		self::$processing = true;

		try {
			$group_id = 'nsg_' . wp_generate_password(12, false);

			if ($upgrade_id) {
				$this->swap_host_for_upgrade($cart_item_key, $host_id, $quantity, $upgrade_id, $upgrade_variation_id, $rules, $group_id);
			} elseif (isset(WC()->cart->cart_contents[$cart_item_key])) {
				// Tag the host line so NudgeSells_Cart_Pricing recognizes it
				// as the addons' parent, same as the dedicated endpoint.
				WC()->cart->cart_contents[$cart_item_key]['nudgesells_group']   = $group_id;
				WC()->cart->cart_contents[$cart_item_key]['nudgesells_role']    = 'host';
				WC()->cart->cart_contents[$cart_item_key]['nudgesells_host_id'] = $host_id;
			}

			foreach ($addons_raw as $addon) {
				$this->add_addon($addon, $addon_rules_by_id, $host_id, $group_id);
			}

			WC()->cart->calculate_totals();
		} finally {
			self::$processing = false;
		}
	}

	/**
	 * Swap host for upgrade.
	 *
	 * An upgrade replaces the host line rather than adding alongside it.
	 * $cart_item_key is the exact line WooCommerce just created for the
	 * host product, so removing it here is precise, not a guess.
	 *
	 * @param string $cart_item_key
	 * @param int    $host_id
	 * @param int    $quantity
	 * @param int    $upgrade_id
	 * @param int    $upgrade_variation_id
	 * @param array  $rules
	 * @param string $group_id
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function swap_host_for_upgrade($cart_item_key, $host_id, $quantity, $upgrade_id, $upgrade_variation_id, array $rules, $group_id)
	{
		$upgrade_rule = null;
		foreach ($rules['upgrades'] as $r) {
			if ((int) $r['product_id'] === $upgrade_id) {
				$upgrade_rule = $r;
				break;
			}
		}
		if (! $upgrade_rule) {
			return;
		}

		$upgrade_product = wc_get_product($upgrade_variation_id ? $upgrade_variation_id : $upgrade_id);
		if (! $upgrade_product || ! $upgrade_product->is_purchasable() || ! $upgrade_product->is_in_stock()) {
			return;
		}

		$upgrade_variation_attributes = array();
		if ($upgrade_variation_id) {
			$variation_obj = wc_get_product($upgrade_variation_id);
			if ($variation_obj instanceof WC_Product_Variation && (int) $variation_obj->get_parent_id() === $upgrade_id) {
				foreach ($variation_obj->get_attributes() as $attr_key => $attr_value) {
					$upgrade_variation_attributes['attribute_' . $attr_key] = $attr_value;
				}
			} else {
				$upgrade_variation_id = 0;
			}
		}

		NudgeSells_Cart_Pricing::$suppress_cascade = true;
		WC()->cart->remove_cart_item($cart_item_key);
		NudgeSells_Cart_Pricing::$suppress_cascade = false;

		WC()->cart->add_to_cart($upgrade_id, $quantity, $upgrade_variation_id, $upgrade_variation_attributes, array(
			'nudgesells_group'              => $group_id,
			'nudgesells_role'               => 'upgrade',
			'nudgesells_host_id'            => $host_id,
			'nudgesells_upgrade_product_id' => $upgrade_id,
			'nudgesells_upgrade_rule'       => $upgrade_rule,
		));
	}

	/**
	 * Add addon.
	 *
	 * @param mixed  $addon
	 * @param array  $addon_rules_by_id
	 * @param int    $host_id
	 * @param string $group_id
	 *
	 * @return void
	 * @since 1.0.0
	 */
	private function add_addon($addon, array $addon_rules_by_id, $host_id, $group_id)
	{
		$product_id   = absint(is_array($addon) ? ($addon['product_id'] ?? 0) : 0);
		$variation_id = absint(is_array($addon) ? ($addon['variation_id'] ?? 0) : 0);
		$qty          = max(1, absint(is_array($addon) ? ($addon['qty'] ?? 1) : 1));

		if (! isset($addon_rules_by_id[$product_id])) {
			return;
		}

		$product = wc_get_product($variation_id ? $variation_id : $product_id);
		if (! $product || ! $product->is_purchasable() || ! $product->is_in_stock()) {
			return;
		}

		$variation_attributes = array();
		if ($variation_id) {
			$variation_obj = wc_get_product($variation_id);
			if ($variation_obj instanceof WC_Product_Variation && (int) $variation_obj->get_parent_id() === $product_id) {
				foreach ($variation_obj->get_attributes() as $attr_key => $attr_value) {
					$variation_attributes['attribute_' . $attr_key] = $attr_value;
				}
			} else {
				$variation_id = 0;
			}
		}

		WC()->cart->add_to_cart($product_id, $qty, $variation_id, $variation_attributes, array(
			'nudgesells_group'             => $group_id,
			'nudgesells_role'              => 'addon',
			'nudgesells_host_id'           => $host_id,
			'nudgesells_addon_product_id'  => $product_id,
			'nudgesells_addon_rule'        => $addon_rules_by_id[$product_id],
		));
	}
}
