<?php
/**
 * Provides shared PPOM helpers for metadata lookup and cart formatting.
 *
 * @package PPOM
 * @subpackage Helpers
 *
 * @see self::make_meta_data()
 * @see self::generate_cart_meta()
 * @see self::get_field_meta_by_dataname()
 */

namespace PPOM\Support;

use PPOM_Meta;
use PPOM\Arrays\Settings;
use PPOM\Files\Handler;
use PPOM\Hooks\Callbacks;
use PPOM\Pricing\Engine;

/**
 * @internal
 */
final class Helpers {

	// Keep this for compatitibilty
	public static function direct_access_not_allowed() {
	}


	public static function pa( $arr ) {

		echo '<pre>';
		print_r( $arr );
		echo '</pre>';
	}

	/**
	 * WooCommerce notice helper (legacy WC 2.1+ / pre-2.1 paths).
	 *
	 * @param string $string Message.
	 * @param string $type   Notice type.
	 *
	 * @return void
	 */
	public static function wc_add_notice( $string, $type = 'error' ) {

		global $woocommerce;
		if ( version_compare( $woocommerce->version, '2.1', '>=' ) ) {
			wc_add_notice( $string, $type );
		} else {
			$woocommerce->add_error( $string );
		}
	}

	/**
	 * WPML / Polylang string translation for PPOM-authored labels.
	 *
	 * @param mixed  $field_value String or array (arrays pass through).
	 * @param string $domain      Text domain / WPML context.
	 *
	 * @return mixed
	 */
	public static function wpml_translate( $field_value, $domain ) {

		if ( is_array( $field_value ) ) {
			return $field_value;
		}

		$field_name  = $domain . ' - ' . sanitize_key( $field_value );
		$field_value = stripslashes( $field_value );

		if ( has_filter( 'wpml_translate_single_string' ) ) {
			$field_value = apply_filters( 'wpml_translate_single_string', $field_value, $domain, $field_name );
		}

		if ( function_exists( 'pll__' ) ) {
			$field_value = pll__( $field_value );
		}

		return $field_value;
	}

	// Get field column
	public static function get_field_colum( $meta ) {

		$field_column = isset( $meta['width'] ) ? $meta['width'] : 12;

		// Check width has old settings
		if ( strpos( $field_column, '%' ) !== false ) {

			$field_column = 12;
		} elseif ( intval( $field_column ) > 12 ) {
			$field_column = 12;
		}

		return apply_filters( 'ppom_field_col', $field_column, $meta );
	}

	public static function translation_options( $option ) {

		if ( ! isset( $option['option'] ) ) {
			return $option;
		}

		$option['option'] = self::wpml_translate( $option['option'], 'PPOM' );

		// if label is set
		if ( isset( $option['label'] ) ) {
			$option['label'] = self::wpml_translate( $option['label'], 'PPOM' );
		}

		return $option;
	}


	/**
	 * returning product id
	 *
	 * @since 7.9
	 */
	public static function get_product_id( $product ) {

		$product_id = '';
		if ( version_compare( WOOCOMMERCE_VERSION, '2.7', '<' ) ) {

			// vesion less then 2.7
			$product_id = isset( $product->id ) ? $product->id : $product->ID;
		} elseif ( is_a( $product, 'WC_Product' ) ) {


			if ( $product->is_type( 'variation' ) ) {
				$product_id = $product->get_parent_id();
			} else {

				$product_id = $product->get_id();
			}
		}


		// WPML Check, if product is translated
		if ( function_exists( 'icl_object_id' ) && apply_filters( 'ppom_use_parent_product_ml', false ) ) {

			$wpml_default_lang = apply_filters( 'wpml_default_language', null );
			$product_id        = apply_filters( 'wpml_object_id', $product_id, 'product', false, $wpml_default_lang );
		}

		return $product_id;
	}

	// Get product price after some filters like currency switcher
	public static function get_product_price( $product, $variation_id = null, $context = '' ) {

		$product_price = 'incl' === get_option( 'woocommerce_tax_display_shop' ) ? wc_get_price_including_tax( $product ) : wc_get_price_excluding_tax( $product );

		// self::pa($product);
		// $product_price = $product->get_price();

		if ( $product->is_type( 'variable' ) && $variation_id ) {
			$variable_product = wc_get_product( $variation_id );
			$product_price    = $variable_product->get_price();
		}

		if ( method_exists( 'WWP_Wholesale_Prices', 'get_product_wholesale_price_on_shop_v3' ) ) {

			$wwp_roles           = \WWP_Wholesale_Roles::getInstance();
			$user_wholesale_role = $wwp_roles->getUserRoles();
			$price_arr           = \WWP_Wholesale_Prices::get_product_wholesale_price_on_shop_v3( \WWP_Helper_Functions::wwp_get_product_id( $product ), $user_wholesale_role );
			// self::pa($price_arr);
			if ( ! empty( $price_arr['wholesale_price'] ) ) {
				$product_price = $price_arr['wholesale_price'];
			}
		}


		if ( has_filter( 'woocs_exchange_value' ) ) {
			global $WOOCS;
			if ( ! $WOOCS->is_multiple_allowed ) {
				$product_price = apply_filters( 'woocs_exchange_value', $product_price );
			}
		}

		return apply_filters( 'ppom_product_price', $product_price, $product );
	}

	// Get product Regular Price after some filters like currency switcher
	public static function get_product_regular_price( $product ) {

		$product_price = $product->get_regular_price();

		// Disabling, PRODUCT->get_price() already manage WOOCS
		/*
		if( has_filter('woocs_exchange_value') ) {
		global $WOOCS;

		if($WOOCS->current_currency != $WOOCS->default_currency ) {
			if($WOOCS->is_multiple_allowed) {
				$product_price = apply_filters('woocs_raw_woocommerce_price', $product_price);
			} else {

				$product_price = apply_filters('woocs_exchange_value', $product_price);
			}
		}
		}*/

		// WholeSale Plugin Price
		// Well, this also need to be confirm, PRODUCT->get_price should include this filter as well.
		if ( has_filter( 'wwp_filter_wholesale_price' ) ) {

			$user_wholesale_role = \WWP_Wholesale_Roles::getUserRoles();
			$quantity            = 1;
			$product_price       = apply_filters( 'wwp_filter_wholesale_price', $product_price, self::get_product_id( $product ), $user_wholesale_role, $quantity );
		}

		return apply_filters( 'ppom_product_regular_price', $product_price, $product );
	}

	/**
	 * Sanitize the input fields.
	 *
	 * @param mixed $field_value Field value to sanitize.
	 * @return mixed|string Sanitized field value.
	 */
	public static function recursive_sanitization( $field_value ) {
		if ( is_string( $field_value ) ) {
			$field_value = sanitize_textarea_field( wp_strip_all_tags( $field_value ) );
		}

		if ( is_array( $field_value ) ) {
			foreach ( $field_value as $key => $val ) {
				$field_value[ $key ] = self::recursive_sanitization( $val );
			}
		}

		return $field_value;
	}

	// Cart and order metadata.

	/**
	 * Formats PPOM cart data into metadata rows.
	 *
	 * Sanitizes saved field values against the resolved field schema before
	 * delegating display formatting to `self::generate_cart_meta()`.
	 *
	 * @param array  $cart_item Cart item data.
	 * @param string $context   Metadata context.
	 *
	 * @return array
	 *
	 * @since 8.2
	 *
	 * @see self::generate_cart_meta()
	 * @see self::get_field_meta_by_dataname()
	 * @see ppom_woocommerce_order_item_meta()
	 */
	public static function make_meta_data( $cart_item, $context = 'cart' ) {

		if ( ! isset( $cart_item['ppom']['fields'] ) ) {
			return $cart_item;
		}

		$ppom_meta_ids = '';
		// removing id field
		if ( ! empty( $cart_item ['ppom'] ['fields']['id'] ) ) {
			$ppom_meta_ids = $cart_item ['ppom'] ['fields']['id'];
			unset( $cart_item ['ppom'] ['fields']['id'] );
		}

		// check if product type is variable
		$variation_id = null;
		if ( isset( $cart_item['variation_id'] ) ) {
			$variation_id = $cart_item['variation_id'];
		}

		$product_id                  = self::get_product_id( $cart_item['data'] );
		$cart_item['ppom']['fields'] = self::filter_posted_ppom_fields_by_active_variation( $cart_item['ppom']['fields'], $product_id, $variation_id );

		// Fields sanitization.
		$ppom = new PPOM_Meta( $product_id );
		if ( is_array( $ppom->fields ) ) {
			foreach ( $ppom->fields as $field ) {
				$data_name = sanitize_key( $field['data_name'] );
				if ( isset( $cart_item['ppom']['fields'][ $data_name ] ) ) {
					$cart_item['ppom']['fields'][ $data_name ] = self::recursive_sanitization( $cart_item['ppom']['fields'][ $data_name ] );
				}
			}
		}

		$ppom_meta        = array();
		$ppom_cart_fields = $cart_item ['ppom'];
		$ppom_meta_ids    = apply_filters( 'ppom_meta_ids_in_cart', null, $cart_item );
		// self::pa($cart_item);
		$ppom_meta = self::generate_cart_meta( $ppom_cart_fields, $product_id, $ppom_meta_ids, $context );

		return apply_filters( 'ppom_meta_data', $ppom_meta, $cart_item, $context );
	}

