<?php // phpcs:ignore WordPress.Files.FileName.NotHyphenatedLowercase, WordPress.Files.FileName.InvalidClassFileName
/**
 * Wholesale pricing Native UI hook handler.
 *
 * @package Autoship\Modules\WholesalePricing\Services
 * @since   2.13.0
 */

namespace Autoship\Modules\WholesalePricing\Services;

use Autoship\Modules\WholesalePricing\Compatibility\LegacyWholesalePricingAdapter;

/**
 * Handles scheduled order (Native UI) hook callbacks for wholesale pricing.
 *
 * Covers product dropdown price ranges, quantity input overrides, and
 * add/update item wholesale price adjustments.
 *
 * @package Autoship\Modules\WholesalePricing\Services
 * @since   2.13.0
 */
class WholesaleNativeUIHandler {

	/**
	 * The pricing service.
	 *
	 * @var WholesalePricingServiceInterface
	 */
	private WholesalePricingServiceInterface $pricing;

	/**
	 * The legacy adapter for validate calls.
	 *
	 * @var LegacyWholesalePricingAdapter
	 */
	private LegacyWholesalePricingAdapter $legacy_adapter;

	/**
	 * Constructor.
	 *
	 * @param WholesalePricingServiceInterface $pricing        The pricing service.
	 * @param LegacyWholesalePricingAdapter    $legacy_adapter The legacy adapter.
	 */
	public function __construct(
		WholesalePricingServiceInterface $pricing,
		LegacyWholesalePricingAdapter $legacy_adapter
	) {
		$this->pricing        = $pricing;
		$this->legacy_adapter = $legacy_adapter;
	}

	/**
	 * Return title with wholesale price range for a product dropdown.
	 *
	 * Hooked to autoship_scheduled_order_form_item_add_display_name.
	 *
	 * @param string $dropdown      The current title and price string.
	 * @param string $title         The current product title.
	 * @param float  $originalprice The current regular price from QPilot.
	 * @param float  $saleprice     The sale price from QPilot.
	 * @param array  $product       The product data from QPilot.
	 *
	 * @return string The filtered product select name for the dropdown.
	 */
	public function product_dropdown_get_price_range( $dropdown, $title, $originalprice, $saleprice, $product ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
		if ( ! class_exists( 'WWP_Wholesale_Roles' ) ) {
			return $dropdown;
		}

		$uses_wc_data = autoship_filter_schedulable_products_use_wc_data();
		$product      = $uses_wc_data ? $product : wc_get_product( $product['id'] );

		$new_item = array(
			'price'     => $originalprice,
			'salePrice' => null,
			'quantity'  => 0,
		);

		$prices = $this->filter_add_schedule_items_wholesale_price( $new_item, '', 1, $product->get_id(), $product->get_id() );

		$new_dropdown = $dropdown;
		if ( isset( $prices['salePrice'] ) && ! empty( $prices['salePrice'] ) ) {
			$new_dropdown = sprintf( $dropdown . ' %s %s', trim( apply_filters( 'wwp_filter_wholesale_price_title_text', __( 'Wholesale Price:', 'woocommerce-wholesale-prices' ) ) ), autoship_get_formatted_price( $prices['salePrice'] ) );
		}

		return apply_filters( 'autoship_product_dropdown_get_price_range', $new_dropdown, $dropdown, $new_item, $prices, $product->get_id() );
	}

	/**
	 * Adjusts the HTML input for wholesale items to allow for current value.
	 *
	 * Hooked to autoship_scheduled_order_form_item_quantity_field.
	 *
	 * @param string $product_quantity The input HTML string.
	 * @param array  $item            The current scheduled order item.
	 * @param array  $scheduled_item  The raw scheduled order item from QPilot.
	 *
	 * @return string The filtered HTML string.
	 */
	public function enable_schedule_items_wholesale_price_input( $product_quantity, $item, $scheduled_item ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
		if ( ( $item['is_sold_individually'] ) || ( 'outofstock' === $item['stock_status'] ) ) {
			return $product_quantity;
		}

		$dom = new \DOMDocument();
		$dom->loadHTML( $product_quantity );

		$xpath = new \DOMXPath( $dom );
		$tags  = $xpath->query( '//input[@title="Qty"]' );

		if ( $tags->length <= 0 ) {
			return $product_quantity;
		}

		$value = trim( $tags[0]->getAttribute( 'value' ) );

		if ( $value !== $item['qty'] ) {
			$product_quantity = str_replace( 'value="' . $value . '"', 'value="' . $item['qty'] . '"', $product_quantity );
		}

		return $product_quantity;
	}

	/**
	 * Adjust the price display for newly added wholesale products in the Native UI.
	 *
	 * Hooked to autoship_scheduled_order_form_item_add_display_name (price display).
	 *
	 * @param string $formatted_amount The current formatted price string.
	 * @param array  $item             The current item data array.
	 * @param array  $product          The product data from QPilot.
	 *
	 * @return string The new formatted amount.
	 */
	public function added_product_html_get_price( $formatted_amount, $item, $product ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
		$new_item = array(
			'price'     => $item['price'],
			'salePrice' => null,
			'quantity'  => $item['min_input'],
		);

		$prices = $this->add_schedule_items_wholesale_price( $new_item, '', 1, $item['wc_product_id'], $item['wc_product_id'] );

		if ( isset( $prices['salePrice'] ) && ! empty( $prices['salePrice'] ) ) {
			return autoship_get_formatted_price( $prices['salePrice'] );
		}

		return $formatted_amount;
	}

