<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}

final class WOOBE_BULK extends WOOBE_EXT {

	protected $slug    = 'bulk'; // unique
	public $text_keys  = array();
	public $num_keys   = array();
	public $other_keys = array();

	public function __construct() {

		$this->init_bulk_keys();

		add_action( 'woobe_ext_scripts', array( $this, 'woobe_ext_scripts' ), 1 );
		add_action( 'woobe_tools_panel_buttons_end', array( $this, 'woobe_tools_panel_buttons_end' ), 1 );

		// ajax
		add_action( 'wp_ajax_woobe_bulk_products_count', array( $this, 'woobe_bulk_products_count' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_products', array( $this, 'woobe_bulk_products' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_finish', array( $this, 'woobe_bulk_finish' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_draw_gallery_btn', array( $this, 'woobe_bulk_draw_gallery_btn' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_draw_download_files_btn', array( $this, 'woobe_bulk_draw_download_files_btn' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_draw_cross_sells_btn', array( $this, 'woobe_bulk_draw_cross_sells_btn' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_draw_upsell_ids_btn', array( $this, 'woobe_bulk_draw_upsell_ids_btn' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_draw_grouped_ids_btn', array( $this, 'woobe_bulk_draw_grouped_ids_btn' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_get_att_terms', array( $this, 'woobe_bulk_get_att_terms' ), 1 );

		add_action( 'wp_ajax_woobe_bulk_delete_products_count', array( $this, 'woobe_bulk_delete_products_count' ), 1 );
		add_action( 'wp_ajax_woobe_bulk_delete_products', array( $this, 'woobe_bulk_delete_products' ), 1 );

		add_action( 'woobe_bulk_going', array( $this, 'woobe_bulk_going' ), 10, 2 );

		// tabs
		$this->add_tab( $this->slug, 'top_panel', esc_html__( 'Bulk Edit', 'woo-bulk-editor' ), 'pencil' );
		add_action( 'woobe_ext_top_panel_' . $this->slug, array( $this, 'woobe_ext_panel' ), 1 );
	}

	public function woobe_ext_scripts() {
		wp_enqueue_script( 'woobe_ext_' . $this->slug, $this->get_ext_link() . 'assets/js/' . $this->slug . '.js', array(), WOOBE_VERSION, false );
		wp_enqueue_style( 'woobe_ext_' . $this->slug, $this->get_ext_link() . 'assets/css/' . $this->slug . '.css', array(), WOOBE_VERSION );
		?>
		<script>
			lang.<?php echo esc_attr( $this->slug ); ?> = {};
			lang.<?php echo esc_attr( $this->slug ); ?>.want_to_bulk = "<?php echo esc_html__( 'Will be edited next:', 'woo-bulk-editor' ); ?>";
			lang.<?php echo esc_attr( $this->slug ); ?>.want_to_delete = "<?php echo esc_html__( 'Sure? Delete products?', 'woo-bulk-editor' ); ?>";
			lang.<?php echo esc_attr( $this->slug ); ?>.deleting = "<?php echo esc_html__( 'Bulk deleting', 'woo-bulk-editor' ); ?>";
			lang.<?php echo esc_attr( $this->slug ); ?>.deleted = "<?php echo esc_html__( 'Product(s) deleted!', 'woo-bulk-editor' ); ?>";
			lang.<?php echo esc_attr( $this->slug ); ?>.bulking = "<?php echo esc_html__( 'Bulk editing', 'woo-bulk-editor' ); ?> ...";
			lang.<?php echo esc_attr( $this->slug ); ?>.bulked = "<?php echo esc_html__( 'Product(s) edited! Table redrawing ...', 'woo-bulk-editor' ); ?>";
			lang.<?php echo esc_attr( $this->slug ); ?>.bulked2 = "<?php echo esc_html__( 'Product(s) edited!', 'woo-bulk-editor' ); ?>";
			lang.<?php echo esc_attr( $this->slug ); ?>.bulk_is_going = "<?php echo esc_html__( 'ATTENTION: Bulk operation is going!', 'woo-bulk-editor' ); ?>";
			lang.<?php echo esc_attr( $this->slug ); ?>.attention_all_products = "<?php echo esc_html__( 'ATTENTION: You have not applied a filter and have not selected any products. This operation will be applied to all products in your database.', 'woo-bulk-editor' ); ?>";
		</script>
		<?php
	}

	public function woobe_tools_panel_buttons_end() {
		global $WOOBE;
		?>
		&nbsp;|&nbsp;<span>
			<?php
			WOOBE_HELPER::draw_advanced_switcher_e(
				0,
				'woobe_bind_editing',
				'',
				array(
					'true'  => esc_html__( 'binded editing', 'woo-bulk-editor' ),
					'false' => esc_html__( 'binded editing', 'woo-bulk-editor' ),
				),
				array(
					'true'  => 1,
					'false' => 0,
				),
				'js_check_woobe_bind_editing',
				'woobe_bind_editing'
			);
			?>

			<?php
			$bind_tooltip = '';
			if ( $WOOBE->show_notes ) {
				$fields = $WOOBE->settings->get_fields();
				if ( ! empty( $fields ) ) {
					$bind_tooltip = array();
					foreach ( $fields as $field_key => $f ) {
						if ( $f['direct'] ) {
							$t = wp_strip_all_tags( $f['title'] );
							if ( ! empty( $t ) and $field_key != 'ID' ) {
								$bind_tooltip[] = $t;
							}
						}
					}

					// translators: %s: comma-separated list of field names.
					$bind_tooltip = sprintf( esc_html__( 'In FREE version of the plugin you can change only next fields: %s', 'woo-bulk-editor' ), implode( ', ', $bind_tooltip ) );
				}
			}
			?>

			<?php WOOBE_HELPER::draw_tooltip( esc_html__( 'In this mode to the all selected products will be set the value of a product field which been edited', 'woo-bulk-editor' ) . '. ' . $bind_tooltip ); ?>

		</span>
		<?php
	}

	public function woobe_ext_panel() {
		$data                            = array();
		$data['shop_manager_visibility'] = $this->settings->get_shop_manager_visibility();
		$data['text_keys']               = $this->text_keys;
		$data['num_keys']                = $this->num_keys;
		$data['other_keys']              = $this->other_keys;
		$data['settings_fields']         = $this->settings->get_fields();
		WOOBE_HELPER::render_html_e( $this->get_ext_path() . 'views/panel.php', $data );
	}

	// ajax
	public function woobe_bulk_products_count() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			die( '0' );
		}

		if ( ! isset( $_REQUEST['bulk_form_nonce'] ) || ! wp_verify_nonce( $_REQUEST['bulk_form_nonce'], 'woobe_bulk_form_nonce' ) ) {
			die( '0' );
		}
		// ***

		$bulk_data = array();

		if ( ! isset( $_REQUEST['woobe_bind_editing'] ) ) {
			parse_str( $_REQUEST['bulk_data'], $bulk_data );
			$bulk_data = WOOBE_HELPER::sanitize_array( $bulk_data );
		} else {
			// binded editing operation works
			if ( is_array( $_REQUEST['val'] ) ) {
				$value = WOOBE_HELPER::sanitize_array( $_REQUEST['val'] );
			} else {
				$value = wp_kses( $_REQUEST['val'], wp_kses_allowed_html( 'post' ) );
				$value = str_replace( '&amp;', '&', $value );
			}

			$field_key = sanitize_text_field( $_REQUEST['field'] );

			// ***

			$bulk_data['woobe_bulk'] = array(
				'is'       => array(
					$field_key => 1,
				),
				$field_key => array(
					'value'    => $value,
					'behavior' => sanitize_text_field( $_REQUEST['behavior'] ),
				),
			);
		}

		$ids = $this->count_products_before_bulk( $_REQUEST['bulk_key'], $bulk_data['woobe_bulk'], isset( $_REQUEST['no_filter'] ) );
		echo json_encode( $ids );

		exit;
	}

	public function count_products_before_bulk( $bulk_key, $woobe_bulk, $no_filter = true ) {
		$this->storage->set_val( 'woobe_bulk_' . WOOBE_HELPER::sanitize_bulk_key( $bulk_key ), $woobe_bulk );

		$ids = array();

		if ( ! $no_filter ) {
			// get count of filtered - doesn work if bulk for checked products
			$products = $this->products->gets(
				array(
					'fields'        => 'ids',
					'no_found_rows' => true,
				)
			);

			$ids = $products->posts;
		}

		// ***

		do_action( 'woobe_bulk_started', WOOBE_HELPER::sanitize_bulk_key( $bulk_key ) );
		return $ids;
	}

	public function woobe_bulk_delete_products_count() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			die( '0' );
		}
		if ( ! isset( $_REQUEST['bulk_form_nonce'] ) || ! wp_verify_nonce( $_REQUEST['bulk_form_nonce'], 'woobe_bulk_form_nonce' ) ) {
			die( '0' );
		}
		$bulk_data = array();

		if ( ! isset( $_REQUEST['woobe_bind_editing'] ) ) {
			parse_str( $_REQUEST['bulk_data'], $bulk_data );
			$bulk_data = WOOBE_HELPER::sanitize_array( $bulk_data );
		} else {
			// binded editing operation works
			if ( is_array( $_REQUEST['val'] ) ) {
				$value = WOOBE_HELPER::sanitize_array( $_REQUEST['val'] );
			} else {
				$value = wp_kses( $_REQUEST['val'], wp_kses_allowed_html( 'post' ) );
			}

			$field_key = sanitize_text_field( $_REQUEST['field'] );

			// ***

			$bulk_data['woobe_bulk'] = array(
				'is'       => array(
					$field_key => 1,
				),
				$field_key => array(
					'value'    => $value,
					'behavior' => sanitize_text_field( $_REQUEST['behavior'] ),
				),
			);
		}

		$this->storage->set_val( 'woobe_bulk_' . WOOBE_HELPER::sanitize_bulk_key( $_REQUEST['bulk_key'] ), $bulk_data['woobe_bulk'] );

		if ( ! isset( $_REQUEST['no_filter'] ) ) {
			// get count of filtered - doesn work if bulk for checked products
			$products = $this->products->gets(
				array(
					'fields'        => 'ids',
					'no_found_rows' => true,
				)
			);
			echo json_encode( $products->posts );
		}

		exit;
	}

