<?php

namespace Bright_Deposits_For_WooCommerce\Pages;

use Bright_Deposits_For_WooCommerce\Core\ContainerManager;

/**
 * @package Bright_Deposits_For_WooCommerce\Pages
 * @since 1.0.0
 * @author Bright Plugins
 * Description: This class is responsible for handling the cart page functionalities for deposits in WooCommerce.
 */
class Cart {
	
	/**
	 * Singleton instance of the class.
	 */
	private static $instance = null;

	protected $helper, $exclusion_manager;
	
	public function __construct() {

		$this->helper = ContainerManager::get('helper');
		$this->exclusion_manager = ContainerManager::get('exclusion_manager');

		add_action( 'woocommerce_cart_totals_after_order_total', [$this, 'depositTable'] );
		add_filter( 'woocommerce_cart_item_name', [$this, 'displayCartItemDepositData'], 10, 3 );
		add_filter( 'woocommerce_add_cart_item_data', [$this, 'cartItemData'], 10, 3 );
		add_action( 'woocommerce_after_calculate_totals', array( $this, 'setCartSessionData' ), 999 );
		add_filter( 'woocommerce_cart_totals_order_total_html', [$this, 'cartTotalHtml'], 10, 1 );
		add_filter( 'woocommerce_cart_item_subtotal', [$this, 'customCartItemSubtotal'], 10, 3 );
		add_filter( 'woocommerce_cart_subtotal', [$this, 'customCartTotalsSubtotal'], 10, 3 );

		/**
		 * Custom action hook for extending cart behavior in this plugin.
		 *
		 * @since 1.0.0
		 * @param self $cart Cart page handler instance.
		 */
		do_action( 'bdfwbp_wc_deposit_cart', $this );

		// Back-compat: keep the original (unprefixed) hook as deprecated.
		$deprecated_hook = 'wc_deposit_cart';
		do_action_deprecated( $deprecated_hook, array( $this ), BDFWBP_VERSION, 'bdfwbp_wc_deposit_cart' );
	}