	/**
	 * Adjusts the price for new order items added in the Autoship Scheduled Order UI.
	 *
	 * Hooked to autoship_create_scheduled_order_item_data.
	 *
	 * @param array  $new_item       The new scheduled order item data.
	 * @param string $frequency_type The current frequency type.
	 * @param int    $frequency      The current frequency.
	 * @param int    $product_id     The current autoship product ID.
	 * @param int    $external_id    The current WC product ID.
	 *
	 * @return array The items after adjustment.
	 */
	public function add_schedule_items_wholesale_price( $new_item, $frequency_type, $frequency, $product_id, $external_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
		if ( $new_item['quantity'] <= 0 ) {
			return $new_item;
		}

		$product        = wc_get_product( $external_id );
		$adjusted_price = $this->pricing->adjust_price( (int) $external_id );

		if ( ! $this->is_non_zero_empty( $adjusted_price ) && $adjusted_price !== $new_item['price'] ) {
			$user_wholesale_role = $this->pricing->get_user_role();
			$qty                 = (int) $new_item['quantity'];
			$apply               = $this->legacy_adapter->autoship_validate_wholesale_price( true, round( $adjusted_price * $qty, 2 ), $user_wholesale_role, $qty, $external_id );

			if ( true === $apply ) {
				$new_item['salePrice'] = $adjusted_price;
			} else {
				wc_add_notice( $apply['message'], $apply['type'] );
			}
		}

		return $new_item;
	}

	/**
	 * Adjusts the price for add item dropdown in the Autoship Scheduled Order UI.
	 *
	 * Display-only pricing — skips validation and notice generation.
	 *
	 * @param array  $new_item       The new scheduled order item data.
	 * @param string $frequency_type The current frequency type.
	 * @param int    $frequency      The current frequency.
	 * @param int    $product_id     The current autoship product ID.
	 * @param int    $external_id    The current WC product ID.
	 *
	 * @return array The items after adjustment.
	 */
	public function filter_add_schedule_items_wholesale_price( $new_item, $frequency_type, $frequency, $product_id, $external_id ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundInExtendedClassBeforeLastUsed
		$adjusted_price = $this->pricing->adjust_price( (int) $external_id );

		if ( ! $this->is_non_zero_empty( $adjusted_price ) && $adjusted_price !== $new_item['price'] ) {
			$new_item['salePrice'] = $adjusted_price;
		}

		return $new_item;
	}

	/**
	 * Adjusts prices for qty updates in the Autoship Scheduled Order UI.
	 *
	 * Hooked to autoship_update_schedule_items_changes.
	 *
	 * @param array  $updated_items  The current scheduled order items being updated.
	 * @param array  $original_items The original scheduled order items.
	 * @param int    $order_id       The QPilot order ID.
	 * @param string $action         The action being performed.
	 * @param array  $data           The scheduled order data.
	 *
	 * @return array The updated items after adjustment.
	 */
	public function update_schedule_items_wholesale_price( $updated_items, $original_items, $order_id, $action, $data ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed
		$user_wholesale_role = $this->pricing->get_user_role();

		if ( empty( $user_wholesale_role ) ) {
			return $updated_items;
		}

		$autoship = array();
		foreach ( $updated_items as $key => $updated_item ) {
			$autoship[ $key ]['price']     = $updated_item['price'];
			$autoship[ $key ]['saleprice'] = $updated_item['product']['salePrice'];
			$autoship[ $key ]['type']      = $updated_item['product']['Type'];
			$autoship[ $key ]['qty']       = $updated_item['quantity'];
			$autoship[ $key ]['id']        = $updated_item['product']['id'];
			$autoship[ $key ]['rule_id']   = 'simple' === $autoship[ $key ]['type'] ? $updated_item['product']['id'] : wp_get_post_parent_id( $updated_item['product']['id'] );
		}

		foreach ( $autoship as $key => $item ) {
			$autoship[ $key ]['adjusted_price'] = $this->pricing->adjust_price( (int) $autoship[ $key ]['id'] );

			if ( ! $this->is_non_zero_empty( $autoship[ $key ]['adjusted_price'] ) && $autoship[ $key ]['adjusted_price'] !== $autoship[ $key ]['price'] ) {
				$apply = $this->legacy_adapter->autoship_validate_wholesale_price( true, round( $autoship[ $key ]['adjusted_price'] * $item['qty'], 2 ), $user_wholesale_role, $item['qty'], $autoship[ $key ]['id'] );

				if ( true === $apply ) {
					$updated_items[ $key ]['salePrice'] = $autoship[ $key ]['adjusted_price'];
				} else {
					$updated_items[ $key ]['salePrice'] = apply_filters( 'autoship_update_schedule_items_wholesale_price', null, $autoship[ $key ], $updated_items[ $key ], $user_wholesale_role );
					wc_add_notice( $apply['message'], $apply['type'] );
					continue;
				}
			}
		}

		return $updated_items;
	}

	/**
	 * Checks for empty value (checks empty, not 0 strings and NULL).
	 *
	 * @param mixed $val The value to check.
	 *
	 * @return bool True if empty or not set, else false.
	 */
	private function is_non_zero_empty( $val ): bool {
		return ! isset( $val ) || ( empty( $val ) && 0 !== $val );
	}
}