	/**
	 * Builds readable PPOM metadata from cart field values.
	 *
	 * @param array                 $ppom_cart_items Cart PPOM payload.
	 * @param int                   $product_id      Product ID.
	 * @param array|int|string|null $ppom_meta_ids Optional PPOM group IDs.
	 * @param string                $context         Metadata context.
	 * @param int|null              $variation_id    Variation ID.
	 *
	 * @return array
	 *
	 * @see self::make_meta_data()
	 * @see self::get_field_meta_by_dataname()
	 */
	public static function generate_cart_meta( $ppom_cart_items, $product_id, $ppom_meta_ids = null, $context = 'cart', $variation_id = null ) {
		$ppom_meta = array();
		// Return the empty array if the cart is empty.
		if ( ! $ppom_cart_items ) {
			return $ppom_meta;
		}

		$ppom_cart_fields = $ppom_cart_items['fields'];

		foreach ( $ppom_cart_fields as $key => $value ) {

			// if no value
			if ( $value == '' ) {
				continue;
			}

			$conditionally_hidden = isset( $ppom_cart_items['conditionally_hidden'] ) ? $ppom_cart_items['conditionally_hidden'] : '';
			if ( self::is_field_hidden_by_condition( $key, $conditionally_hidden ) ) {
				continue;
			}

			// $cart_item['data'] ->post_type == 'product' ? $cart_item['data']->get_id() : $cart_item['data']->get_parent_id();
			$field_meta = self::get_field_meta_by_dataname( $product_id, $key, $ppom_meta_ids );
			$data_name  = $key;
			// self::pa($value);

			// If field deleted while it's in cart
			if ( empty( $field_meta ) ) {
				continue;
			}

			$field_type  = isset( $field_meta['type'] ) ? $field_meta['type'] : '';
			$field_title = isset( $field_meta['title'] ) ? $field_meta['title'] : '';

			// third party plugin for different fields types
			$field_type = apply_filters( 'ppom_make_meta_data_field_type', $field_type, $field_meta );

			if ( $variation_id ) {
				$product = wc_get_product( $variation_id );
			} else {
				$product = wc_get_product( $product_id );
			}

			$meta_data = array();

			// self::pa($field_type);
			switch ( $field_type ) {
				case 'quantities':
					$total_qty  = 0;
					$qty_values = array( '&nbsp;' );
					// self::pa($value);
					foreach ( $value as $label => $qty ) {
						if ( ! empty( $qty ) && apply_filters( 'ppom_hide_variation_if_qty_zero', true, $value ) ) {
							$qty_values[] = "{$label} = {$qty}";
							// $ppom_meta[$label] = $qty;
							$total_qty += intval( $qty );
						}
					}

					if ( $total_qty > 0 ) {
						// translators: %d: the total quantity.
						$qty_values[] = '<strong>' . sprintf( __( 'Total = %d', 'woocommerce-product-addon' ), $total_qty ) . '</strong>';
						$meta_data    = array(
							'name'  => $field_title,
							'value' => implode( '<br>', $qty_values ),
						);
						// A placeholder key to handle quantity display in item meta data under myaccount.
					}

					$ppom_meta['ppom_has_quantities'] = $total_qty;
					break;

				case 'qtypack':
					$total_qty  = 0;
					$qty_values = array( '&nbsp;' );
					// self::pa($value);
					foreach ( $value as $label => $qty ) {
						if ( ! empty( $qty ) ) {
							$qty_values[] = "{$label} = {$qty}";
							// $ppom_meta[$label] = $qty;
							$total_qty += intval( $qty );
						}
					}

					if ( $total_qty > 0 ) {
						// translators: %d: the total quantity.
						$qty_values[] = '<strong>' . sprintf( __( 'Total = %d', 'woocommerce-product-addon' ), $total_qty ) . '</strong>';
						$meta_data    = array(
							'name'  => $field_title,
							'value' => implode( '<br>', $qty_values ),
						);
						// A placeholder key to handle qunantity display in item meta data under myaccount
					}

					$ppom_meta['ppom_has_quantities'] = $total_qty;
					break;

				// Note: "VM" Variation Matrix Use for only customized clients
				case 'vm':
					$total_qty  = 0;
					$qty_values = array();
					// self::pa($value);
					foreach ( $value as $label => $qty ) {
						if ( ! empty( $qty ) ) {
							$qty_values[] = "{$label} = {$qty}";
							// $ppom_meta[$label] = $qty;
							$total_qty += intval( $qty );
						}
					}

					if ( $total_qty > 0 ) {
						// translators: %d: the total quantity.
						$qty_values[] = '<strong>' . sprintf( __( 'Total = %d', 'woocommerce-product-addon' ), $total_qty ) . '</strong>';
						$meta_data    = array(
							'name'  => $field_title,
							'value' => implode( ',', $qty_values ),
						);
						// A placeholder key to handle qunantity display in item meta data under myaccount
					}

					$ppom_meta['ppom_has_quantities'] = $total_qty;
					break;

				case 'vqmatrix':
					$total_qty = 0;

					$vqmatrix_html = apply_filters( 'ppom_vqmatrix_cart_html', $value, $field_meta, $total_qty );

					foreach ( $value as $label => $qty ) {
						if ( ! empty( $qty ) ) {
							$total_qty += $qty;
						}
					}

					if ( $total_qty > 0 ) {
						$meta_data = array(
							'name'  => $field_title,
							'value' => $vqmatrix_html,
						);
					}

					$ppom_meta['ppom_has_quantities'] = $total_qty;
					break;

				case 'eventcalendar':
					$total_qty = 0;

					// self::pa($value);

					$meta_display = array( '&nbsp;' );

					foreach ( $value as $date => $ticket_meta ) {
						if ( ! empty( $ticket_meta ) ) {

							// Changing date formate
							$date_format = isset( $field_meta['date_formate'] ) ? $field_meta['date_formate'] : 'yyyy-mm-dd';

							$date_format = apply_filters( 'ppom_eventcalendar_formats', $date_format, $field_meta );

							$formatted_date = date( $date_format, strtotime( $date ) );

							$meta_display[] = "{$formatted_date} : ";

							foreach ( $ticket_meta as $ticket_variations => $quantity ) {

								if ( ! empty( $quantity ) ) {
									$meta_display[] = "{$ticket_variations} = {$quantity}";
									$total_qty     += intval( $quantity );
								}
							}
						}
					}

					if ( $total_qty > 0 ) {
						// translators: %d: the total quantity.
						$meta_display[] = '<strong>' . sprintf( __( 'Total = %d', 'woocommerce-product-addon' ), $total_qty ) . '</strong>';
						$meta_data      = array(
							'name'    => $field_title,
							'display' => implode( '<br>', $meta_display ),
							'value'   => $value,
						);
						// A placeholder key to handle qunantity display in item meta data under myaccount
					}

					$ppom_meta['ppom_has_quantities'] = $total_qty;
					break;

				case 'file':
					if ( $context == 'order' ) {
						$uploaded_filenames = array();
						foreach ( $value as $file_id => $file_uploaded ) {
							$uploaded_filenames[] = $file_uploaded['org'];
						}
						$meta_data = array(
							'name'  => $field_title,
							'value' => implode( ',', $uploaded_filenames ),
						);
					} else {
						$file_thumbs_html = '';
						foreach ( $value as $file_id => $file_uploaded ) {
							$file_name         = $file_uploaded['org'];
							$file_thumbs_html .= Handler::create_thumb_for_meta( $file_name, $product_id );
						}
						// $ppom_meta['ppom_has_files'][$key] = $value;
						$meta_data = array(
							'name'  => $field_title,
							'value' => $file_thumbs_html,
						);
						// $ppom_meta[$field_title] = $file_thumbs_html;
					}
					break;


				case 'fancycropper':
					$ppom_html  = '';
					$ppom_html .= '<table class="table table-bordered">';
					foreach ( $value as $popupID => $image_data ) {

						$fomatted_data = json_decode( stripcslashes( $image_data ), true );

						$imageURL = isset( $fomatted_data['imageURL'] ) ? $fomatted_data['imageURL'] : '';
						$imageURL = Handler::get_dir_url() . 'cropped/' . $imageURL;
						$fileName = isset( $fomatted_data['fileName'] ) ? $fomatted_data['fileName'] : '';

						$fileName = substr( $fileName, 0, strrpos( $fileName, '.' ) );

						$ppom_html .= '<tr>';
						$ppom_html .= '<td>';
						$ppom_html .= '<a href="' . esc_url( $imageURL ) . '"><img class="img-thumbnail" style="width:' . esc_attr( self::get_thumbs_size() ) . '" src="' . esc_url( $imageURL ) . '" title="' . esc_attr( $fileName ) . '"></a>';
						$ppom_html .= '</td>';
						$ppom_html .= '<td>' . __( 'Original Image', 'woocommerce-product-addon' ) . '</td>';
						$ppom_html .= '</tr>';

						foreach ( $fomatted_data['cropped'] as $cropped_id => $cropped_meta ) {

							$file_name = isset( $cropped_meta['croppedURL'] ) ? $cropped_meta['croppedURL'] : '';
							$qty       = isset( $cropped_meta['qty'] ) ? $cropped_meta['qty'] : '';
							$label     = ! empty( $cropped_meta['label'] ) ? $cropped_meta['label'] : __( 'Cropped', 'woocommerce-product-addon' );

							$qtylabel    = "{$label} x {$qty}";
							$cropped_url = Handler::get_dir_url() . 'cropped/' . $file_name;

							$ppom_html .= '<tr>';
							$ppom_html .= '<td>';
							$ppom_html .= '<a href="' . esc_url( $cropped_url ) . '" class="lightbox">';
							$ppom_html .= '<img class="img-thumbnail" style="width:' . esc_attr( self::get_thumbs_size() ) . '" src="' . esc_url( $cropped_url ) . '">';
							$ppom_html .= '</a>';
							$ppom_html .= '</td>';
							$ppom_html .= '<td>' . $qtylabel . '</td>';
							$ppom_html .= '</tr>';
						}
					}

					$ppom_html .= '</table>';

					$cropped_html = apply_filters( 'ppom_fancycropper_cart_html', $ppom_html, $value, $field_meta );

					if ( ! empty( $value ) ) {
						$meta_data = array(
							'name'  => $field_title,
							'value' => $cropped_html,
						);
					}

					break;

				case 'cropper':
					// self::pa($value);

					// Checking if ratio found with cropping
					$crop_options = self::convert_options_to_key_val( $field_meta['options'], $field_meta, $product );
					$crop_size    = '';
					if ( isset( $value['ratio'] ) && $value['ratio'] !== '' ) {
						$ratio_found = $value['ratio'];
						// Getting option
						foreach ( $crop_options as $option ) {
							if ( $option['option_id'] === $ratio_found ) {
								$crop_size = $option['label'];
							}
						}
					}

					if ( $context == 'order' ) {
						$uploaded_filenames = array();
						foreach ( $value as $file_id => $file_cropped ) {
							if ( $file_id == 'ratio' ) {
								continue;
							}
							$uploaded_filenames[] = $file_cropped['org'];
						}
						$meta_data = array(
							'name'  => $field_title,
							'value' => implode( ',', $uploaded_filenames ),
						);
					} else {
						$file_thumbs_html = '';
						foreach ( $value as $file_id => $file_cropped ) {

							if ( $file_id == 'ratio' ) {
								continue;
							}
							$file_name         = isset( $file_cropped['org'] ) ? $file_cropped['org'] : '';
							$file_thumbs_html .= Handler::create_thumb_for_meta( $file_name, $product_id, true, $crop_size );

							// Adding ratio to cart
						}
						$meta_data = array(
							'name'  => $field_title,
							'value' => $file_thumbs_html,
						);
					}
					break;

				case 'image':
					if ( $value ) {

						$display = self::generate_html_for_images( $value );

						$meta_data = array(
							'name'    => $field_title,
							'value'   => $value,
							'display' => $display,
						);
					}
					break;

				case 'palettes':
					$selected_color = array();
					$color_options  = $field_meta['options'];
					$options_filter = self::convert_options_to_key_val( $field_meta['options'], $field_meta, $product );
					foreach ( $value as $color ) {
						foreach ( $options_filter as $option_key => $opt ) {

							if ( $color == $option_key ) {
								$display          = ! empty( $opt['label'] ) ? $opt['label'] : $opt['option'];
								$selected_color[] = $display;
								$meta_data        = array(
									'name'    => $field_title,
									'value'   => $value,
									'display' => implode( ',', $selected_color ),
								);
								break;
							}
						}
					}

					break;

				case 'audio':
					if ( $value ) {
						$ppom_file_count = 1;
						foreach ( $value as $id => $audio_meta ) {
							$audio_meta = json_decode( stripslashes( $audio_meta ), true );
							$audio_url  = stripslashes( $audio_meta['link'] );
							$audio_html = '<a href="' . esc_url( $audio_url ) . '" title="' . esc_attr( $audio_meta['title'] ) . '">' . $audio_meta['title'] . '</a>';
							$meta_lable = $field_title . ': ' . $ppom_file_count++;
							// $ppom_meta[$meta_lable] = $audio_html;
							$meta_data = array(
								'name'  => $meta_lable,
								'value' => $audio_html,
							);
						}
					}
					break;

				case 'bulkquantity':
					$bq_value = $value['option'] . ' (' . $value['qty'] . ')';
					// $ppom_meta[$key] = $value['option'].' ('.$value['qty'].')';
					$meta_data = array(
						'name'  => $field_title,
						'value' => $bq_value,
					);
					// A placeholder key to handle qunantity display in item meta data under myaccount
					$ppom_meta['ppom_has_quantities'] = array(
						'name'   => $key,
						'value'  => $value['qty'],
						'hidden' => true,
					);
					break;

				// NOTE: We have DISABLE this due to REST API values
				case 'checkbox':
					$option_posted = $value;

					if ( is_array( $option_posted ) ) {

						$option_posted = stripslashes_deep( $option_posted );
					}

					$option_label_array = array();
					$options_data_array = array();

					$options_filter = self::convert_options_to_key_val( $field_meta['options'], $field_meta, $product );
					// self::pa($options_filter);

					foreach ( $option_posted as $posted_value ) {
						foreach ( $options_filter as $option_key => $option ) {

							$option_value = stripslashes( self::wpml_translate( $option['raw'], 'PPOM' ) );

							if ( stripcslashes( $posted_value ) === $option_value ) {
								$option_label_array[] = $option['label'];
								$options_data_array[] = array(
									'option' => $option['raw'],
									'price'  => $option['price'],
									'id'     => $option['option_id'],
								);
							}
						}
					}

					if ( $context == 'api' ) {
						$meta_data = array(
							'name'    => $field_title,
							'value'   => json_encode( $options_data_array ),
							'display' => implode( ',', $option_label_array ),
						);
					} else {

						$meta_data = array(
							'name'  => $field_title,
							'value' => implode( ', ', $option_label_array ),
						);
					}
					break;

				case 'select':
				case 'radio':
					$posted_value = wp_unslash( $value );

					$option_price = '';
					$option_data  = array();

					$options_filter = self::convert_options_to_key_val( $field_meta['options'], $field_meta, $product );

					foreach ( $options_filter as $option_key => $option ) {

						$option_value = stripslashes( self::wpml_translate( $option['raw'], 'PPOM' ) );

						if ( $posted_value == $option_value ) {
							$option_price  = $option['label'];
							$option_data[] = array(
								'option' => $option['raw'],
								'price'  => $option['price'],
								'id'     => $option['option_id'],
							);
							break;
						}
					}

					if ( $context == 'api' ) {
						$meta_data = array(
							'name'    => $field_title,
							'value'   => json_encode( $option_data ),
							'display' => $option_price,
						);
					} else {
						$meta_data = array(
							'name'  => $field_title,
							'value' => $option_price,
						);
					}
					break;

				case 'multiple_select':
					$option_data  = array();
					$option_price = array();

					$options_filter = self::convert_options_to_key_val( $field_meta['options'], $field_meta, $product );

					foreach ( $value as $opt_index => $selected_opt ) {

						foreach ( $options_filter as $option_key => $option ) {

							$option_raw   = isset( $option['raw'] ) ? $option['raw'] : '';
							$option_value = stripslashes( self::wpml_translate( $option_raw, 'PPOM' ) );

							if ( $option_value === $selected_opt ) {

								$option_price[] = $option['label'];
								$option_data[]  = array(
									'option' => $option['raw'],
									'price'  => $option['price'],
									'id'     => $option['option_id'],
								);
							}
						}
					}

					$option_price = is_array( $option_price ) ? implode( ', ', $option_price ) : $value;

					if ( $context == 'api' ) {
						$meta_data = array(
							'name'    => $field_title,
							'value'   => json_encode( $option_data ),
							'display' => $option_price,
						);
					} else {
						$meta_data = array(
							'name'  => $field_title,
							'value' => $option_price,
						);
					}
					break;

				case 'measure':
					// if units are set for this
					if ( ! empty( $cart_item['ppom']['unit'][ $key ] ) ) {
						$field_title .= ' (' . $cart_item['ppom']['unit'][ $key ] . ')';
					}
					$meta_data = array(
						'name'  => $field_title,
						'value' => $value,
					);

					break;

				case 'section':
					$show_cart = isset( $field_meta['cart_display'] ) && $field_meta['cart_display'] == 'on' ? true : false;
					if ( $show_cart ) {
						$meta_data = array(
							'name'  => $field_title,
							'value' => $value,
						);
					}
					break;

				case 'hidden':
					$show_cart = isset( $field_meta['cart_display'] ) && $field_meta['cart_display'] == 'on' ? false : true;
					$meta_data = array(
						'name'   => $field_title,
						'value'  => $value,
						'hidden' => $show_cart,
					);
					break;

				default:
					$value = is_array( $value ) ? implode( ',', $value ) : $value;
					// $ppom_meta[$field_title] = stripcslashes($value);
					$meta_data = array(
						'name'  => $field_title,
						'value' => stripcslashes( $value ),
					);
					break;
			}

			// Getting option price if field have
			$option_price = self::get_field_option_price( $field_meta, $value );
			if ( $option_price != 0 ) {
				$meta_data['price'] = $option_price;
			}

			$meta_data_field = apply_filters( 'ppom_meta_data_field', $meta_data, $key, $field_meta, $product_id );
			// new filter with cart $value
			$meta_data_field   = apply_filters( 'ppom_fields_cart_meta', $meta_data_field, $key, $field_meta, $product_id, $ppom_cart_fields );
			$ppom_meta[ $key ] = $meta_data_field;

			$ppom_meta[ $key ]['type'] = $field_type;
		}

		return $ppom_meta;
	}