	public function woobe_bulk_delete_products() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			die( '0' );
		}
		if ( ! isset( $_REQUEST['products_ids'] ) ) {
			die( '0' );
		}

		if ( ! isset( $_REQUEST['bulk_form_nonce'] ) || ! wp_verify_nonce( $_REQUEST['bulk_form_nonce'], 'woobe_bulk_form_nonce' ) ) {
			die( '0' );
		}

		if ( is_array( $_REQUEST['products_ids'] ) ) {
			$is_variations_solo = intval( $_REQUEST['woobe_show_variations'] );

			$products_ids = array_map(
				function ( $item ) {
					return intval( $item ); // sanitize intval
				},
				$_REQUEST['products_ids']
			);

			// as we want to change variations only but have ids of parents - lets get variations ids
			if ( $is_variations_solo and ! empty( $products_ids ) ) {
				$vars_ids = array();
				foreach ( $products_ids as $product_id ) {
					$product = $this->products->get_product( $product_id );
					if ( $product->is_type( 'variable' ) ) {
						$children = $product->get_children();
						if ( ! empty( $children ) ) {
							$vars_ids = array_merge( $vars_ids, $children );
						}
					}
				}
				$products_ids = array_unique( array_merge( $products_ids, $vars_ids ) );
			}
			$woobe_bulk = $this->storage->get_val( 'woobe_bulk_' . WOOBE_HELPER::sanitize_bulk_key( $_REQUEST['bulk_key'] ) );

			foreach ( $products_ids as $id ) {
				if ( $is_variations_solo ) {

					// lets check that currenct variation has the same attributes combination
					if ( isset( $woobe_bulk['combination_attributes'] ) and ! empty( $woobe_bulk['combination_attributes'] ) ) {

						$variation  = $this->products->get_product( $id );
						$attributes = $variation->get_attributes();

						// ***

						$go = false;

						// ***

						if ( ! empty( $attributes ) ) {
							foreach ( $woobe_bulk['combination_attributes'] as $comb ) {
								// lets look is $attributes the same set of attributes as in $comb
								$ak_att = array_keys( $attributes );
								$ak_cv  = array_keys( $comb );

								// fix for non-latin symbols
								if ( ! empty( $ak_att ) ) {
									$ak_att = array_map( 'urldecode', $ak_att );
								}

								// fix for non-latin symbols
								if ( ! empty( $ak_cv ) ) {
									$ak_cv = array_map( 'urldecode', $ak_cv );
								}

								sort( $ak_att );
								sort( $ak_cv );

								if ( $ak_att === $ak_cv ) {

									$new_attributes = $attributes;
									$new_comb       = $comb;
									if ( in_array( '-1', $comb ) ) {
										$delete_keys = array_keys( $comb, '-1', );

										foreach ( $delete_keys as $d_key ) {
											if ( isset( $new_attributes[ $d_key ] ) ) {
												unset( $new_attributes[ $d_key ] );
												unset( $new_comb[ $d_key ] );
											}
										}
									}

									$av_att = array_values( $new_attributes );
									$av_cv  = array_values( $new_comb );

									// fix for non-latin symbols
									if ( ! empty( $ak_att ) ) {
										$av_att = array_map( 'urldecode', $av_att );
									}

									if ( ! empty( $av_cv ) ) {
										$av_cv = array_map( 'urldecode', $av_cv );
									}

									sort( $av_att );
									sort( $av_cv );

									if ( $av_att === $av_cv ) {
										$go = true;
										break;
									}
								}
							}
						}

						// ***

						if ( ! $go ) {
							continue;
						}
					}
				}
				// wp_delete_post($id,false);
				wp_trash_post( intval( $id ) );
			}
		} else {
			die( '0' );
		}

		die( json_encode( $_REQUEST['products_ids'] ) );
		exit;
	}

	// ajax
	public function woobe_bulk_products() {
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			die( '0' );
		}

		if ( ! isset( $_REQUEST['products_ids'] ) ) {
			die( '0' );
		}
		if ( ! isset( $_REQUEST['bulk_form_nonce'] ) || ! wp_verify_nonce( $_REQUEST['bulk_form_nonce'], 'woobe_bulk_form_nonce' ) ) {
			die( '0' );
		}

		$bulk_key   = WOOBE_HELPER::sanitize_bulk_key( $_REQUEST['bulk_key'] );
		$woobe_bulk = $this->storage->get_val( 'woobe_bulk_' . $bulk_key );

		$this->do_bulk(
			$bulk_key,
			$_REQUEST['products_ids'],
			$woobe_bulk,
			intval( $_REQUEST['woobe_show_variations'] )
		);

		die( 'done' );
	}

	public function do_bulk( $bulk_key, $products_ids, $woobe_bulk, $is_variations_solo = 0 ) {
		$fields = $this->settings->get_fields();
		// key for history bulk opearation, not related to products keys
		$_REQUEST['woobe_bulk_key'] = $bulk_key;
		// as we want to change variations only but have ids of parents - lets get variations ids
		if ( $is_variations_solo and ! empty( $products_ids ) ) {
			$vars_ids = array();
			foreach ( $products_ids as $product_id ) {
				$product_id = intval( $product_id ); // sanitize

				$product = $this->products->get_product( $product_id );
				if ( $product->is_type( 'variable' ) ) {
					$children = $product->get_children();
					if ( ! empty( $children ) ) {
						$vars_ids = array_merge( $vars_ids, $children );
					}
				}
			}

			$products_ids = array_unique( array_merge( $products_ids, $vars_ids ) );
		}

		// ***

		if ( isset( $woobe_bulk['is'] ) and ! empty( $woobe_bulk['is'] ) and ! empty( $products_ids ) ) {

			// ***

			foreach ( $woobe_bulk['is'] as $field_key => $is ) {

				if ( $fields[ $field_key ]['edit_view'] === 'calendar' ) {
					if ( ! is_int( $woobe_bulk[ $field_key ]['value'] ) and ( isset( $fields[ $field_key ]['field_type'] ) and $fields[ $field_key ]['field_type'] == 'meta' ) ) {
						$woobe_bulk[ $field_key ]['value'] = strtotime( $woobe_bulk[ $field_key ]['value'] ); // - wrong way
					} else {
						$woobe_bulk[ $field_key ]['value'] = $this->products->normalize_calendar_date( $woobe_bulk[ $field_key ]['value'], $field_key );
					}
				}

				// ***
				// speedfix
				wp_defer_term_counting( false );
				wp_defer_comment_counting( true );

				// ***

				if ( intval( $is ) === 1 ) {

					foreach ( $products_ids as $product_id ) {

						if ( $is_variations_solo ) {
							// if enabled editing of variations only parent-products are ignored
							$product = $this->products->get_product( $product_id );
							if ( ! $product->is_type( 'variation' ) ) {
								continue;
							}

							// lets check that currenct variation has the same attributes combination
							if ( isset( $woobe_bulk['combination_attributes'] ) and ! empty( $woobe_bulk['combination_attributes'] ) ) {

								$variation  = $this->products->get_product( $product_id );
								$attributes = $variation->get_attributes();

								// ***

								$go = false;

								// ***

								if ( ! empty( $attributes ) ) {
									foreach ( $woobe_bulk['combination_attributes'] as $comb ) {
										// lets look is $attributes the same set of attributes as in $comb
										$ak_att = array_keys( $attributes );
										$ak_cv  = array_keys( $comb );

										// fix for non-latin symbols
										if ( ! empty( $ak_att ) ) {
											$ak_att = array_map( 'urldecode', $ak_att );
										}

										// fix for non-latin symbols
										if ( ! empty( $ak_cv ) ) {
											$ak_cv = array_map( 'urldecode', $ak_cv );
										}

										sort( $ak_att );
										sort( $ak_cv );

										if ( $ak_att === $ak_cv ) {
											$new_attributes = $attributes;
											$new_comb       = $comb;
											if ( in_array( '-1', $comb ) ) {
												$delete_keys = array_keys( $comb, '-1', );

												foreach ( $delete_keys as $d_key ) {
													if ( isset( $new_attributes[ $d_key ] ) ) {
														unset( $new_attributes[ $d_key ] );
														unset( $new_comb[ $d_key ] );
													}
												}
											}

											$av_att = array_values( $new_attributes );
											$av_cv  = array_values( $new_comb );

											// fix for non-latin symbols
											if ( ! empty( $ak_att ) ) {
												$av_att = array_map( 'urldecode', $av_att );
											}

											if ( ! empty( $av_cv ) ) {
												$av_cv = array_map( 'urldecode', $av_cv );
											}

											sort( $av_att );
											sort( $av_cv );
											if ( $av_att === $av_cv ) {
												$go = true;
												break;
											}
										}
									}
								}

								// ***

								if ( ! $go ) {
									continue;
								}
							}
						}

						// ***

						switch ( $field_key ) {
							case 'post_title':
							case 'post_content':
							case 'post_excerpt':
							case 'post_name':
							case 'purchase_note':
							case 'sku':
							case 'tax_class':
							case 'backorders':
							case 'sold_individually':
							case 'reviews_allowed':
							case 'product_url':
							case 'button_text':
								$this->_process_text_data( $woobe_bulk, $field_key, $product_id );
								break;

							case 'post_status':
							case 'stock_status':
							case 'manage_stock':
							case 'tax_status':
							case 'catalog_visibility':
							case 'product_type':
							case 'featured':
							case 'virtual':
							case 'downloadable':
							case 'download_files':
							case 'gallery':
							case 'upsell_ids':
							case 'cross_sell_ids':
							case 'grouped_ids':
							case 'post_date':
								if ( intval( $woobe_bulk[ $field_key ]['value'] ) !== -1 ) {
									$this->products->update_page_field( $product_id, $field_key, $woobe_bulk[ $field_key ]['value'] );
								}
								break;
							case 'attribute_visibility':
								if ( ! isset( $woobe_bulk[ $field_key ]['value'] ) or ! is_array( $woobe_bulk[ $field_key ]['value'] ) ) {

									$woobe_bulk[ $field_key ]['value'] = array();
								}
								if ( ! isset( $woobe_bulk[ $field_key ]['visible'] ) ) {
									$woobe_bulk[ $field_key ]['visible'] = 1;
								}
								$this->products->set_product_attributes_visible( $product_id, $woobe_bulk[ $field_key ]['value'], $woobe_bulk[ $field_key ]['visible'] );

								break;
							case 'regular_price':
							case 'sale_price':
							case 'stock_quantity':
							case 'download_expiry':
							case 'download_limit':
							case 'date_on_sale_from':
							case 'date_on_sale_to':
							case 'weight':
							case 'length':
							case 'width':
							case 'height':
							case 'product_shipping_class':
							case 'menu_order':
							case 'post_author':
							case 'total_sales':
							case 'review_count':
							case 'average_rating':
								$this->_process_number_data( $woobe_bulk, $field_key, $product_id );
								break;

							default:
								break;
						}

						// ***

						if ( isset( $fields[ $field_key ] ) and $fields[ $field_key ]['field_type'] === 'taxonomy' ) {
							// if (!empty($woobe_bulk[$field_key]['value'])) {
							do_action( 'woobe_before_update_page_field', $field_key, $product_id, 0 ); // for the History
							if ( ! isset( $woobe_bulk[ $field_key ]['behavior'] ) ) {
								$woobe_bulk[ $field_key ]['behavior'] = '';
							}
							switch ( $woobe_bulk[ $field_key ]['behavior'] ) {
								case 'append':
									if ( is_taxonomy_hierarchical( $field_key ) ) {
										wp_set_post_terms( $product_id, $woobe_bulk[ $field_key ]['value'], $field_key, true );
									} else {
										// product_tag for example
										foreach ( $woobe_bulk[ $field_key ]['value'] as $term_id ) {
											$t = get_term_by( 'id', $term_id, $field_key );
											wp_set_post_terms( $product_id, $t->slug, $field_key, true );
										}
									}
									break;
								case 'replace':
								case 'new':
									if ( is_taxonomy_hierarchical( $field_key ) ) {
										wp_set_post_terms( $product_id, $woobe_bulk[ $field_key ]['value'], $field_key, false );
									} else {
										// product_tag for example
										$append = false; // clean previous by first one then append
										if ( ! empty( $woobe_bulk[ $field_key ]['value'] ) and is_array( $woobe_bulk[ $field_key ]['value'] ) ) {
											foreach ( $woobe_bulk[ $field_key ]['value'] as $term_id ) {
												$t = get_term_by( 'id', $term_id, $field_key );
												wp_set_post_terms( $product_id, $t->slug, $field_key, $append );
												$append = true;
											}
										}
									}
									break;
								case 'remove':
									foreach ( $woobe_bulk[ $field_key ]['value'] as $term_id ) {
										$t = get_term_by( 'id', $term_id, $field_key );
										wp_remove_object_terms( $product_id, $t->slug, $field_key );
									}
									break;
							}
							// }
						}

						// ***

						if ( isset( $fields[ $field_key ] ) and $fields[ $field_key ]['field_type'] === 'attribute' ) {
							if ( ! isset( $woobe_bulk[ $field_key ]['value'] ) ) {
								$woobe_bulk[ $field_key ]['value'] = '';
							}
							do_action( 'woobe_before_update_page_field', $field_key, $product_id, 0 ); // for the History
							$this->products->set_product_attributes( $product_id, $field_key, $woobe_bulk[ $field_key ]['value'], $woobe_bulk[ $field_key ]['behavior'] );
						}

						// ***

						if ( isset( $fields[ $field_key ] ) and $fields[ $field_key ]['field_type'] === 'meta' ) {
							switch ( $fields[ $field_key ]['type'] ) {
								case 'string':
									// if data is serialized in ine string
									if ( $fields[ $field_key ]['edit_view'] == 'meta_popup_editor' ) {
										if ( ! is_array( $woobe_bulk[ $field_key ]['value'] ) ) {

											// if not else parsed
											parse_str( $woobe_bulk[ $field_key ]['value'], $meta_val );

											$woobe_bulk[ $field_key ]['value'] = $this->products->process_jsoned_meta_data( $meta_val );
										}
									}
									// ***
									if ( $fields[ $field_key ]['edit_view'] == 'gallery_popup_editor' ) {

										if ( ! is_array( $woobe_bulk[ $field_key ]['value'] ) ) {
											// if not else parsed
											parse_str( $woobe_bulk[ $field_key ]['value'], $meta_val );
											if ( ! empty( $meta_val['woobe_gallery_images'] ) ) {
												$woobe_bulk[ $field_key ]['value'] = $meta_val;
											}
										}
									}
									// ***

									if ( $fields[ $field_key ]['edit_view'] !== 'switcher' ) {
										$this->_process_text_data( $woobe_bulk, $field_key, $product_id );
									} elseif ( intval( $woobe_bulk[ $field_key ]['value'] ) !== -1 ) {
											$this->products->update_page_field( $product_id, $field_key, intval( $woobe_bulk[ $field_key ]['value'] ) );
									}
									break;

								case 'number':
									$this->_process_number_data( $woobe_bulk, $field_key, $product_id );
									break;

								default:
									break;
							}
						}
					}
				}
			}

			do_action( 'woobe_bulk_going', sanitize_text_field( $_REQUEST['woobe_bulk_key'] ), count( $products_ids ) );
		}
	}

	public function woobe_bulk_going( $bulk_key, $products_count ) {
		$count_key = 'woobe_bulk_' . strtolower( $bulk_key ) . '_count';
		$count_now = intval( $this->storage->get_val( $count_key ) );
		$this->storage->set_val( $count_key, $products_count + $count_now );
	}

	private function _process_text_data( $woobe_bulk, $field_key, $product_id ) {
		$val = $this->products->get_post_field( $product_id, $field_key );

		// Auto-increment SKU: supports patterns like "10300+", "10300+5", "PREFIX-10300+", "PREFIX-10300+5"
		// Syntax: {prefix}{number}+{step} where prefix and step are optional, step defaults to 1
		if ( apply_filters( 'woobe_sku_auto_increment', true ) && $field_key === 'sku' && isset( $woobe_bulk[ $field_key ]['value'] ) && preg_match( '/^(.*?)(\d+)\+(\d*)$/', $woobe_bulk[ $field_key ]['value'], $matches ) ) {
			static $woobe_sku_counter = null; // current counter value
			static $woobe_sku_pattern = null; // last seen pattern, used to detect new bulk run
			static $woobe_sku_step    = 1;       // increment step

			$sku_prefix = $matches[1];           // e.g. "ABC-" or "" if none
			$sku_start  = intval( $matches[2] );    // e.g. 10300
			$sku_step   = ! empty( $matches[3] ) ? intval( $matches[3] ) : 1; // e.g. 5, default 1

			$pattern_key = $woobe_bulk[ $field_key ]['value'];

			// Reset counter when a new bulk operation starts (new pattern detected)
			if ( $woobe_sku_pattern !== $pattern_key ) {
				$woobe_sku_counter = $sku_start;
				$woobe_sku_pattern = $pattern_key;
				$woobe_sku_step    = $sku_step;
			}

			// Increment first - direct cell edit already saved the start number
			$woobe_sku_counter += $woobe_sku_step;

			// Override the value with the generated sequential SKU
			$woobe_bulk[ $field_key ]['value'] = $sku_prefix . $woobe_sku_counter;
		}

		// +++

		$woobe_bulk[ $field_key ]['value'] = $this->products->string_macros( $woobe_bulk[ $field_key ]['value'], $field_key, $product_id );
		switch ( $woobe_bulk[ $field_key ]['behavior'] ) {
			case 'append':
				$val = $this->products->string_replacer( $val . $woobe_bulk[ $field_key ]['value'], $product_id );
				break;
			case 'prepend':
				$val = $this->products->string_replacer( $woobe_bulk[ $field_key ]['value'] . $val, $product_id );
				break;
			case 'new':
				$val = $this->products->string_replacer( $woobe_bulk[ $field_key ]['value'], $product_id );
				break;
			case 'replace':
				$replace_to   = $this->products->string_replacer( $woobe_bulk[ $field_key ]['replace_to'], $product_id );
				$replace_from = $this->products->string_replacer( $woobe_bulk[ $field_key ]['value'], $product_id );

				// fix  for  apostrophe
				$replace_from = str_replace( "\'", "'", $replace_from );

				if ( $woobe_bulk[ $field_key ]['case'] == 'ignore' ) {
					$val = str_ireplace( $replace_from, $replace_to, $val );
				} else {
					$val = str_replace( $replace_from, $replace_to, $val );
					/*
					 * https://stackoverflow.com/questions/19317493/php-preg-replace-case-insensitive-match-with-case-sensitive-replacement
						$val = preg_replace_callback('/\b' . $replace_from . '\b/i', function($matches) use ($replace_to) {
						$i = 0;
						return join('', array_map(function($char) use ($matches, &$i) {
						return ctype_lower($matches[0][$i++]) ? strtolower($char) : strtoupper($char);
						}, str_split($replace_to)));
						}, $val);
					 *
					 */
				}

				break;
		}

		// ***
		$empty_exceptions = array( 'tax_class' ); // setting empty values is possible with this fields

		$can = true; // !empty($val);

		if ( in_array( $field_key, $empty_exceptions ) ) {
			$can = true;
		}

		if ( $can ) {

			$val = $this->products->update_page_field( $product_id, $field_key, $val );
		}
	}

	private function _process_number_data( $woobe_bulk, $field_key, $product_id ) {
		if ( $woobe_bulk[ $field_key ]['behavior'] != 'new' ) {
			$val = floatval( $this->products->get_post_field( $product_id, $field_key ) );
		}

		// ***

		switch ( $woobe_bulk[ $field_key ]['behavior'] ) {
			case 'new':
				$val = floatval( $woobe_bulk[ $field_key ]['value'] );
				break;

			case 'invalue':
				$val += floatval( $woobe_bulk[ $field_key ]['value'] );
				break;

			case 'devalue':
				$val -= floatval( $woobe_bulk[ $field_key ]['value'] );
				break;

			case 'inpercent':
				$val = $val + $val * floatval( $woobe_bulk[ $field_key ]['value'] ) / 100;
				break;

			case 'depercent':
				$val = $val - $val * floatval( $woobe_bulk[ $field_key ]['value'] ) / 100;
				break;

			case 'devalue_regular_price':
				// for sale_price only
				$val = floatval( $this->products->get_post_field( $product_id, 'regular_price' ) ) - floatval( $woobe_bulk[ $field_key ]['value'] );
				break;

			case 'depercent_regular_price':
				// for sale_price only
				$val = floatval( $this->products->get_post_field( $product_id, 'regular_price' ) );
				$val = $val - $val * floatval( $woobe_bulk[ $field_key ]['value'] ) / 100;
				break;

			case 'invalue_sale_price':
				// for regular_price only
				$val = floatval( $this->products->get_post_field( $product_id, 'sale_price' ) + floatval( $woobe_bulk[ $field_key ]['value'] ) );
				break;

			case 'inpercent_sale_price':
				// for regular_price only
				$val = floatval( $this->products->get_post_field( $product_id, 'sale_price' ) );
				$val = $val + $val * floatval( $woobe_bulk[ $field_key ]['value'] ) / 100;
				break;
		}

		if ( isset( $_REQUEST['num_formula_action'] ) and isset( $_REQUEST['num_formula_value'] ) and $_REQUEST['num_formula_value'] != '-1' ) {
			$v_key  = esc_textarea( $_REQUEST['num_formula_value'] );
			$action = esc_textarea( $_REQUEST['num_formula_action'] );
			$v_data = floatval( get_post_meta( $product_id, $v_key, true ) );

			switch ( $action ) {
				case '-':
					$val = $val - $v_data;
					break;
				case '*':
					$val = $val * $v_data;
					break;
				case '/':
					if ( $v_data == 0 ) {
						$v_data = 1;
					}
					$val = $val / $v_data;
					break;

				default:
					$val = $val + $v_data;
					break;
			}
		}

		if ( isset( $_REQUEST['num_rand_data'] ) && is_array( $_REQUEST['num_rand_data'] ) ) {
			$rand_data = wc_clean( $_REQUEST['num_rand_data'] );
			if ( isset( $rand_data['from'] ) && isset( $rand_data['to'] ) && ( $rand_data['from'] != $rand_data['to'] ) && ( $rand_data['from'] < $rand_data['to'] ) ) {
				$from    = (float) $rand_data['from'];
				$to      = (float) $rand_data['to'];
				$decimal = 1;
				if ( isset( $rand_data['decimal'] ) ) {
					$decimal = (int) $rand_data['decimal'];
				}
				$action = '+';
				if ( isset( $rand_data['action'] ) ) {
					$action = $rand_data['action'];
				}

				$rand_val = wp_rand( $from * $decimal, $to * $decimal ) / $decimal;
				switch ( $action ) {
					case '-':
						$val = $val - $rand_val;
						break;
					case '*':
						$val = $val * $rand_val;
						break;
					case '/':
						if ( $rand_val == 0 ) {
							$rand_val = 1;
						}
						$val = $val / $rand_val;
						break;

					default:
						$val = $val + $rand_val;
						break;
				}
			}
		}

		// ***

		$convert = true;
		if ( $field_key == 'sale_price' ) {
			// sale price CAN NOT be more OR even equal to the regular price
			if ( $val >= $this->products->get_post_field( $product_id, 'regular_price' ) ) {
				$convert = false;
			}
			// to delete sale price
			if ( $val <= 0 ) {
				$val     = -1;
				$val     = $this->products->update_page_field( $product_id, $field_key, $val );
				$convert = false;
			}
		}

		// ***

		if ( $convert ) {
			$val = $this->products->update_page_field( $product_id, $field_key, floatval( $val ) );
		}
	}

	public function woobe_bulk_finish() {
		do_action( 'woobe_bulk_finished', WOOBE_HELPER::sanitize_bulk_key( $_REQUEST['bulk_key'] ) );
		$count_key = 'woobe_bulk_' . WOOBE_HELPER::sanitize_bulk_key( $_REQUEST['bulk_key'] ) . '_count';
		die( esc_html( $this->storage->get_val( $count_key ) . '' ) );
	}

	private function init_bulk_keys() {

		$fields = woobe_get_fields();

		$this->text_keys = array(
			'post_title'   => array(
				'title'       => esc_html__( 'title', 'woo-bulk-editor' ),
				'css_classes' => isset( $fields['post_title']['css_classes'] ) ? $fields['post_title']['css_classes'] : '',
			),
			'post_content' => array(
				'title'       => esc_html__( 'description', 'woo-bulk-editor' ),
				'css_classes' => isset( $fields['post_content']['css_classes'] ) ? $fields['post_content']['css_classes'] : '',
			),
			'post_excerpt' => array(
				'title'       => esc_html__( 'short description', 'woo-bulk-editor' ),
				'css_classes' => isset( $fields['post_excerpt']['css_classes'] ) ? $fields['post_excerpt']['css_classes'] : '',
			),
			'post_name'    => array(
				'title'       => esc_html__( 'product slug', 'woo-bulk-editor' ),
				'css_classes' => isset( $fields['post_name']['css_classes'] ) ? $fields['post_name']['css_classes'] : '',
			),
			'sku'          => array(
				'title'       => esc_html__( 'SKU', 'woo-bulk-editor' ),
				'css_classes' => isset( $fields['sku']['css_classes'] ) ? $fields['sku']['css_classes'] : '',
			),
		);

		$this->other_keys = array(
			'post_status'        => array(
				'title'       => esc_html__( 'post status', 'woo-bulk-editor' ),
				'options'     => $fields['post_status']['select_options'],
				'direct'      => $fields['post_status']['direct'],
				'css_classes' => isset( $fields['post_status']['css_classes'] ) ? $fields['post_status']['css_classes'] : '',
			),
			'stock_status'       => array(
				'title'       => esc_html__( 'stock status', 'woo-bulk-editor' ),
				'options'     => $fields['stock_status']['select_options'],
				'direct'      => $fields['stock_status']['direct'],
				'css_classes' => isset( $fields['stock_status']['css_classes'] ) ? $fields['stock_status']['css_classes'] : '',
			),
			'tax_status'         => array(
				'title'       => esc_html__( 'tax status', 'woo-bulk-editor' ),
				'options'     => $fields['tax_status']['select_options'],
				'direct'      => $fields['tax_status']['direct'],
				'css_classes' => isset( $fields['tax_status']['css_classes'] ) ? $fields['tax_status']['css_classes'] : '',
			),
			'catalog_visibility' => array(
				'title'       => esc_html__( 'catalog visibility', 'woo-bulk-editor' ),
				'options'     => $fields['catalog_visibility']['select_options'],
				'direct'      => $fields['catalog_visibility']['direct'],
				'css_classes' => isset( $fields['catalog_visibility']['css_classes'] ) ? $fields['catalog_visibility']['css_classes'] : '',
			),
			'product_type'       => array(
				'title'       => esc_html__( 'product type', 'woo-bulk-editor' ),
				'options'     => $fields['product_type']['select_options'],
				'direct'      => $fields['product_type']['direct'],
				'css_classes' => isset( $fields['product_type']['css_classes'] ) ? $fields['product_type']['css_classes'] : '',
			),
			'featured'           => array(
				'title'       => esc_html__( 'featured', 'woo-bulk-editor' ),
				'options'     => $fields['featured']['select_options'],
				'direct'      => $fields['featured']['direct'],
				'css_classes' => isset( $fields['featured']['css_classes'] ) ? $fields['featured']['css_classes'] : '',
			),
		);
		// ***

		$options1 = array(
			'invalue'   => esc_html__( 'increase by value', 'woo-bulk-editor' ),
			'devalue'   => esc_html__( 'decrease by value', 'woo-bulk-editor' ),
			'inpercent' => esc_html__( 'increase by %', 'woo-bulk-editor' ),
			'depercent' => esc_html__( 'decrease by %', 'woo-bulk-editor' ),
			'new'       => esc_html__( 'set new', 'woo-bulk-editor' ),
		);

		$options2 = array(
			'invalue' => esc_html__( 'increase by value', 'woo-bulk-editor' ),
			'devalue' => esc_html__( 'decrease by value', 'woo-bulk-editor' ),
			'delete'  => esc_html__( 'delete', 'woo-bulk-editor' ),
			'new'     => esc_html__( 'set new', 'woo-bulk-editor' ),
		);

		// ***

		$this->num_keys = array(
			'regular_price'   => array(
				'title'       => esc_html__( 'regular price', 'woo-bulk-editor' ),
				'direct'      => $fields['regular_price']['direct'],
				'options'     => array(
					'invalue'              => esc_html__( 'increase by value', 'woo-bulk-editor' ),
					'devalue'              => esc_html__( 'decrease by value', 'woo-bulk-editor' ),
					'inpercent'            => esc_html__( 'increase by %', 'woo-bulk-editor' ),
					'depercent'            => esc_html__( 'decrease by %', 'woo-bulk-editor' ),
					'inpercent_sale_price' => esc_html__( 'sale price plus %', 'woo-bulk-editor' ),
					'invalue_sale_price'   => esc_html__( 'sale price plus value', 'woo-bulk-editor' ),
					'new'                  => esc_html__( 'set new', 'woo-bulk-editor' ),
				),
				'css_classes' => isset( $fields['regular_price']['css_classes'] ) ? $fields['regular_price']['css_classes'] : '',
			),
			'sale_price'      => array(
				'title'       => esc_html__( 'sale price', 'woo-bulk-editor' ),
				'direct'      => $fields['sale_price']['direct'],
				'options'     => array(
					'invalue'                 => esc_html__( 'increase by value', 'woo-bulk-editor' ),
					'devalue'                 => esc_html__( 'decrease by value', 'woo-bulk-editor' ),
					'inpercent'               => esc_html__( 'increase by %', 'woo-bulk-editor' ),
					'depercent'               => esc_html__( 'decrease by %', 'woo-bulk-editor' ),
					'depercent_regular_price' => esc_html__( 'regular price minus %', 'woo-bulk-editor' ),
					'devalue_regular_price'   => esc_html__( 'regular price minus value', 'woo-bulk-editor' ),
					'new'                     => esc_html__( 'set new', 'woo-bulk-editor' ),
				),
				'css_classes' => isset( $fields['sale_price']['css_classes'] ) ? $fields['sale_price']['css_classes'] : '',
			),
			'stock_quantity'  => array(
				'title'       => esc_html__( 'in stock quantity', 'woo-bulk-editor' ),
				'direct'      => $fields['stock_quantity']['direct'],
				'options'     => $options2,
				'css_classes' => isset( $fields['stock_quantity']['css_classes'] ) ? $fields['stock_quantity']['css_classes'] : '',
			),
			'download_expiry' => array(
				'title'       => esc_html__( 'download expiry', 'woo-bulk-editor' ),
				'direct'      => $fields['download_expiry']['direct'],
				'options'     => $options2,
				'css_classes' => isset( $fields['download_expiry']['css_classes'] ) ? $fields['download_expiry']['css_classes'] : '',
			),
			'download_limit'  => array(
				'title'       => esc_html__( 'download limit', 'woo-bulk-editor' ),
				'direct'      => $fields['download_limit']['direct'],
				'options'     => $options2,
				'css_classes' => isset( $fields['download_limit']['css_classes'] ) ? $fields['download_limit']['css_classes'] : '',
			),
		);
	}

	// ajax
	public function woobe_bulk_draw_gallery_btn() {
		$images = array();
		parse_str( $_REQUEST['images'], $images ); // sanitize below in array_map
		$data                 = array();
		$woobe_gallery_images = isset( $images['woobe_gallery_images'] ) ? $images['woobe_gallery_images'] : array();
		// sanitizing to intval
		$woobe_gallery_images = array_map(
			function ( $item ) {
				return intval( $item ); // sanitize intval
			},
			$woobe_gallery_images
		);

		$data['html']       = WOOBE_HELPER::draw_gallery_popup_editor_btn( sanitize_text_field( $_REQUEST['field'] ), 0, $woobe_gallery_images );
		$data['images_ids'] = implode( ',', $woobe_gallery_images ); // for any case, but now we not need it because updating of products applies by serialized data

		die( json_encode( $data ) );
	}

	// ajax
	public function woobe_bulk_draw_download_files_btn() {
		$files = array();
		parse_str( $_REQUEST['files'], $files );
		$files = WOOBE_HELPER::sanitize_array( $files );
		$count = 0;

		if ( isset( $files['_wc_file_names'] ) ) {
			$count = count( $files['_wc_file_names'] );
		}

		WOOBE_HELPER::draw_downloads_popup_editor_btn_e( sanitize_text_field( $_REQUEST['field'] ), 0, $count );

		exit;
	}

	// ajax
	public function woobe_bulk_draw_cross_sells_btn() {
		$products = array();
		parse_str( $_REQUEST['products'], $products );

		$ids = array();
		if ( isset( $products['woobe_prod_ids'] ) ) {
			$ids = $products['woobe_prod_ids'];
		}

		$ids = array_map(
			function ( $item ) {
				return intval( $item ); // sanitize intval
			},
			$ids
		);

		WOOBE_HELPER::draw_cross_sells_popup_editor_btn_e( sanitize_text_field( $_REQUEST['field'] ), 0, $ids );

		exit;
	}

	// ajax
	public function woobe_bulk_draw_upsell_ids_btn() {
		$products = array();
		parse_str( $_REQUEST['products'], $products );

		$ids = array();
		if ( isset( $products['woobe_prod_ids'] ) ) {
			$ids = array_map(
				function ( $item ) {
					return intval( $item ); // sanitize intval
				},
				$products['woobe_prod_ids']
			);
		}

		WOOBE_HELPER::draw_upsells_popup_editor_btn_e( $_REQUEST['field'], 0, $ids );

		exit;
	}

	// ajax
	public function woobe_bulk_draw_grouped_ids_btn() {
		$products = array();
		parse_str( $_REQUEST['products'], $products ); // sanitize below

		$ids = array();
		if ( isset( $products['woobe_prod_ids'] ) ) {
			$ids = array_map(
				function ( $item ) {
					return intval( $item ); // sanitize intval
				},
				$products['woobe_prod_ids']
			);
		}

		WOOBE_HELPER::draw_grouped_popup_editor_btn_e( sanitize_text_field( $_REQUEST['field'] ), 0, $ids );

		exit;
	}

	// ajax
	public function woobe_bulk_get_att_terms() {
		
		if ( ! current_user_can( 'manage_woocommerce' ) ) {
			die( '0' );
		}

		if ( ! isset( $_REQUEST['bulk_form_nonce'] ) || ! wp_verify_nonce( $_REQUEST['bulk_form_nonce'], 'woobe_bulk_form_nonce' ) ) {
			die( '0' );
		}

		$drop_downs = '';
		if ( ! empty( $_REQUEST['attributes'] ) && is_array( $_REQUEST['attributes'] )  ) {
			foreach ( $_REQUEST['attributes'] as $pa ) {
				$pa = sanitize_text_field( $pa ); // sanitize attribute name

				$terms = WOOBE_HELPER::get_taxonomies_terms_hierarchy( $pa );
				if ( ! empty( $terms ) ) {
					$options       = array();
					$options['']   = esc_html__( 'not selected', 'woo-bulk-editor' );
					$options['-1'] = esc_html__( 'Any', 'woo-bulk-editor' );
					foreach ( $terms as $t ) {
						$options[ $t['slug'] ] = $t['name'];
					}

					$drop_downs .= WOOBE_HELPER::draw_select(
						array(
							'field'      => 0,
							'product_id' => 0,
							'class'      => '',
							'options'    => $options,
							'name'       => 'woobe_bulk[combination_attributes][' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['hash_key'] ) ) ) . '][' . $pa . ']',
						)
					);
				}
			}
		}

		$allowed_html = array(
			'div'    => array(
				'class' => true,
			),
			'select' => array(
				'name'               => true,
				'id'                 => true,
				'class'              => true,
				'multiple'           => true,
				'size'               => true,
				'disabled'           => true,
				'data-field'         => true,
				'data-product-id'    => true,
				'data-placeholder'   => true,
				'data-selected'      => true,
			),
			'option' => array(
				'value'    => true,
				'selected' => true,
			),
		);

		echo wp_kses( $drop_downs, $allowed_html );
		exit;
	}
}