	/**
	 * Get the singleton instance of the class.
	 * @since 1.0.0
	 * @return Cart
	 */
	public static function instance() {
		if ( is_null( self::$instance ) ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	/**
	 * Prevents cloning of the instance.
	 * @since 1.0.0
	 * @return void
	 */
	private function __clone() {
		// Cloning is forbidden.
	}

	/**
	 * Prevents unserializing of the instance.
	 * @since 1.0.0
	 * @return void
	 */
	public function __wakeup() {
		// Unserializing instances of this class is forbidden.
	}

	/**
	 * Add deposit data to the cart item.
	 * @since 1.0.0
	 * @param array $cart_item_data The cart item data.
	 * @param int   $product_id The product ID.
	 * @param int   $variation_id The variation ID, if applicable.
	 * @return array The modified cart item data with deposit information.
	 */
	public function cartItemData( $cart_item_data, $product_id, $variation_id ) {

		/**
		 * Nonce verification for add to cart button
		 * Here we use the custom nonce and action for add to cart button. Not exist a standard nonce and action for add to cart button.
		 * For other cases, you should use the standard nonce "_wpnonce".
		 */
		if( isset( $_POST['bdfwbp_add_to_cart_button_nonce'] ) ){
			$nonce = sanitize_text_field( wp_unslash( $_POST['bdfwbp_add_to_cart_button_nonce'] ) );
			$action = 'bdfwbp_add_to_cart_button';
			
			if ( !wp_verify_nonce( $nonce, $action ) ) {
				wp_die( esc_html__( 'Security check failed. Please try again.', 'bright-deposits-for-woocommerce' ) );
			}
		}
		/**
		 * End of nonce verification for add to cart button
		 */

		$deposit_mode = ( isset( $_POST['deposit-mode'] ) ) ? sanitize_text_field( wp_unslash( $_POST['deposit-mode'] ) ) : '';
		
		if ( !empty( $deposit_mode ) && $deposit_mode === 'check_full' ) {
			return $cart_item_data;
		}

		$vProductId = $variation_id ? $variation_id : $product_id;

		if ( $this->exclusion_manager->is_product_excluded( $vProductId ) ) {
			return $cart_item_data;
		}
		$product = wc_get_product( $vProductId );

		$is_deposit_enabled_globally = $this->helper->getOptionValue( 'global_deposits_mode' ) == 1;
		$is_deposit_enabled_for_product = get_post_meta( $vProductId, '_bdfwbp_enable_deposit', true ) === 'yes';

		// If deposits are not enabled in any way, do nothing.
		if ( !$is_deposit_enabled_globally && !$is_deposit_enabled_for_product ) {
			return $cart_item_data;
		}

		$deposit_type = 'fixed_amount';
		$deposit_value = 0;

		// Priority: Product-specific settings > Global settings
		if ( $is_deposit_enabled_for_product ) {
			$deposit_type = get_post_meta( $vProductId, '_bdfwbp_deposits_type', true );
			$deposit_value = get_post_meta( $vProductId, '_bdfwbp_deposits_value', true );
		} elseif ( $is_deposit_enabled_globally ) {
			$deposit_type = $this->helper->getOptionValue( 'global_deposit_type' );
			$deposit_value = ( $deposit_type === 'percentage' )
				? $this->helper->getOptionValue( 'global_deposit_percentage' )
				: $this->helper->getOptionValue( 'global_deposit_fixed_amount' );
		}

		$price = (float) $product->get_price();
		$deposit_amount = 0;

		if ( $deposit_type === 'percentage' ) {
			$deposit_amount = ( (float)$deposit_value / 100 ) * $price;
		} else {
			$deposit_amount = (float)$deposit_value;
		}

		/**
		 * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to modify the cart item deposit amount.
		 * @since 1.0.0
		 * @param float       $deposit_amount The deposit amount.
		 * @param \WC_Product $product The product object.
		 * @return float      The modified deposit amount.
		 */
		$cart_item_data['_deposit'] = apply_filters( 'bdfwbp_cart_item_deposit_amount', $deposit_amount, $product );

		/**
		 * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to modify the cart item due payment amount.
		 * @since 1.0.0
		 * @param float       $due_payment The due payment amount.
		 * @param \WC_Product $product The product object.
		 * @return float      The modified due payment amount.
		 */
		$cart_item_data['_due_payment'] = apply_filters( 'bdfwbp_cart_item_due_payment', $price - $deposit_amount, $product );


		$cart_item_data['_deposit_mode'] = 'check_deposit';

		/**
		 * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to modify the cart item data.
		 * @since 1.0.0
		 * @param array  $cart_item_data The cart item data.
		 * @param int    $product_id The product ID.
		 * @param int    $variation_id The variation ID, if applicable.
		 * @return array The modified cart item data.
		 */
		return apply_filters( 'bdfwbp_cart_item_data', $cart_item_data, $product_id, $variation_id );
	}

	/**
	 * Modify the cart total HTML to include deposit information.
	 * @since 1.0.0
	 * @param string $value The original cart total HTML.
	 * @return string The modified cart total HTML with deposit information.
	 */
	public function cartTotalHtml( $value ) {
		if ( !$this->helper->cartHaveDepositItem() ) {
			return $value; // return because cart not have any deposit item
		}

		$deposit_amount = wc_price( WC()->session->get( 'bdfwbp_cart_deposit_amount' ) );

		$htmlValue = '<strong>' . $deposit_amount . '</strong>';

		// If prices are tax inclusive, show taxes here.
		if ( wc_tax_enabled() && WC()->cart->display_prices_including_tax() ) {
			$tax_string_array = array();
			$cart_tax_totals  = WC()->cart->get_tax_totals();

			if ( get_option( 'woocommerce_tax_total_display' ) === 'itemized' ) {
				foreach ( $cart_tax_totals as $code => $tax ) {
					$tax_string_array[] = sprintf( '%s %s', $tax->formatted_amount, $tax->label );
				}
			} elseif ( !empty( $cart_tax_totals ) ) {
				$tax_string_array[] = sprintf( '%s %s', wc_price( WC()->cart->get_taxes_total( true, true ) ), WC()->countries->tax_or_vat() );
			}

			if ( !empty( $tax_string_array ) ) {
				$taxable_address = WC()->customer->get_taxable_address();
				if ( WC()->customer->is_customer_outside_base() && !WC()->customer->has_calculated_shipping() ) {
					$country = WC()->countries->estimated_for_prefix( $taxable_address[0] ) . WC()->countries->countries[$taxable_address[0]];
					/* translators: 1: tax amount 2: country name */
					$tax_text = wp_kses_post( sprintf( __( '(includes %1$s estimated for %2$s)', 'bright-deposits-for-woocommerce' ), implode( ', ', $tax_string_array ), $country ) );
				} else {
					/* translators: %s: tax amount */
					$tax_text = wp_kses_post( sprintf( __( '(includes %s)', 'bright-deposits-for-woocommerce' ), implode( ', ', $tax_string_array ) ) );
				}

				$htmlValue .= '<small class="includes_tax">' . $tax_text . '</small>';
			}
		}

		/**
		 * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to modify the cart total HTML.
		 * @since 1.0.0
		 * @param string    $htmlValue The cart total HTML.
		 * @param \Cart    $this The cart object.
		 * @return string The modified cart total HTML.
		 */
		return apply_filters( 'bdfwbp_cart_total_html', $htmlValue, $this );
	}

	/**
	 * Display the deposit data in the cart item name.
	 * @since 1.0.0
	 * @param string $name The cart item name.
	 * @param array  $cart_item The cart item data.
	 * @param string $cart_item_key The cart item key.
	 * @return string The modified cart item name with deposit data.
	 */
	public function displayCartItemDepositData( $name, $cart_item, $cart_item_key ) {
		if ( isset( $cart_item['_deposit'] ) && is_cart() && isset( $cart_item['_deposit_mode'] ) && $cart_item['_deposit_mode'] == 'check_deposit' ) {
			$line_deposit_total = $cart_item['_deposit'] * $cart_item['quantity'];
			$line_due_total = $cart_item['_due_payment'] * $cart_item['quantity'];

			$deposit_data_html = sprintf(
				'<p style="font-size:13px; font-weight:bold;">' . $this->helper->getOptionValue( 'bdfw_deposit_label' ) . ': %s <br> ' . $this->helper->getOptionValue( 'bdfw_due_payment_label' ) . ': %s</p>',
				wc_price( $line_deposit_total ),
				wc_price( $line_due_total )
			);

			/**
			 * BDFWBP_CUSTOM_FILTER_HOOK: Allows developers to modify the cart item deposit data HTML.
			 * @since 1.0.0
			 * @param string    $deposit_data_html The cart item deposit data HTML.
			 * @param array     $cart_item The cart item data.
			 * @param string    $cart_item_key The cart item key.
			 * @return string The modified cart item deposit data HTML.
			 */
			$name .= apply_filters( 'bdfwbp_cart_item_deposit_data_html', $deposit_data_html, $cart_item, $cart_item_key );

			return $name;
		}

		return $name;
	}
	
	/**
	 * Set the cart session data for deposits.
	 * @since 1.0.0
	 * @param \WC_Cart $cart The WooCommerce cart object.
	 * @return void
	 */
	public function setCartSessionData( $cart ): void {
		// If cart not have any deposit item, return
		if ( !$this->helper->cartHaveDepositItem() ) {
			return; // return because cart not have any deposit item
		}

		$initial_payment_total = 0;
		$future_payment_total = 0;
		
		foreach ( $cart->get_cart() as $cart_item ) {
			if ( isset( $cart_item['_deposit_mode'] ) && $cart_item['_deposit_mode'] === 'check_deposit' ) {
				$initial_payment_total += $cart_item['_deposit'] * $cart_item['quantity'];
				$future_payment_total += $cart_item['_due_payment'] * $cart_item['quantity'];
			} else {
				$initial_payment_total += $cart_item['data']->get_price() * $cart_item['quantity'];
			}
		}

		// Add Taxes, Shipping, and Fees to the initial payment total
		if ( wc_tax_enabled() && !wc_prices_include_tax() ) {
			$total_tax = $cart->get_total_tax();
			$initial_payment_total += $total_tax;
		}

		if ( $cart->needs_shipping() ) {
			$shipping_total = $cart->get_shipping_total();
			$initial_payment_total += $shipping_total;
		}

		$fee_total = $cart->get_fee_total();
		if ( $fee_total > 0 ) {
			$initial_payment_total += $fee_total;
		}

		WC()->session->set( 'bdfwbp_default_cart_total', $cart->total );
		WC()->session->set( 'bdfwbp_cart_deposit_amount', $initial_payment_total );
		WC()->session->set( 'bdfwbp_cart_due_amount', $future_payment_total );

		$cart->total = WC()->session->get( 'bdfwbp_cart_deposit_amount' );
	}

	/**
	 * Display the deposit table in the cart totals section.
	 * @since 1.0.0
	 * @return void
	 */
	public function depositTable(): void {
		/**
		 * BDFWBP_CUSTOM_ACTION_HOOK: Allows developers to add content before display deposit table.
		 * @since 1.0.0
		 * @return void
		 */
		do_action( 'bdfwbp_before_deposit_table' );

		$this->helper->maybeDisplayToPayHtml();

		/**
		 * BDFWBP_CUSTOM_ACTION_HOOK: Allows developers to add content after display deposit table.
		 * @since 1.0.0
		 * @return void
		 */
		do_action( 'bdfwbp_after_deposit_table' );
	}

	/**
	 * Custom cart item subtotal.
	 * @since 1.0.0
	 * @param string $subtotal The original subtotal.
	 * @param array  $cart_item The cart item data.
	 * @return string The modified subtotal.
	 */
	public function customCartItemSubtotal( $subtotal, $cart_item ) {
		if (
			isset( $cart_item['_deposit'] )
			&& isset( $cart_item['_deposit_mode'] )
			&& $cart_item['_deposit_mode'] === 'check_deposit'
			&& is_cart()
		) {
			$deposit_amount = $cart_item['_deposit'] * $cart_item['quantity'];
        	$product_total  = $cart_item['data']->get_price() * $cart_item['quantity'];

			$subtotal = '<strong>' . wc_price($deposit_amount) . '</strong>';
			$total = '<small>' .
				sprintf(
					/* translators: 1: product total */
					esc_html__( '(of %1$s)', 'bright-deposits-for-woocommerce' ),
					wc_price($product_total),
				) .
				'</small>';

			$custom_subtotal = $subtotal . ' ' . $total;

			return $custom_subtotal;
		}
		return $subtotal;
	}

	/**
	 * Custom cart totals subtotal.
	 * @since 1.0.0
	 * @param string $cart_subtotal The original cart subtotal.
	 * @param bool   $compound The compound flag.
	 * @param \WC_Cart $cart The WooCommerce cart object.
	 * @return string The modified cart subtotal.
	 */
	public function customCartTotalsSubtotal( $cart_subtotal, $compound, $cart ) {
		if ( !$this->helper->cartHaveDepositItem() ) {
			return $cart_subtotal;
		}

		$deposit_amount_total = 0;
		$product_total = 0;

		foreach ( $cart->get_cart() as $cart_item ) {
			if (
				isset( $cart_item['_deposit'] )
				&& isset( $cart_item['_deposit_mode'] )
				&& $cart_item['_deposit_mode'] === 'check_deposit'
			) {
				$deposit_amount_total += $cart_item['_deposit'] * $cart_item['quantity'];
				$product_total        += $cart_item['data']->get_price() * $cart_item['quantity'];
			}
			else{
				$deposit_amount_total += $cart_item['data']->get_price() * $cart_item['quantity'];
				$product_total        += $cart_item['data']->get_price() * $cart_item['quantity'];
			}
		}

		$subtotal = '<strong>' . wc_price($deposit_amount_total) . '</strong>';

		$total = '<small>' .
			sprintf(
				/* translators: 1: product total */
				esc_html__( '(of %1$s)', 'bright-deposits-for-woocommerce' ),
				wc_price($product_total),
			) .
			'</small>';

		$custom_subtotal = $subtotal . ' ' . $total;

		return $custom_subtotal;
	}
}