	/**
	 * hiding prices for variable product
	 * only when priced options are used
	 *
	 * @since 8.2
	 **/
	public static function meta_priced_options( $the_meta ) {

		$has_priced_option = false;
		foreach ( $the_meta as $key => $meta ) {

			$options = ( isset( $meta['options'] ) ? $meta['options'] : array() );
			foreach ( $options as $opt ) {

				if ( isset( $opt['price'] ) && $opt['price'] != '' ) {
					$has_priced_option = true;
				}
			}
		}

		return apply_filters( 'ppom_meta_priced_options', $has_priced_option, $the_meta );
	}

	/**
	 * check if browser is IE
	 **/
	public static function if_browser_is_ie() {
		// print_r($_SERVER['HTTP_USER_AGENT']);

		if ( ! ( isset( $_SERVER['HTTP_USER_AGENT'] ) && ( strpos( $_SERVER['HTTP_USER_AGENT'], 'Trident' ) !== false || strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE' ) !== false ) ) ) {
			return false;
		} else {
			return true;
		}
	}

	// parsing viary tools to array notation
	public static function get_editing_tools( $editing_tools ) {

		parse_str( $editing_tools, $tools );
		if ( isset( $tools['editing_tools'] ) && $tools['editing_tools'] ) {
			return implode( ',', $tools['editing_tools'] );
		}
	}

	/**
	 * Check if selected meta as input type included
	 * return input: data_name
	 **/
	public static function has_posted_field_value( $posted_fields, $field ) {

		$has_value = false;

		$data_name = sanitize_key( $field['data_name'] );
		$type      = $field['type'];

		if ( ! empty( $posted_fields ) ) {
			foreach ( $posted_fields as $field_key => $value ) {
				$field_key = explode( '__clone_', $field_key );

				if ( in_array( $data_name, $field_key, true ) ) {

					switch ( $type ) {

						case 'quantities':
							$quantities_field = $value;
							$quantity         = 0;
							foreach ( $quantities_field as $option => $qty ) {
								$quantity += intval( $qty );
							}

							if ( $quantity > 0 ) {
								$has_value = true;
							}

							break;

						case 'fonts':
							if ( isset( $value['font'] ) && $value['font'] != '' ) {
								$has_value = true;
							}

							break;

						default:
							if ( $value != '' ) {
								$has_value = true;
							}
							break;

					}


					if ( $has_value ) {
						break;
					}
				}
			}
		}

		return apply_filters( 'ppom_has_posted_field_value', $has_value, $posted_fields, $field );
	}

	public static function is_aviary_installed() {

		if ( is_plugin_active( 'nm-aviary-photo-editing-addon/index.php' ) ) {
			return true;
		} else {
			return false;
		}
	}

	public static function settings_link( $links ) {
		$ppom_setting_url = admin_url( 'admin.php?page=ppom' );

		$links[] = '<a href="' . esc_url( $ppom_setting_url ) . '">' . __( 'Add Fields', 'woocommerce-product-addon' ) . '</a>';

		return $links;
	}

	// Field lookup.

	/**
	 * Resolves a visible PPOM field definition by data name.
	 *
	 * @param int                   $product_id          Product ID.
	 * @param string                $original_data_name Field data name from the request or stored payload.
	 * @param array|int|string|null $ppom_id            Optional PPOM group ID or IDs.
	 *
	 * @return array|string
	 *
	 * @internal Maintains the legacy `ppom_get_field_by_dataname__field_meta` filter signature when required by Pro compatibility flags.
	 *
	 * @see PPOM_Meta::get_fields()
	 * @see self::make_meta_data()
	 * @see self::generate_cart_meta()
	 */
	public static function get_field_meta_by_dataname( $product_id, $original_data_name, $ppom_id = null ) {

		$ppom        = new PPOM_Meta( $product_id );
		$ppom_fields = $ppom->fields;

		if ( ! empty( $ppom_id ) ) {
			$ppom_fields = $ppom->get_fields_by_id( $ppom_id );
		}

		if ( ! $ppom_fields ) {
			return '';
		}

		// self::pa($ppom_fields);
		$data_name = apply_filters( 'ppom_get_field_by_dataname_dataname', $original_data_name, $ppom );

		$field_meta = '';
		foreach ( $ppom_fields as $field ) {

			if ( ! self::is_field_visible( $field ) ) {
				continue;
			}

			if ( ! empty( $field['data_name'] ) && sanitize_key( $field['data_name'] ) == $data_name ) {
				$field_meta = $field;
				break;
			}
		}

		// Keep the apply_filters call has wrong param (released with v32.0.0)
		if ( self::pro_is_installed() && self::check_pro_compatibility( 'cond_field_repeat' ) && ! self::check_pro_compatibility( 'pgfbdfm_wp_filter_param_fix' ) ) {
			return apply_filters( 'ppom_get_field_by_dataname__field_meta', $ppom_fields, $field_meta, $original_data_name, $data_name );
		}

		// apply_filters call param fixed with PPOM v32.0.1
		return apply_filters( 'ppom_get_field_by_dataname__field_meta', $field_meta, $ppom_fields, $original_data_name, $data_name );
	}

	// Is PPOM meta has field of specific type
	public static function has_field_by_type( $product_id, $field_type ) {

		$ppom = new PPOM_Meta( $product_id );
		if ( ! $ppom->fields ) {
			return '';
		}

		$fields_found = array();
		foreach ( $ppom->fields as $field ) {

			if ( ! empty( $field['type'] ) && $field['type'] == $field_type ) {
				$fields_found[] = $field;
			}
		}

		return $fields_found;
	}

	public static function load_template( $file_name, $variables = array( '' ) ) {

		if ( is_array( $variables ) ) {
			extract( $variables );
		}

		$file_path = PPOM_PATH . '/templates/' . $file_name;
		$file_path = apply_filters( 'ppom_load_template', $file_path, $file_name, $variables );

		if ( file_exists( $file_path ) ) {
			include $file_path;
		} else {
			die( 'File not found' . $file_path );
		}
	}

	// Loading loading innput template absolute path provided
	public static function load_input_templates( $template_path, $vars = array( '' ) ) {

		// Extract variable from array
		if ( $vars != null && is_array( $vars ) ) {
			extract( $vars );
		}

		if ( isset( $addon_type ) ) {
			$full_path = $template_path;
		} else {
			$full_path = PPOM_PATH . "/templates/{$template_path}";
		}

		// self::pa($vars);

		// For template override
		$full_path = apply_filters( 'ppom_input_templates_path', $full_path, $template_path, $vars );

		// Load Inputs from theme
		// $theme_template = ppom_load_templates_from_theme($template_path);

		// if( $theme_template != null ) { $full_path = $theme_template; }

		if ( file_exists( $full_path ) ) {
			include $full_path;
		} else {
			die( "File not found {$full_path}" );
		}
	}

	// function ppom_load_templates_from_theme($template_name) {

	// $template_path =  get_parent_theme_file_path() . "/ppom/{$template_name}";

	// if( ! is_file( $template_path ) ){
	// $template_path = null;
	// }

	// return  $template_path;
	// }

	// load file from full given path
	public static function load_file( $file_path, $variables = array( '' ) ) {

		if ( is_array( $variables ) ) {
			extract( $variables );
		}

		if ( file_exists( $file_path ) ) {
			include $file_path;
		} else {
			die( 'File not found' . $file_path );
		}
	}

	public static function load_bootstrap_css() {

		$return = true;
		if ( self::get_option( 'ppom_disable_bootstrap' ) == 'yes' ) {
			$return = false;
		}

		return apply_filters( 'ppom_bootstrap_css', $return );
	}

	public static function load_fontawesome() {

		$return = true;
		if ( self::get_option( 'ppom_disable_fontawesome' ) == 'yes' ) {
			$return = false;
		}

		return apply_filters( 'ppom_disable_fontawesome', $return );
	}


	public static function convert_options_to_key_val( $options, $meta, $product ) {

		if ( empty( $options ) ) {
			return $options;
		}

		if ( is_string( $options ) ) {
			$options = json_decode( $options, true );
		}

		if ( ! apply_filters( 'ppom_is_option_convertable', true, $meta ) ) {
			return $options;
		}

		$meta_type = isset( $meta['type'] ) ? $meta['type'] : '';

		// Do not change options for cropper
		// if( $meta['type'] == 'cropper' ) return $options;

		$ppom_new_option = array();
		foreach ( $options as $option ) {

			$the_option = isset( $option['option'] ) ? stripslashes( wp_specialchars_decode( $option['option'] ) ) : '';

			if ( apply_filters( 'ppom_hide_if_out_of_stock', true, $option ) ) {
				$has_stock = self::option_has_stock( $option );
				if ( ! $has_stock ) {
					continue;
				}
			}

			// Following input has 'title' instead 'option' in options array
			$option_with_titles_keys = apply_filters(
				'ppom_option_with_title_key',
				array(
					'imageselect',
					'image',
					'audio',
				)
			);
			if ( in_array( $meta_type, $option_with_titles_keys ) ) {

				$the_option = ! empty( $option['title'] ) ? stripslashes( $option['title'] ) : $option['id'];
			}

			if ( $the_option != '' ) {

				$option                   = self::translation_options( $option );
				$option_price_without_tax = '';


				$option_percent = '';

				$show_price = isset( $meta['show_price'] ) ? $meta['show_price'] : '';
				$data_name  = isset( $meta['data_name'] ) ? $meta['data_name'] : '';

				$option_price = isset( $option['price'] ) ? $option['price'] : '';

				// Currency swithcer
				$product_price = self::get_product_price( $product );
				$product_price = Callbacks::convert_price_back( $product_price );

				// For quantities if default price is set
				if ( $meta['type'] == 'quantities' ) {
					$quantities_dp = '';
					if ( Engine::is_field_has_price( $meta ) ) {
						$quantities_dp = isset( $meta['default_price'] ) && $meta['default_price'] != '' ? $meta['default_price'] : '';
					}

					$option_price = isset( $option['price'] ) && $option['price'] != '' ? $option['price'] : $quantities_dp;
				}

				$option_raw_price = $option_price;


				if ( strpos( $option_price, '%' ) !== false ) {
					$option_price   = Engine::get_amount_after_percentage( $product_price, $option_price );
					$option_percent = $option_raw_price;
				}

				// Handling vat for option price
				$option_price = apply_filters( 'ppom_option_price_vat', $option_price, $product );
				// var_dump($option_price);

				$option_label = self::generate_option_label( $option, $option_price, $meta );

				// This filter change prices for Currency switcher
				// $option_price    = apply_filters('ppom_option_price', $option_price);

				// Price matrix discount
				$discount      = isset( $meta['discount'] ) && $meta['discount'] == 'on' ? true : false;
				$discount_type = isset( $meta['discount_type'] ) ? $meta['discount_type'] : 'base';

				// $show_option_price = apply_filters('ppom_show_option_price', $show_price, $meta);
				/*
				if( !empty($option_price) ) {

				// $option_price = $option['price'];

				// check if price in percent
				if(strpos($option_price,'%') !== false){
					$option_price = Engine::get_amount_after_percentage($product_price, $option_price);
					// check if price is fixed and taxable
					if(isset($meta['onetime']) && $meta['onetime'] == 'on' && isset($meta['onetime_taxable']) && $meta['onetime_taxable'] == 'on') {
						$option_price_without_tax = $option_price;
						$option_price = self::get_price_including_tax($option_price, $product);
					}
					$option_label   = self::generate_option_label($option, $option_price, $meta);
					$option_percent = $option['price'];
				} else {

					// check if price is fixed and taxable
					if(isset($meta['onetime']) && $meta['onetime'] == 'on' && isset($meta['onetime_taxable']) && $meta['onetime_taxable'] == 'on') {
						$option_price_without_tax = $option_price;
						$option_price = self::get_price_including_tax($option_price, $product);
					}
					$option_label = self::generate_option_label($option, $option_price, $meta);
				}

				}*/

				// self::pa($option);
				$option_id = self::get_option_id( $option, $meta );

				$ppom_new_option[ $the_option ] = array(
					'label'       => $option_label,
					'price'       => apply_filters( 'ppom_option_price', $option_price ),
					'raw_price'   => $option_raw_price,
					'raw'         => $the_option,
					'without_tax' => $option_price_without_tax,
					'percent'     => $option_percent,
					'data_name'   => $data_name,
					'id'          => $option_id,        // Legacy key fix
					'option_id'   => $option_id,
				);

				if ( $discount ) {
					$ppom_new_option[ $the_option ]['discount'] = $discount_type;
				}


				// Adding weight
				if ( isset( $option['weight'] ) ) {
					$ppom_new_option[ $the_option ]['option_weight'] = $option['weight'];
				}

				// Matrix-fixed @since 22.0
				if ( isset( $option['isfixed'] ) ) {
					$ppom_new_option[ $the_option ]['matrix_fixed'] = $option['isfixed'];
				}

				$ppom_new_option = apply_filters( 'ppom_option_meta', $ppom_new_option, $the_option, $option, $meta, $product );
			}
		}

		if ( ! empty( $meta['first_option'] ) ) {

			$fo_labeld    = self::wpml_translate( $meta['first_option'], 'PPOM' );
			$first_option = array(
				'' => array(
					'label'       => $fo_labeld,
					'price'       => '',
					'raw'         => '',
					'without_tax' => '',
					'option_id'   => '__first_option__',
				),
			);

			$ppom_new_option = $first_option + $ppom_new_option;
			// array_unshift( $ppom_new_option, $first_option);
		}

		// self::pa($ppom_new_option);
		return apply_filters( 'ppom_options_after_changes', $ppom_new_option, $options, $meta, $product );
	}


	// Generating option label with price
	public static function generate_option_label( $option, $price, $meta ) {

		$meta_type = isset( $meta['type'] ) ? $meta['type'] : '';

		$the_option = isset( $option['option'] ) ? $option['option'] : '';
		if ( $meta_type == 'imageselect' || $meta_type === 'image' ) {
			$the_option = isset( $option['title'] ) ? $option['title'] : '';
		}

		$price = isset( $option['discount'] ) && $option['discount'] > 0 ? $option['discount'] : $price;

		$option_label = ! empty( $option['label'] ) ? $option['label'] : $the_option;
		$option_label = stripcslashes( $option_label );

		if ( ! empty( $price ) ) {

			$price = apply_filters( 'ppom_option_price', $price );

			$option_price_opr = apply_filters( 'ppom_option_price_operator', '+', $price, $meta );

			$price = strip_tags( self::price( $price ) );

			switch ( $meta_type ) {

				// No span/html in Select DOM
				case 'selectqty':
				case 'select':
				case 'multiple_select':
					$price_replacement = " [{$option_price_opr}{$price}]";
					break;

				default:
					$price_replacement = " <span class='ppom-option-label-price'>[{$option_price_opr}{$price}]</span>";
					break;
			}


			$option_label = "{$option_label}{$price_replacement}";
		}

		return apply_filters( 'ppom_option_label', $option_label, $option, $meta, $price );
	}


	// Retrun unique option ID
	public static function get_option_id( $option, $field_meta = null ) {

		$data_name  = isset( $field_meta['data_name'] ) ? $field_meta['data_name'] : '';
		$the_option = isset( $option['option'] ) ? $option['option'] : '';
		$field_type = isset( $field_meta['type'] ) ? $field_meta['type'] : '';

		switch ( $field_type ) {
			case 'image':
				$the_option   = isset( $option['title'] ) ? $option['title'] : '';
				$option['id'] = sanitize_key( $the_option );
				if ( empty( $option['id'] ) && is_scalar( $the_option ) ) {
					$the_option   = strtolower( $the_option );
					$option['id'] = wp_hash( $the_option );
				}
				break;

			case 'imageselect':
				$the_option = isset( $option['title'] ) ? $option['title'] : '';
				break;
		}


		$default_option = is_null( $data_name ) ? $the_option : $data_name . '_' . $the_option;

		$option_id = empty( $option['id'] ) ? $default_option : $option['id'];

		return apply_filters( 'ppom_option_id', sanitize_key( $option_id ), $option, $data_name );
	}

	public static function get_price_including_tax( $price, $product ) {

		if ( 'incl' !== get_option( 'woocommerce_tax_display_shop' ) ) {
			return $price;
		}

		$line_price   = $price;
		$return_price = $line_price;

		$tax_rates    = WC_Tax::get_rates( $product->get_tax_class() );
		$taxes        = WC_Tax::calc_tax( $line_price, $tax_rates, false );
		$tax_amount   = WC_Tax::get_tax_total( $taxes );
		$return_price = round( $line_price + $tax_amount, wc_get_price_decimals() );

		return $return_price;

		if ( $product->is_taxable() ) {
			if ( ! wc_prices_include_tax() ) {
				$tax_rates    = WC_Tax::get_rates( $product->get_tax_class() );
				$taxes        = WC_Tax::calc_tax( $line_price, $tax_rates, false );
				$tax_amount   = WC_Tax::get_tax_total( $taxes );
				$return_price = round( $line_price + $tax_amount, wc_get_price_decimals() );
			} else {
				$tax_rates      = WC_Tax::get_rates( $product->get_tax_class() );
				$base_tax_rates = WC_Tax::get_base_tax_rates( $product->get_tax_class( 'unfiltered' ) );

				/**
				 * If the customer is excempt from VAT, remove the taxes here.
				 * Either remove the base or the user taxes depending on woocommerce_adjust_non_base_location_prices setting.
				 */
				if ( ! empty( WC()->customer ) && WC()->customer->get_is_vat_exempt() ) {
					$remove_taxes = apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ? WC_Tax::calc_tax( $line_price, $base_tax_rates, true ) : WC_Tax::calc_tax( $line_price, $tax_rates, true );
					$remove_tax   = array_sum( $remove_taxes );
					$return_price = round( $line_price - $remove_tax, wc_get_price_decimals() );

					/**
					 * The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing with out of base locations.
					 * e.g. If a product costs 10 including tax, all users will pay 10 regardless of location and taxes.
					 * This feature is experimental @since 2.4.7 and may change in the future. Use at your risk.
					 */
				} elseif ( $tax_rates !== $base_tax_rates && apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ) {
					$base_taxes   = WC_Tax::calc_tax( $line_price, $base_tax_rates, true );
					$modded_taxes = WC_Tax::calc_tax( $line_price - array_sum( $base_taxes ), $tax_rates, false );
					$return_price = round( $line_price - array_sum( $base_taxes ) + wc_round_tax_total( array_sum( $modded_taxes ), wc_get_price_decimals() ), wc_get_price_decimals() );
				}
			}
		}

		return apply_filters( 'ppom_get_price_including_tax', $return_price, $product );
	}

	// Check if field conditionally hidden
	public static function is_field_hidden_by_condition( $field_name, $conditionally_hidden = null ) {

		if ( ! isset( $_POST['ppom']['conditionally_hidden'] ) && $conditionally_hidden == null ) {
			return false;
		}

		$conditionally_hidden = isset( $_POST['ppom']['conditionally_hidden'] ) ? sanitize_text_field( $_POST['ppom']['conditionally_hidden'] ) : $conditionally_hidden;

		$ppom_is_hidden = false;

		$ppom_hidden_fields = explode( ',', $conditionally_hidden );
		// Remove duplicates
		$ppom_hidden_fields = array_unique( $ppom_hidden_fields );

		if ( in_array( $field_name, $ppom_hidden_fields ) ) {

			$ppom_is_hidden = true;
		}

		return apply_filters( 'ppom_is_field_hidden_by_condition', $ppom_is_hidden );
	}

	/**
	 * Normalizes PPOM group IDs from scalar, comma-separated, or array payloads.
	 *
	 * @param mixed $meta_ids PPOM group IDs.
	 * @return int[]
	 */
	public static function normalize_ppom_meta_ids( $meta_ids ) {
		if ( is_string( $meta_ids ) ) {
			$meta_ids = explode( ',', $meta_ids );
		} elseif ( is_numeric( $meta_ids ) ) {
			$meta_ids = array( $meta_ids );
		} elseif ( ! is_array( $meta_ids ) ) {
			$meta_ids = array();
		}

		$normalized = array();
		foreach ( $meta_ids as $meta_id ) {
			$meta_id = absint( $meta_id );
			if ( $meta_id > 0 ) {
				$normalized[] = $meta_id;
			}
		}

		return array_values( array_unique( $normalized ) );
	}

	/**
	 * Returns variation display rules for a parent product.
	 *
	 * Stored shape is: [ ppom_group_id => [ variation_id, ... ] ]. Data is
	 * normalized on write by {@see self::update_variation_rule_map()}, so the
	 * read path trusts the stored value.
	 *
	 * @param int $product_id Parent product ID.
	 * @return array<int, int[]>
	 */
	public static function get_variation_rule_map( $product_id ) {
		$product_id = absint( $product_id );
		if ( $product_id <= 0 ) {
			return array();
		}

		$rules = get_post_meta( $product_id, PPOM_VARIATION_META_KEY, true );

		return is_array( $rules ) ? $rules : array();
	}

	/**
	 * Saves normalized variation display rules for a parent product.
	 *
	 * @param int                                 $product_id Parent product ID.
	 * @param array<int|string, array<int>|mixed> $rules    Rule map keyed by PPOM group ID.
	 * @return void
	 */
	public static function update_variation_rule_map( $product_id, array $rules ) {
		$product_id = absint( $product_id );
		if ( $product_id <= 0 ) {
			return;
		}

		$normalized = array();
		foreach ( $rules as $ppom_id => $variation_ids ) {
			$ppom_id = absint( $ppom_id );
			if ( $ppom_id <= 0 || ! is_array( $variation_ids ) ) {
				continue;
			}

			$variation_ids = array_values(
				array_unique(
					array_filter(
						array_map( 'absint', $variation_ids ),
						function ( $variation_id ) {
							return $variation_id > 0;
						}
					)
				)
			);

			if ( ! empty( $variation_ids ) ) {
				$normalized[ $ppom_id ] = $variation_ids;
			}
		}

		if ( empty( $normalized ) ) {
			delete_post_meta( $product_id, PPOM_VARIATION_META_KEY );
			return;
		}

		update_post_meta( $product_id, PPOM_VARIATION_META_KEY, $normalized );
	}

	/**
	 * Returns the selected variation IDs for one PPOM group on one product.
	 *
	 * @param int $product_id Parent product ID.
	 * @param int $ppom_id    PPOM group ID.
	 * @return int[]
	 */
	public static function get_variation_ids_for_group( $product_id, $ppom_id ) {
		$rules   = self::get_variation_rule_map( $product_id );
		$ppom_id = absint( $ppom_id );

		return isset( $rules[ $ppom_id ] ) ? $rules[ $ppom_id ] : array();
	}

	/**
	 * Determines whether a PPOM group should be active for the selected variation.
	 *
	 * Empty restrictions mean unrestricted legacy behavior.
	 *
	 * @param int $product_id   Parent product ID.
	 * @param int $ppom_id      PPOM group ID.
	 * @param int $variation_id Selected WooCommerce variation ID.
	 * @return bool
	 */
	public static function is_meta_group_active_for_variation( $product_id, $ppom_id, $variation_id ) {
		$allowed_variations = self::get_variation_ids_for_group( $product_id, $ppom_id );
		if ( empty( $allowed_variations ) ) {
			return true;
		}

		$variation_id = absint( $variation_id );
		if ( $variation_id <= 0 ) {
			return false;
		}

		return in_array( $variation_id, $allowed_variations, true );
	}

	/**
	 * Filters posted PPOM field values to the groups active for a variation.
	 *
	 * @param array<string, mixed> $posted_fields Posted ppom[fields] payload.
	 * @param int                  $product_id    Parent product ID.
	 * @param int                  $variation_id  Selected WooCommerce variation ID.
	 * @return array<string, mixed>
	 */
	public static function filter_posted_ppom_fields_by_active_variation( array $posted_fields, $product_id, $variation_id ) {
		$ppom = new PPOM_Meta( $product_id );
		if ( empty( $ppom->fields ) ) {
			return $posted_fields;
		}

		$inactive_datanames = array();
		foreach ( $ppom->fields as $field ) {
			$ppom_id = isset( $field['ppom_id'] ) ? absint( $field['ppom_id'] ) : 0;
			if ( $ppom_id <= 0 || self::is_meta_group_active_for_variation( $product_id, $ppom_id, $variation_id ) ) {
				continue;
			}

			if ( ! empty( $field['data_name'] ) ) {
				$inactive_datanames[ sanitize_key( $field['data_name'] ) ] = true;
			}
		}

		foreach ( array_keys( $posted_fields ) as $data_name ) {
			if ( 'id' === $data_name ) {
				continue;
			}

			if ( isset( $inactive_datanames[ sanitize_key( $data_name ) ] ) ) {
				unset( $posted_fields[ $data_name ] );
			}
		}

		if ( isset( $posted_fields['id'] ) ) {
			$active_meta_ids = array();
			foreach ( self::normalize_ppom_meta_ids( $posted_fields['id'] ) as $ppom_id ) {
				if ( self::is_meta_group_active_for_variation( $product_id, $ppom_id, $variation_id ) ) {
					$active_meta_ids[] = $ppom_id;
				}
			}

			if ( empty( $active_meta_ids ) ) {
				unset( $posted_fields['id'] );
			} else {
				$posted_fields['id'] = implode( ',', $active_meta_ids );
			}
		}

		return $posted_fields;
	}

	/**
	 * Filters a full PPOM payload to the groups active for a variation.
	 *
	 * @param array<string, mixed> $ppom_payload Posted ppom payload.
	 * @param int                  $product_id   Parent product ID.
	 * @param int                  $variation_id Selected WooCommerce variation ID.
	 * @return array<string, mixed>
	 */
	public static function filter_ppom_payload_by_active_variation( array $ppom_payload, $product_id, $variation_id ) {
		if ( empty( $ppom_payload['fields'] ) || ! is_array( $ppom_payload['fields'] ) ) {
			return $ppom_payload;
		}

		$original_fields        = $ppom_payload['fields'];
		$ppom_payload['fields'] = self::filter_posted_ppom_fields_by_active_variation( $ppom_payload['fields'], $product_id, $variation_id );
		$inactive_datanames     = array_diff( array_keys( $original_fields ), array_keys( $ppom_payload['fields'] ) );

		if ( ! empty( $inactive_datanames ) && ! empty( $ppom_payload['ppom_option_price'] ) ) {
			$option_prices = json_decode( wp_unslash( $ppom_payload['ppom_option_price'] ), true );
			if ( is_array( $option_prices ) ) {
				$inactive_map = array();
				foreach ( $inactive_datanames as $data_name ) {
					$inactive_map[ sanitize_key( $data_name ) ] = true;
				}

				$option_prices = array_values(
					array_filter(
						$option_prices,
						function ( $option ) use ( $inactive_map ) {
							if ( ! is_array( $option ) || empty( $option['data_name'] ) ) {
								return true;
							}

							return ! isset( $inactive_map[ sanitize_key( $option['data_name'] ) ] );
						}
					)
				);

				$encoded_option_prices = wp_json_encode( $option_prices );
				if ( false !== $encoded_option_prices ) {
					$ppom_payload['ppom_option_price'] = $encoded_option_prices;
				}
			}
		}

		return $ppom_payload;
	}

	// Get cart item max quantity for matrix
	public static function get_cart_item_max_quantity( $cart_item ) {

		$max_quantity = null;
		if ( isset( $cart_item['ppom']['ppom_pricematrix'] ) ) {
			$matrix       = json_decode( stripslashes( $cart_item['ppom']['ppom_pricematrix'] ) );
			$last_range   = end( $matrix );
			$qty_ranges   = explode( '-', $last_range->raw );
			$max_quantity = $qty_ranges[1];
		}

		return $max_quantity;
	}

	// Extract relevant matrix from Matrix Range given by quantity
	public static function extract_matrix_by_quantity( $quantities_field, $product, $quantity ) {

		$matrix = '';
		if ( ! isset( $quantities_field['options'] ) ) {
			return $matrix;
		}

		$options = $quantities_field['options'];
		$ranges  = self::convert_options_to_key_val( $options, $quantities_field, $product );

		if ( empty( $ranges ) ) {
			return $matrix;
		}

		$quantity = intval( $quantity );
		foreach ( $ranges as $range => $data ) {

			if ( strpos( $range, '-' ) !== false ) {
				list( $start, $end ) = array_map( 'intval', explode( '-', $range ) );
				if ( $quantity >= $start && $quantity <= $end ) {
					$matrix = $data;
					break;
				}
			} else {
				$value = intval( $range );

				if ( $range === array_key_first( $ranges ) && $quantity <= $value ) {
					$matrix = $data;
					break;
				} elseif ( $range === array_key_last( $ranges ) && $quantity >= $value ) {
					$matrix = $data;
					break;
				}
			}
		}

		return $matrix;
	}

	/**
	 * Thumbnail image size.
	 *
	 * @param int $size Image size.
	 *
	 * @return string
	 */
	public static function get_thumbs_size( $size = 150 ) {

		return apply_filters( 'ppom_thumbs_size', sprintf( '%dpx', absint( $size ) ) );
	}

	// Return file size in kb
	public static function get_filesize_in_kb( $file_name ) {

		$base_dir  = Handler::get_dir_path();
		$file_path = $base_dir . 'confirmed/' . $file_name;

		if ( file_exists( $file_path ) ) {
			$size = filesize( $file_path );

			return round( $size / 1024, 2 ) . ' KB';
		} elseif ( file_exists( $base_dir . '/' . $file_name ) ) {
			$size = filesize( $base_dir . '/' . $file_name );

			return round( $size / 1024, 2 ) . ' KB';
		}
	}


	// Generating html for file input and cropper in order meta from filename
	public static function generate_html_for_files( $file_names, $input_type, $item ) {
		$file_name_array = explode( ',', $file_names );

		$order_html = '<table>';
		foreach ( $file_name_array as $file_name ) {

			$file_edit_path = Handler::get_dir_path( 'edits' ) . Handler::file_get_name( $file_name, $item->get_product_id() );
			// Making file thumb download with new path
			$ppom_file_url = Handler::get_file_download_url( $file_name, $item->get_order_id(), $item->get_product_id() );

			$file_path           = Handler::get_dir_url( true ) . $file_name;
			$is_image_file       = Handler::is_file_image( $file_path );
			$ppom_file_thumb_url = $is_image_file ? $file_path : PPOM_URL . '/images/file.png';
			$order_html         .= '<tr><td class="ppom-files-display">';
			$order_html         .= '<a target="_blank" href="' . esc_url( $ppom_file_url ) . '">';
			$order_html         .= '<img class="img-thumbnail" style="width:' . esc_attr( self::get_thumbs_size() ) . '" src="' . esc_url( $ppom_file_thumb_url ) . '">';
			$order_html         .= '</a>';

			// Requested by Kevin, hiding downloading file button after order on thank you page
			// @since version 16.6
			if ( is_admin() ) {
				$order_html .= '<a class="button" href="' . esc_url( $ppom_file_url ) . '" download>';
				$order_html .= __( 'Download File', 'woocommerce-product-addon' );
				$order_html .= '</a>';
			}

			$order_html .= '</td>';
			$order_html .= '</tr>';

			if ( $input_type == 'cropper' ) {

				$cropped_file_name = Handler::file_get_name( $file_name, $item->get_product_id() );
				$cropped_url       = Handler::get_dir_url() . 'cropped/' . $cropped_file_name;
				$order_html       .= '<tr><td><a target="_blank" href="' . esc_url( $cropped_url ) . '">';
				$order_html       .= '<img style="width:' . esc_attr( self::get_thumbs_size() ) . '" class="img-thumbnail" src="' . esc_url( $cropped_url ) . '">';
				$order_html       .= '</a></td>';

				// Requested by Kevin, hiding downloading file button after order on thank you page
				// @since version 16.6
				if ( is_admin() ) {
					$order_html .= '<td><a target="_blank" class="button" href="' . esc_url( $cropped_url ) . '">';
					$order_html .= __( 'Cropped', 'woocommerce-product-addon' );
					$order_html .= '</a></td>';
				}
				$order_html .= '</tr>';

			} elseif ( file_exists( $file_edit_path ) ) {

				$edit_file_name = Handler::file_get_name( $file_name, $item->get_product_id() );
				$edit_url       = Handler::get_dir_url() . 'edits/' . $edit_file_name;
				$edit_thumb_url = Handler::get_dir_url() . 'edits/thumbs/' . $file_name;
				$order_html    .= '<tr><td><a target="_blank"  href="' . esc_url( $edit_url ) . '">';
				$order_html    .= '<img style="width:' . esc_attr( self::get_thumbs_size() ) . '" class="img-thumbnail" src="' . esc_url( $edit_thumb_url ) . '">';
				$order_html    .= '</a></td>';
				$order_html    .= '<td><a class="button" href="' . esc_url( $edit_url ) . '">';
				$order_html    .= __( 'Edited', 'woocommerce-product-addon' );
				$order_html    .= '</a></td></tr>';
			}
		}
		$order_html .= '</table>';

		return apply_filters( 'ppom_order_files_html', $order_html, $file_names, $input_type, $item );
	}


	// return html for images selected
	public static function generate_html_for_images( $images ) {
		global $post;

		static $ppom_has_cart_block = null;
		if ( is_null( $ppom_has_cart_block ) ) {
			$ppom_has_cart_block = has_block( 'woocommerce/cart', $post );
		}

		if ( $ppom_has_cart_block ) {
			return self::get_image_name( $images );
		}

		$ppom_html = '<table class="table table-bordered">';
		foreach ( $images as $id => $images_meta ) {

			$images_meta = json_decode( stripslashes( $images_meta ), true );
			$image_url   = stripslashes( $images_meta['link'] );
			$image_label = isset( $images_meta['raw'] ) ? $images_meta['raw'] : '';
			$image_html  = '<img class="img-thumbnail" style="width:' . esc_attr( self::get_thumbs_size( 75 ) ) . '" src="' . esc_url( $image_url ) . '" title="' . esc_attr( $image_label ) . '">';

			$ppom_html .= '<tr><td><a href="' . esc_url( $image_url ) . '" class="lightbox" itemprop="image" title="' . esc_attr( $image_label ) . '">' . $image_html . '</a></td>';
			$ppom_html .= '<td>' . esc_attr( Handler::files_trim_name( $image_label ) ) . '</td>';
			$ppom_html .= '</tr>';

		}

		$ppom_html .= '</table>';

		return apply_filters( 'ppom_images_html', $ppom_html, $images );
	}

	// Getting field option price
	public static function get_field_option_price( $field_meta, $option_label ) {

		// var_dump($field_meta['options']);
		if ( ! isset( $field_meta['options'] ) || $field_meta['type'] == 'bulkquantity' || $field_meta['type'] == 'cropper' ) {
			return 0;
		}

		$option_price = 0;
		foreach ( $field_meta['options'] as $option ) {

			if ( isset( $option['option'] ) && $option['option'] == $option_label && isset( $option['price'] ) && $option['price'] != '' ) {

				$option_price = $option['price'];
			}
		}

		// For currency switcher
		$option_price = apply_filters( 'ppom_option_price', $option_price );

		return apply_filters( 'ppom_field_option_price', wc_format_decimal( $option_price ), $field_meta, $option_label );
	}

	// Getting field option price by ID
	public static function get_field_option_price_by_id( $option, $product, $ppom_meta_ids ) {

		$data_name = isset( $option['data_name'] ) ? $option['data_name'] : '';
		$option_id = isset( $option['option_id'] ) ? $option['option_id'] : '';

		// soon we will remove this product param
		$product_id = null;
		$field_meta = self::get_field_meta_by_dataname( $product_id, $data_name, $ppom_meta_ids );

		if ( empty( $field_meta ) ) {
			return 0;
		}


		// It was huge lost of PPOM :(, finally got it :)
		// When migration from old PPOM version where option id was not being created
		// price were not calculated due to this old data unless admin re-save it again
		$option_key = $field_meta['type'] == 'image' ? 'images' : 'options';
		if ( ! isset( $field_meta[ $option_key ][0]['id'] ) ) {
			$field_meta[ $option_key ] = self::convert_options_to_key_val( $field_meta[ $option_key ], $field_meta, $product );
		}

		$field_type = isset( $field_meta['type'] ) ? $field_meta['type'] : '';

		if ( $field_type == 'bulkquantity' || $field_type == 'cropper' ) {
			return 0;
		}

		$option_price = 0;

		switch ( $field_type ) {

			case 'image':
				if ( isset( $field_meta['images'] ) ) {
					foreach ( $field_meta['images'] as $option ) {

						$image_id = $field_meta['data_name'] . '-' . $option['id'];
						if ( $image_id == $option_id && isset( $option['price'] ) && $option['price'] != '' ) {

							if ( strpos( $option['price'], '%' ) !== false ) {
								$option_price = Engine::get_amount_after_percentage( $product->get_price(), $option['price'] );
							} else {
								// For currency switcher
								// $option_price = apply_filters('ppom_option_price', $option['price']);
								$option_price = $option['price'];
							}
						}
					}
				}
				break;

			default:
				if ( isset( $field_meta['options'] ) ) {
					foreach ( $field_meta['options'] as $option ) {

						if ( $option['id'] == $option_id && isset( $option['price'] ) && $option['price'] != '' ) {

							if ( strpos( $option['price'], '%' ) !== false ) {
								$option_price = Engine::get_amount_after_percentage( $product->get_price(), $option['price'] );
							} else {
								// For currency switcher
								// $option_price = apply_filters('ppom_option_price', $option['price']);
								$option_price = $option['price'];
							}
						}
					}
				}
				break;
		}


		return apply_filters( 'ppom_field_option_price_by_id', wc_format_decimal( $option_price ), $field_meta, $option_id, $product );
	}

	// Getting field option weight by ID
	public static function get_field_option_weight_by_id( $option, $ppom_meta_ids ) {

		$data_name = isset( $option['data_name'] ) ? $option['data_name'] : '';
		$option_id = isset( $option['option_id'] ) ? $option['option_id'] : '';

		// soon we will remove this product param
		$product_id = null;
		$field_meta = self::get_field_meta_by_dataname( $product_id, $data_name, $ppom_meta_ids );

		if ( empty( $field_meta ) ) {
			return 0;
		}

		if ( ! isset( $field_meta['options'] ) || $field_meta['type'] == 'bulkquantity' || $field_meta['type'] == 'cropper' ) {
			return 0;
		}

		$option_weight = 0;
		foreach ( $field_meta['options'] as $option ) {

			if ( $option['id'] == $option_id && isset( $option['weight'] ) && $option['weight'] != '' ) {

				$option_weight = floatval( $option['weight'] );
			}
		}

		return apply_filters( 'ppom_field_option_weight_by_id', $option_weight, $field_meta, $option_id, $ppom_meta_ids );
	}

	// Getting field option stock by ID
	public static function field_has_stock( $meta, $value ) {

		$type      = isset( $meta['type'] ) ? $meta['type'] : '';
		$has_stock = array();

		switch ( $type ) {

			case 'select':
			case 'radio':
				if ( isset( $meta['options'] ) ) {
					foreach ( $meta['options'] as $option ) {
						// var_dump( $option['option'] .'==> ' .stripslashes($value));
						// var_dump( isset($option['stock']) && $option['stock'] != '' && stripslashes($option['option']) == stripslashes($value));
						if ( isset( $option['stock'] ) && $option['stock'] != '' && stripslashes( $option['option'] ) == stripslashes( $value ) ) {
							$has_stock[] = $option;
							break;
						}
					}
				}
				break;

			case 'checkbox':
				if ( is_array( $value ) ) {
					$cb_value = array_map( 'stripslashes', $value );
					foreach ( $cb_value as $cb ) {
						foreach ( $meta['options'] as $option ) {
							if ( isset( $option['stock'] ) && ! empty( $option['stock'] ) && stripslashes( $option['option'] ) == $cb ) {
								// var_dump($option['stock']);
								$has_stock[] = $option;
								break;
							}
						}
					}
				}
				break;

			case 'quantities':
				$manage_stock = $meta['manage_stock'] === 'on' ? true : false;

				if ( is_array( $value ) && $manage_stock ) {
					foreach ( $value as $v => $qty ) {
						if ( ! $qty ) {
							continue;
						}
						// self::pa($meta['options']);
						// self::pa($value);
						foreach ( $meta['options'] as $option ) {
							if ( isset( $option['stock'] ) && ! empty( $option['stock'] ) && stripslashes( $option['option'] ) == $v ) {
								$option['stock'] = $option['stock'] - $qty;
								$has_stock[]     = $option;
								break;
							}
						}
					}
				}
				break;

			case 'image':
				foreach ( $value as $data ) {
					$image = json_decode( stripslashes( $data ), true );
					foreach ( $meta['images'] as $option ) {
						if ( isset( $option['stock'] ) && ! empty( $option['stock'] ) && stripslashes( $option['id'] ) == $image['image_id'] ) {
							$option['option'] = $option['title'];
							$has_stock[]      = $option;
							break;
						}
					}
				}
				break;

		}

		return apply_filters( 'ppom_field_has_stock', $has_stock, $meta, $value );
	}

	// Check if given option has stock
	public static function option_has_stock( $option ) {

		$has_stock = true;
		if ( isset( $option['stock'] ) && $option['stock'] !== '' && intval( $option['stock'] ) <= 0 ) {
			$has_stock = false;
		}

		return apply_filters( 'ppom_option_has_stock', $has_stock, $option );
	}

	// check if PPOM PRO is installed
	public static function pro_is_installed() {
		return class_exists( 'PPOM_PRO' );
	}

	/**
	 * Check is valid license activated.
	 *
	 * @return bool
	 */
	public static function pro_is_valid_license() {
		return self::pro_is_installed() && apply_filters( 'product_ppom_license_status', '' ) === 'valid';
	}

	// Check if PPOM API is enable
	public static function is_api_enable() {

		$api_enable = self::get_option( 'ppom_api_enable' );
		$api_key    = self::get_option( 'ppom_rest_secret_key' );

		$return = false;

		if ( $api_enable == 'yes' && $api_key != '' ) {
			$return = true;
		}

		return $return;
	}

	// Check if field is visible
	public static function is_field_visible( $field ) {

		if ( ! self::pro_is_installed() ) {
			return true;
		}
		// self::pa($field);

		$visibility = isset( $field['visibility'] ) ? $field['visibility'] : 'everyone';

		$visibility_role = isset( $field['visibility_role'] ) ? $field['visibility_role'] : '';

		$is_visible = false;
		switch ( $visibility ) {

			case 'everyone':
				$is_visible = true;
				break;

			case 'members':
				if ( is_user_logged_in() ) {
					$is_visible = true;
				}
				break;

			case 'guests':
				if ( ! is_user_logged_in() ) {
					$is_visible = true;
				}
				break;

			case 'roles':
				$user_roles    = self::get_current_user_role();
				$allowed_roles = explode( ',', $visibility_role );
				// var_dump(array_intersect($allowed_roles, $user_roles));

				$result = array_intersect( $allowed_roles, $user_roles );
				if ( count( $result ) > 0 ) {
					$is_visible = true;
				}
				break;
		}

		return apply_filters( 'ppom_is_field_visible', $is_visible, $field );
	}

	// Get logged in user role
	public static function get_current_user_role() {

		if ( is_user_logged_in() ) {
			$user = wp_get_current_user();

			return (array) $user->roles;
		} else {
			return array();
		}
	}

	// Retrun price with currency symbol but without html
	public static function price( $price ) {

		$price = floatval( $price );

		$decimal_separator  = wc_get_price_decimal_separator();
		$thousand_separator = wc_get_price_thousand_separator();
		$decimals           = wc_get_price_decimals();
		$price_format       = get_woocommerce_price_format();
		$negative           = $price < 0;

		// $wc_price = number_format( $price,$decimals, $decimal_separator, $thousand_separator );
		$wc_price        = number_format( abs( $price ), $decimals, $decimal_separator, $thousand_separator );
		$formatted_price = ( $negative ? '-' : '' ) . sprintf( $price_format, get_woocommerce_currency_symbol(), $wc_price );

		return apply_filters( 'ppom_woocommerce_price', $formatted_price );
	}

	// If price set by pricematrix in cart return matrix
	public static function get_price_matrix_chunk( $product, $option_prices, $ppom_item_order_qty ) {

		$matrix_found = '';

		$pricematrix_field = self::has_field_by_type( self::get_product_id( $product ), 'pricematrix' );
		// self::pa($pricematrix_field);

		if ( ! $pricematrix_field ) {
			return $matrix_found;
		}

		if ( count( $pricematrix_field ) > 0 ) {

			foreach ( $pricematrix_field as $pm ) {

				// iterecting option_prices
				foreach ( $option_prices as $op ) {

					if ( $op['apply'] != 'matrix_discount' && $op['apply'] != 'matrix' ) {
						continue;
					}

					if ( $op['data_name'] == $pm['data_name'] ) {
						$pricematrix_field = $pm;
						break;
					}
				}
			}

			// $pricematrix_field = $pricematrix_field[0];
			$matrix_found = self::extract_matrix_by_quantity( $pricematrix_field, $product, $ppom_item_order_qty );
		}

		return apply_filters( 'ppom_price_matrix_found_in_cart', $matrix_found, $product, $option_prices );
	}

	public static function get_date_formats() {

		$formats = array(
			'mm/dd/yy'                                  => 'Default - mm/dd/yyyy',
			'dd/mm/yy'                                  => 'dd/mm/yyyy',
			'yy-mm-dd'                                  => 'ISO 8601 - yy-mm-dd',
			'd M, y'                                    => 'Short - d M, y',
			'd MM, y'                                   => 'Medium - d MM, y',
			'd-MM-yy'                                   => 'Military date: d-MM-yy',
			'DD, d MM, yy'                              => 'Full - DD, d MM, yy',
			'\'day\' d \'of\' MM \'in the year\' yy'    => 'With text - \'day\' d \'of\' MM \'in the year\' yy',
			'\'Month\' MM \'day\' d \'in the year\' yy' => 'With text - \'Month\' January \'day\' 7 \'in the year\' yy',
		);

		return apply_filters( 'ppom_date_formats', $formats );
	}

	// Security: checking if attached fields have price
	public static function is_price_attached_with_fields( $fields_posted ) {


		$is_price_attached = false;

		$option_price = 0;
		$ppom_id      = $fields_posted['id'];
		foreach ( $fields_posted as $data_name => $value ) {

			// soon prodcut_id will be removed
			$product_id = null;
			$field_meta = self::get_field_meta_by_dataname( $product_id, $data_name, $ppom_id );
			$field_type = isset( $field_meta['type'] ) ? $field_meta['type'] : '';

			switch ( $field_type ) {

				case 'checkbox':
					if ( is_array( $value ) ) {
						foreach ( $value as $cb_value ) {
							$option_price += self::get_field_option_price( $field_meta, $cb_value );
						}
					}
					break;

				default:
					$option_price += self::get_field_option_price( $field_meta, $value );
					break;
			}
		}

		if ( $option_price > 0 ) {
			$is_price_attached = true;
		}

		// If price matrix attached
		if ( isset( $_POST['ppom']['ppom_pricematrix'] ) ) {
			$is_price_attached = true;
		}

		// exit;

		return apply_filters( 'ppom_option_price_attached', $is_price_attached, $fields_posted, $product_id );
	}

	/**
	 * Builds a legacy ppom_option_price structure from posted field values.
	 *
	 * @param array<string, mixed> $fields_posted Posted ppom[fields] payload.
	 * @param int                  $product_id    Product ID to look up field metadata against.
	 *
	 * @return array<array<string, mixed>> Option-price entries (empty when no priced options match).
	 */
	public static function compute_option_price_from_fields( $fields_posted, $product_id ) {

		$option_prices = array();
		$ppom_id       = isset( $fields_posted['id'] ) ? $fields_posted['id'] : null;

		foreach ( $fields_posted as $data_name => $value ) {

			$field_meta = self::get_field_meta_by_dataname( $product_id, $data_name, $ppom_id );
			if ( empty( $field_meta ) ) {
				continue;
			}

			$apply = ( isset( $field_meta['onetime'] ) && 'on' === $field_meta['onetime'] ) ? 'onetime' : 'variable';

			if ( is_array( $value ) ) {
				foreach ( $value as $cb_value ) {
					$price = self::get_field_option_price( $field_meta, $cb_value );
					if ( 0 != $price ) {
						$option_prices[] = array(
							'apply'     => $apply,
							'price'     => $price,
							'data_name' => $data_name,
						);
					}
				}
			} else {
				$price = self::get_field_option_price( $field_meta, $value );
				if ( 0 != $price ) {
					$option_prices[] = array(
						'apply'     => $apply,
						'price'     => $price,
						'data_name' => $data_name,
					);
				}
			}
		}

		return $option_prices;
	}

	// PPOM Get settings
	public static function get_option( $key, $default_val = false ) {

		if ( self::settings_migrated() ) {

			$value = \PPOM_SettingsFramework::get_saved_settings( $key, $default_val );
		} else {

			$value = get_option( $key );
			if ( ! $value ) {
				$value = $default_val;
			}
		}

		return $value;
	}

	// Checking PPOM version
	public static function get_version() {

		if ( ! defined( 'PPOM_VERSION' ) ) {
			return 16.0;
		}

		return PPOM_VERSION;
	}

	// Checking PPOM Pro version
	public static function get_pro_version() {

		if ( ! defined( 'PPOM_PRO_VERSION' ) ) {
			return 16.0;
		}

		return PPOM_PRO_VERSION;
	}

	// wp_is_mobile wrapper
	public static function is_mobile() {

		if ( ! function_exists( 'wp_is_mobile' ) ) {
			return false;
		}

		return wp_is_mobile();
	}

	// check price calculation mode
	public static function get_price_mode() {

		$price_mode = 'new';
		if ( self::get_option( 'ppom_legacy_price' ) == 'yes' ) {
			$price_mode = 'legacy';
		}

		return apply_filters( 'ppom_price_mode', $price_mode );
	}

	// check client side validation
	public static function is_client_validation_enabled() {

		$validation = false;
		if ( self::get_option( 'ppom_enable_client_validation' ) == 'yes' ) {
			$validation = true;
		}

		return apply_filters( 'ppom_is_client_validation_enabled', $validation );
	}

	public static function get_conditions_mode() {

		$mode = 'new';
		if ( self::get_option( 'ppom_new_conditions' ) == 'yes' ) {
			$mode = 'legacy';
		}

		return apply_filters( 'ppom_new_conditions', $mode );
	}

	public static function get_price_table_calculation() {

		$js_script = 'ppom-price.js';
		if ( self::get_option( 'ppom_price_table_v2' ) == 'yes' ) {
			$js_script = 'ppom-price-v2.js';
		}

		return apply_filters( 'ppom_price_table_script', $js_script );
	}

	/**
	 * Get price table JS dependencies.
	 *
	 * @return string[]
	 */
	public static function get_price_table_js_dependencies() {
		$dependencies = array( 'jquery', 'ppom-inputs' );

		if ( version_compare( WC_VERSION, '10.3.0', '<' ) ) {
			$dependencies[] = 'accounting';
		} else {
			$dependencies[] = 'wc-accounting';
		}

		return $dependencies;
	}

	public static function get_price_table_location() {

		$location = self::get_option( 'ppom_price_table_location', 'after' );

		return apply_filters( 'ppom_price_table_location', $location );
	}


	// some fields like quantities, bulkquantity, eventcalendar has its own
	// price quantity control
	public static function is_cart_quantity_updatable( $product_id ) {

		$qty_updatable = true;

		$ppom = new PPOM_Meta( $product_id );
		if ( ! $ppom->fields ) {
			return $qty_updatable;
		}

		$fields_found = array();
		foreach ( $ppom->fields as $field ) {

			if ( ! isset( $field['type'] ) ) {
				continue;
			}

			// quantities input checking
			$unlinked = isset( $field['unlink_order_qty'] ) ? true : false;

			if ( ( $field['type'] == 'quantities' && ! $unlinked ) ||
			$field['type'] == 'eventcalendar' ||
			$field['type'] == 'vm' ||
			( $field['type'] == 'vqmatrix' && Engine::is_field_has_price( $field ) ) ||
			$field['type'] == 'bulkquantity_zzz'    // bulkquantity should not be in there ... TESTING.
			) {

				$qty_updatable = false;
			}
		}

		return apply_filters( 'ppom_is_cart_quantity_updatable', $qty_updatable, $product_id );
	}


	/**
	 * some fields like vqmatrix, variationmqtrix (vm) should not be updated for order quantity
	 * only use 1
	 * */
	public static function reset_cart_quantity_to_one( $product_id ) {

		$reset_qty = false;

		$ppom = new PPOM_Meta( $product_id );
		if ( ! $ppom->fields ) {
			return $reset_qty;
		}

		$fields_found = array();
		foreach ( $ppom->fields as $field ) {

			if ( ! isset( $field['type'] ) ) {
				continue;
			}

			// quantities input checking
			$unlinked = isset( $field['unlink_order_qty'] ) ? true : false;

			if ( $field['type'] == 'vm' ||
			( $field['type'] == 'quantities' && Engine::is_field_has_price( $field ) && ! $unlinked ) ||
			( $field['type'] == 'vqmatrix' && Engine::is_field_has_price( $field ) )
			) {

				$reset_qty = true;
			}
		}

		return apply_filters( 'ppom_reset_cart_quantity_to_one', $reset_qty, $product_id );
	}

	// Attachhing PPOM Meta with product helper function
	public static function attach_fields_to_product( $ppom_meta_id, $product_id ) {
		$ppom_meta = array( $ppom_meta_id );
		update_post_meta( $product_id, PPOM_PRODUCT_META_KEY, $ppom_meta );
	}

	// Get confirmed dir thumbs
	public static function get_confirmed_dir_thumbs( $order_id, $file_name, $product_id, $thumb = false ) {

		$confirm_dir = 'confirmed/' . $order_id;
		$file_name   = Handler::file_get_name( $file_name, $product_id );

		$file = '';
		if ( $thumb ) {
			$file_path = Handler::get_dir_url() . $confirm_dir . '/' . $file_name;
			$file      = Handler::is_file_image( $file_path ) ? $file_path : PPOM_URL . '/images/file.png';
		} else {
			$file = Handler::get_dir_path( $confirm_dir ) . $file_name;
		}

		return $file;
	}

	// get all editable user
	public static function get_all_editable_roles() {

		// $get_roles = wp_get_editable_roles();

		$get_roles = wp_roles();

		$all_roles = $get_roles->roles;

		// due to issue commenting this out
		// https://wordpress.org/support/topic/fatal-error-uncaught-error-call-to-undefined-function-wp_get_current_user-2/#post-14821195
		// $all_roles = apply_filters('editable_roles', $all_roles);


		$ppom_user_roles = array();
		foreach ( $all_roles as $role => $role_name ) {

			$ppom_user_roles[ $role ] = $role_name['name'];
		}

		return $ppom_user_roles;
	}

	public static function security_role() {

		$action        = false;
		$ppom_security = array();
		$ppom_security = self::get_option( 'ppom_permission_mfields', array() );

		if ( empty( $ppom_security ) ) {
			$ppom_security = array( 0 => 'administrator' );
		}

		foreach ( $ppom_security as $index => $role ) {
			if ( current_user_can( $role ) ) {
				$action = true;
			}
		}


		return $action;
	}

	// generating ppom conditional data attributes
	public static function get_conditional_data_attributes( $meta ) {

		$logic      = isset( $meta['logic'] ) ? self::wpml_translate( $meta['logic'], 'PPOM' ) : '';
		$conditions = isset( $meta['conditions'] ) ? self::wpml_translate( $meta['conditions'], 'PPOM' ) : '';
		$type       = isset( $meta['type'] ) ? self::wpml_translate( $meta['type'], 'PPOM' ) : '';

		$attr_html = '';

		$attr_html .= ' data-type="' . esc_attr( $type ) . '"';
		// self::pa($conditions);


		if ( isset( $conditions['rules'] ) && $logic === 'on' ) {

			$bound      = isset( $conditions['bound'] ) ? self::wpml_translate( $conditions['bound'], 'PPOM' ) : '';
			$visibility = isset( $conditions['visibility'] ) ? self::wpml_translate( $conditions['visibility'], 'PPOM' ) : '';

			$conditions['rules'] = array_filter(
				$conditions['rules'],
				function ( $rule ) {
					if ( empty( $rule['operators'] ) || ! is_string( $rule['operators'] ) ) {
						return ! empty( $rule['element_values'] );
					}

					if ( in_array( $rule['operators'], array( 'any', 'empty', 'even-number', 'odd-number', 'regex' ) ) ) {
						return true;
					}

					if ( in_array( $rule['operators'], array( 'number-multiplier', 'regex', 'contains', 'not-contains' ) ) ) {
						return ! empty( $rule['element_constant'] );
					}

					if ( in_array( $rule['operators'], array( 'greater than', 'less than', 'is', 'not' ) ) ) {
						return ! empty( $rule['element_constant'] ) || ! empty( $rule['element_values'] );
					}

					if ( 'between' === $rule['operators'] ) {
						return (
							! empty( $rule['cond-between-interval'] ) && is_array( $rule['cond-between-interval'] )
							&& isset( $rule['cond-between-interval']['to'] )
							&& isset( $rule['cond-between-interval']['from'] )
						);
					}

					return ! empty( $rule['element_values'] );
				}
			);

			$attr_html .= ' data-cond="1"';
			$attr_html .= ' data-cond-total="' . esc_attr( count( $conditions['rules'] ) ) . '"';
			$attr_html .= ' data-cond-bind="' . esc_attr( $bound ) . '"';
			$attr_html .= ' data-cond-visibility="' . esc_attr( strtolower( $visibility ) ) . '"';

			$index       = 0;
			$pro_enabled = self::pro_is_installed() && 'valid' === apply_filters( 'product_ppom_license_status', '' );

			foreach ( $conditions['rules'] as $rule ) {

				$counter      = ++$index;
				$input        = 'input' . $counter;
				$value        = 'val' . $counter;
				$opr          = 'operator' . $counter;
				$element      = isset( $rule['elements'] ) ? self::wpml_translate( $rule['elements'], 'PPOM' ) : '';
				$element_val  = isset( $rule['element_values'] ) ? self::wpml_translate( $rule['element_values'], 'PPOM' ) : '';
				$constant_val = isset( $rule['element_constant'] ) ? self::wpml_translate( $rule['element_constant'], 'PPOM' ) : '';
				$operator     = isset( $rule['operators'] ) ? self::wpml_translate( $rule['operators'], 'PPOM' ) : '';

				$attr_html .= ' data-cond-' . $input . '="' . esc_attr( $element ) . '"';
				$attr_html .= ' data-cond-' . $value . '="' . esc_attr( $element_val ) . '"';
				$attr_html .= ' data-cond-' . $opr . '="' . esc_attr( $operator ) . '"';

				if ( $pro_enabled && ! empty( $constant_val ) ) {
					$attr_html .= ' data-cond-constant-val-' . $counter . '="' . esc_attr( $constant_val ) . '"';
				}

				if ( $pro_enabled && 'between' === $operator && isset( $rule['cond-between-interval'] ) ) {
					$attr_html .= ' data-cond-between-from-' . $counter . '="' . esc_attr( $rule['cond-between-interval']['from'] ) . '"';
					$attr_html .= ' data-cond-between-to-' . $counter . '="' . esc_attr( $rule['cond-between-interval']['to'] ) . '"';
				}
			}
		}

		return apply_filters( 'ppom_field_conditions', $attr_html, $meta );
	}

	// Check if given type is an addon
	public static function is_field_addon( $type ) {

		$ppom_meta = Settings::get_plugin_meta();

		$is_addon = false;
		if ( isset( $ppom_meta[ $type ] ) && $ppom_meta[ $type ]['is_addon'] ) {
			$is_addon = true;
		}

		return $is_addon;
	}

	public static function is_legacy_mode() {

		$is_legacy     = false;
		$enable_legacy = self::get_option( 'ppom_enable_legacy_inputs_rendering' );
		if ( $enable_legacy == 'yes' ) {
			$is_legacy = true;
		}

		return $is_legacy;
	}

	// Checking settings migrations
	public static function settings_migrated() {

		$r = get_option( 'ppom_settings_migration_done' );

		return $r != null ? true : false;
	}

	/**
	 * PPOM Check Pro Feature Compatibility
	 *
	 * @param  string $feature_slug That represents feature key to look the if there is a compatibility.
	 * @return bool
	 */
	public static function check_pro_compatibility( $feature_slug ) {
		if ( ! defined( 'PPOM_PRO_COMPATIBILITY_FEATURES' ) || ! is_array( PPOM_PRO_COMPATIBILITY_FEATURES ) ) {
			return false;
		}

		return isset( PPOM_PRO_COMPATIBILITY_FEATURES[ $feature_slug ] ) && PPOM_PRO_COMPATIBILITY_FEATURES[ $feature_slug ];
	}

	/**
	 * Check is legacy user.
	 *
	 * @return bool
	 */
	public static function is_legacy_user() {
		if ( self::pro_is_installed() && ( function_exists( '\PPOM_Pro\get_license_status' ) && 'valid' === \PPOM_Pro\get_license_status( false ) ) ) {
			return false;
		}
		return 'no' === get_option( 'ppom_legacy_user', '' );
	}

	/**
	 * Validate max and min value.
	 *
	 * @param array<string, mixed> $posted_fields Posted fields data.
	 * @param array<string, mixed> $field        Field meta data.
	 * @return string Validation message if validation fails, empty string otherwise.
	 */
	public static function posted_field_max_min_value_validation( $posted_fields, $field ) {
		if ( empty( $field['max_checked'] ) && empty( $field['min_checked'] ) ) {
			return '';
		}

		$data_name     = isset( $field['data_name'] ) ? sanitize_key( $field['data_name'] ) : '';
		$title         = isset( $field['title'] ) ? sanitize_text_field( $field['title'] ) : '';
		$min_check     = isset( $field['min_checked'] ) ? intval( $field['min_checked'] ) : 0;
		$max_check     = isset( $field['max_checked'] ) ? intval( $field['max_checked'] ) : 0;
		$error_message = isset( $field['error_message'] ) ? sanitize_text_field( $field['error_message'] ) : '';

		if ( $min_check ) {
			$has_field_value = isset( $posted_fields[ $data_name ] );
			if ( ! $has_field_value ) {
				foreach ( $posted_fields as $field_key => $field_value ) {
					$field_key = explode( '__clone_', $field_key );
					if ( in_array( $data_name, $field_key, true ) ) {
						$has_field_value = true;
						break;
					}
				}
			}
			if ( ! $has_field_value ) {
				$message = '' !== $error_message
				? sprintf( '%1$s: %2$s', $title, $error_message )
				: sprintf(
					// translators: %1$s is minimum checked value, %2$s is Field label.
					__( 'You must select at least %1$s options for %2$s field.', 'woocommerce-product-addon' ),
					$min_check,
					$title
				);
				return apply_filters( 'ppom_posted_field_min_value_validation_message', $message, $posted_fields, $field );
			}
		}

		foreach ( $posted_fields as $field_key => $field_value ) {
			$field_key = explode( '__clone_', $field_key );

			if ( in_array( $data_name, $field_key, true ) && is_array( $field_value ) ) {
				$count = count( $field_value );
				if ( $max_check && $count > $max_check ) {
					$message = '' !== $error_message
						? sprintf( '%1$s: %2$s', $title, $error_message )
						: sprintf(
							// translators: %1$s is maximum checked value, %2$s is Field label
							__( 'You can select maximum %1$s options for %2$s field.', 'woocommerce-product-addon' ),
							$max_check,
							$title
						);
					return apply_filters( 'ppom_posted_field_max_value_validation_message', $message, $posted_fields, $field );
				} elseif ( $min_check && $count < $min_check ) {
					$message = '' !== $error_message
						? sprintf( '%1$s: %2$s', $title, $error_message )
						: sprintf(
							// translators: %1$s is minimum checked value, %2$s is Field label
							__( 'You must select at least %1$s options for %2$s field.', 'woocommerce-product-addon' ),
							$min_check,
							$title
						);
					return apply_filters( 'ppom_posted_field_min_value_validation_message', $message, $posted_fields, $field );
				}
			}
		}

		return '';
	}

	/**
	 * Get image name from images array.
	 *
	 * @param mixed $images
	 * @return string
	 */
	public static function get_image_name( $images ) {
		$updated_value = '';

		if ( is_array( $images ) ) {
			$total_images = count( $images );

			foreach ( $images as $image_key => $image ) {
				$image_data = json_decode( stripslashes( $image ), true );
				if ( isset( $image_data['raw'] ) ) {
					$updated_value .= $image_data['raw'];
				}

				if ( $image_key < $total_images - 1 ) {
					$updated_value .= ', ';
				}
			}
		}

		return $updated_value;
	}

	/**
	 * Get file uploader notice text based on field meta.
	 *
	 * @param \PPOM_InputManager $meta_field Meta field object.
	 * @return string Notice text to display for file uploader field.
	 */
	public static function get_file_uploader_notice( $meta_field ) {
		$file_types = $meta_field->get_meta_value( 'file_types' );
		$file_size  = $meta_field->get_meta_value( 'file_size' );

		$notice = '';
		if ( $file_types ) {
			$notice = sprintf(
				// translators: %s is the accepted file types.
				__( 'Accepted formats: %s.', 'woocommerce-product-addon' ),
				esc_html( strtoupper( $file_types ) )
			);
		}
		if ( $file_size ) {
			$notice .= ' ' . sprintf(
				// translators: %s is the maximum file size.
				__( 'Max size: %s', 'woocommerce-product-addon' ),
				esc_html( strtoupper( $file_size ) )
			);
		}

		return $notice;
	}
}
