<?php

namespace CommerceBird\API;

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

use CMBIRD_Image_ZI;
use CMBIRD_Products_ZI;
use CMBIRD_Products_ZI_Export;
use WC_Data_Exception;
use WC_Product_Variation;
use WC_Product_Variable;
use WP_REST_Response;
use wpdb;
use CMBIRD_Common_Functions;
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;

/**
 * Handles product webhook operations for CommerceBird API.
 */
class ProductWebhook {


	use Api;

	/**
	 * REST API endpoint for Zoho product webhook.
	 *
	 * @var string
	 */
	private static string $endpoint = 'zoho-product';

	/**
	 * Indicates if WooCommerce taxes are enabled.
	 *
	 * @var bool
	 */
	private $is_tax_enabled;

	/**
	 * ProductWebhook constructor.
	 * Registers REST route, checks tax settings, and sets up hooks for queue processing and cleanup.
	 */
	public function __construct() {
		register_rest_route(
			self::$namespace,
			self::$endpoint,
			array(
				'methods'             => 'POST',
				'callback'            => array( $this, 'handle' ),
				'permission_callback' => '__return_true',
			)
		);
		// Check if WooCommerce taxes are enabled and store the result.
		$this->is_tax_enabled = 'yes' === get_option( 'woocommerce_calc_taxes' );

		// Register queue processing hook.
		add_action( 'cmbird_process_webhook_queue', array( $this, 'process_queued_requests' ) );

		// Add cleanup for old rate limit data.
		add_action( 'wp_scheduled_delete', array( $this, 'cleanup_rate_limit_data' ) );
	}

	/**
	 * Retrieves whether WooCommerce taxes are enabled.
	 *
	 * @return bool
	 */
	public function is_tax_enabled(): bool {
		return $this->is_tax_enabled;
	}

	/**
	 * Filters an incoming Zoho rate before saving as WooCommerce regular price.
	 *
	 * @param mixed    $rate       Incoming Zoho rate.
	 * @param array    $item       Zoho item payload.
	 * @param int|null $product_id WooCommerce product or variation ID when known.
	 * @return mixed
	 */
	private function get_filtered_regular_price( $rate, array $item, ?int $product_id = null ) {
		return apply_filters( 'cmbird_zi_item_regular_price', $rate, (object) $item, $product_id );
	}


	/**
	 * Processes incoming product webhook data.
	 *
	 * @throws WC_Data_Exception If there is an error with WooCommerce product data.
	 */
	private function process( array $data ): WP_REST_Response {
		$response = new WP_REST_Response();
		$response->set_data( $this->empty_response );
		$response->set_status( 404 );
		if ( ! array_key_exists( 'item', $data ) && ! array_key_exists( 'inventory_adjustment', $data ) ) {
			return $response;
		}

		// Accounting stock mode check.
		$accounting_stock        = get_option( 'cmbird_zoho_enable_accounting_stock_status' );
		$zi_enable_locationstock = get_option( 'cmbird_zoho_enable_locationstock_status' );
		$location_id             = get_option( 'cmbird_zoho_location_id_status' );

		// variable item sync.
		if ( array_key_exists( 'item', $data ) ) {
			return $this->process_product_data( $data['item'], $zi_enable_locationstock, $location_id, $accounting_stock );
		}
		// inventory_adjustment.
		if ( array_key_exists( 'inventory_adjustment', $data ) ) {
			return $this->inventory_adjustment( $data['inventory_adjustment'] );
		}

		return $response;
	}

	/**
	 * Processes incoming product webhook data.
	 *
	 * @param array $item - incoming product webhook data.
	 * @param bool  $zi_enable_locationstock - location stock enabled status.
	 * @param int   $location_id - location id.
	 * @param bool  $accounting_stock - accounting stock status.
	 *
	 * @return WP_REST_Response
	 * @throws WC_Data_Exception If there is an error with WooCommerce product data.
	 */
	public function process_product_data( $item, $zi_enable_locationstock, $location_id, $accounting_stock ): WP_REST_Response {
		// $fd = fopen( __DIR__ . '/process_product_data.txt', 'w+' );

		// clean orphaned data from the database.
		$common_class = new CMBIRD_Common_Functions();
		$common_class->clear_orphan_data();

		global $wpdb;
		$item_id          = $item['item_id'];
		$item_name        = $item['name'];
		$item_price       = $item['rate'];
		$item_sku         = $item['sku'];
		$item_description = $item['description'];
		$item_status      = $item['status'] === 'active' ? 'publish' : 'draft';
		$item_brand       = $item['brand'];
		$category_id      = $item['category_id'];
		$custom_fields    = $item['custom_fields'];
		$item_image       = $item['image_name'];
		// Stock mode check.
		$locations = $item['locations'] ?? $item['warehouses'] ?? array();
		if ( $zi_enable_locationstock ) {
			foreach ( $locations as $location ) {
				// Check both location_id and warehouse_id fields against the configured location_id.
				$location_match = ( isset( $location['location_id'] ) && $location['location_id'] === $location_id ) ||
								( isset( $location['warehouse_id'] ) && $location['warehouse_id'] === $location_id );

				if ( $location_match ) {
					if ( $accounting_stock ) {
						// Check for warehouse_ prefix if warehouse_id was used, otherwise use location_ prefix!
						$item_stock = isset( $location['warehouse_id'] )
							? $location['warehouse_available_for_sale_stock']
							: $location['location_available_for_sale_stock'];
					} else {
						// Check for warehouse_ prefix if warehouse_id was used, otherwise use location_ prefix!
						$item_stock = isset( $location['warehouse_id'] )
							? $location['warehouse_actual_available_for_sale_stock']
							: $location['location_actual_available_for_sale_stock'];
					}
				}
			}
		} elseif ( $accounting_stock && ! $zi_enable_locationstock ) {
			$item_stock = $item['available_for_sale_stock'];
		} else {
			$item_stock = $item['actual_available_for_sale_stock'];
		}
		if ( isset( $item['group_name'] ) ) {
			$group_name = $item['group_name'];
		} else {
			$group_name = '';
		}
		$item_category = $item['category_name'];
		if ( isset( $item['group_id'] ) ) {
			$groupid = $item['group_id'];
		} else {
			$groupid = '';
		}

		// Item package details.
		$details = $item['package_details'];
		$weight  = floatval( $details['weight'] );
		$length  = floatval( $details['length'] );
		$width   = floatval( $details['width'] );
		$height  = floatval( $details['height'] );

		$item_row_for_type_check = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s", $item_id )
		); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- item id is sanitized.
		$product_type            = '';
		if ( ! empty( $item_row_for_type_check->post_id ) ) {
			$existing_item_product = wc_get_product( $item_row_for_type_check->post_id );
			if ( $existing_item_product instanceof WC_Product_Variation || $existing_item_product instanceof WC_Product_Variable ) {
				$product_type = 'variable';
			} elseif ( $existing_item_product ) {
				$product_type = $existing_item_product->get_type();
			}
		}

		$is_variable_item = ! empty( $groupid ) || 'variable' === $product_type || 'variation' === $product_type;

		if ( $is_variable_item && $item['has_attribute_options'] ) {
			$this->process_variable_item_data( $item, $groupid, $category_id, $custom_fields, $item_id, $item_name, $item_price, $item_sku, $item_description, $item_status, $item_brand, $item_image, $item_stock, $weight, $length, $width, $height );
		} else {
			$this->process_simple_item_data( $item, $group_name, $item_category, $custom_fields, $item_id, $item_name, $item_price, $item_sku, $item_description, $item_status, $item_brand, $item_image, $item_stock, $weight, $length, $width, $height );
		}
		$response = new WP_REST_Response();
		$response->set_data( 'success on variable product' );
		$response->set_status( 200 );

		// fclose( $fd ); // close logfile.

		return $response;
	}

	/**
	 * Handle variable/grouped Zoho items.
	 */
	private function process_variable_item_data( array $item, $groupid, $category_id, $custom_fields, $item_id, $item_name, $item_price, $item_sku, $item_description, $item_status, $item_brand, $item_image, $item_stock, float $weight, float $length, float $width, float $height ): void {
		global $wpdb;
		// find parent variable product.
		$row      = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key='zi_item_id' AND meta_value=%s", $groupid ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- $groupid is prepared.
		$group_id = isset( $row->post_id ) ? (int) $row->post_id : 0;

		if ( ! empty( $group_id ) ) {
			$existing_parent_product = wc_get_product( $group_id );
			if ( ! $existing_parent_product ) {
				$wpdb->delete( $wpdb->postmeta, array( 'post_id' => $group_id ) );
				return;
			}
			$zi_disable_itemdescription_sync = get_option( 'cmbird_zoho_disable_description_sync_status' );
			if ( ! empty( $item_description ) && ! $zi_disable_itemdescription_sync ) {
				$existing_parent_product->set_short_description( $item_description );
			}
			// Update the name of the variable product if allowed.
			$zi_disable_itemname_sync = get_option( 'cmbird_zoho_disable_name_sync_status' );
			if ( ! $zi_disable_itemname_sync ) {
				$existing_parent_product->set_name( $item['group_name'] );
				$slug = sanitize_title( $item['group_name'] );
				$existing_parent_product->set_slug( $slug );
			}
			// Brand update if taxonomy product_brand exists.
			if ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
				wp_set_object_terms( $groupid, $item_brand, 'product_brand' );
			} elseif ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
				wp_set_object_terms( $groupid, $item_brand, 'product_brand' );
			}
			// Update the custom fields if the custom fields are not empty.
			$cmbird_product_zi = new CMBIRD_Products_ZI();
			if ( ! empty( $custom_fields ) ) {
				$cmbird_product_zi->sync_item_custom_fields( $custom_fields, $group_id );
			}

			// Create or Update the Attributes.
			$gp_arr       = (array) $item;
			$attr_created = $cmbird_product_zi->sync_attributes_of_group( $gp_arr, $group_id );
			if ( ! empty( $group_id ) && $attr_created ) {
				// Create the variations.
				$cmbird_product_zi->import_variable_product_variations( $item, $group_id );
			}

			$existing_parent_product->save();
		} else {
			// Add in scheduler to create the Variable Product.
			$last_synced_page = get_option( 'cmbird_group_item_sync_page_cat_id_' . $category_id );
			if ( ! intval( $last_synced_page ) ) {
				$last_synced_page = 1;
			}
			$data              = array(
				'page'     => $last_synced_page,
				'category' => $category_id,
			);
			$existing_schedule = as_has_scheduled_action( 'import_group_items_cron', $data );
			// Schedule the action if it doesn't exist.
			if ( ! $existing_schedule ) {
				as_schedule_single_action( time(), 'import_group_items_cron', $data );
			}
		}

		$row_item     = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key='zi_item_id' AND meta_value=%s", $item_id ) ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- item id is sanitized.
		$variation_id = $row_item->post_id;
		if ( $variation_id ) {
			// updating existing variations.
			$variation  = new WC_Product_Variation( $variation_id );
			$item_price = $this->get_filtered_regular_price( $item_price, $item, (int) $variation_id );
			// Prices.
			if ( ! empty( $item_price ) ) {
				$variation->set_price( $item_price );
			}
			$variation->set_regular_price( $item_price );
			// Stock.
			$zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
			if ( ! empty( $item_stock ) && ! $zi_disable_stock_sync ) {
				$variation->set_stock_quantity( $item_stock );
				$variation->set_manage_stock( true );
			} else {
				$variation->set_manage_stock( false );
			}
			// featured image.
			$zi_disable_itemimage_sync = get_option( 'cmbird_zoho_disable_image_sync_status' );
			if ( ! empty( $item_image ) && ! $zi_disable_itemimage_sync ) {
				$image_class = new CMBIRD_Image_ZI();
				$image_class->cmbird_zi_get_image( $item_id, $item_name, $item_image, $variation_id );
			}
			// Disable or enable the variation based on the item_status.
			$variation->set_status( $item_status );
			// Update Purchase price.
			$variation->set_cogs_value( $item['purchase_rate'] );

			// Map taxes while syncing product from zoho.
			if ( $item['tax_id'] && ! $this->is_tax_enabled() ) {
				$zi_common_class = new CMBIRD_Common_Functions();
				$woo_tax_class   = $zi_common_class->get_tax_class_by_zoho_id( $item['tax_id'] )
								?? $zi_common_class->get_tax_class_by_percentage( $item['tax_percentage'] );
				$variation->set_tax_status( 'taxable' );
				$variation->set_tax_class( $woo_tax_class );
			}
			// weight & dimensions.
			$variation->set_weight( $weight );
			$variation->set_length( $length );
			$variation->set_width( $width );
			$variation->set_height( $height );

			$variation->save(); // Save the data.
		} elseif ( 'publish' === $item_status ) {
			$attribute_name11 = $item['attribute_option_name1'];
			$attribute_name12 = $item['attribute_option_name2'];
			$attribute_name13 = $item['attribute_option_name3'];
			// Prepare the variation data.
			$attribute_arr = array();
			if ( ! empty( $attribute_name11 ) ) {
				$sanitized_name1                   = wc_sanitize_taxonomy_name( $item['attribute_name1'] );
				$attribute_arr[ $sanitized_name1 ] = $attribute_name11;
			}
			if ( ! empty( $attribute_name12 ) ) {
				$sanitized_name2                   = wc_sanitize_taxonomy_name( $item['attribute_name2'] );
				$attribute_arr[ $sanitized_name2 ] = $attribute_name12;
			}
			if ( ! empty( $attribute_name13 ) ) {
				$sanitized_name3                   = wc_sanitize_taxonomy_name( $item['attribute_name3'] );
				$attribute_arr[ $sanitized_name3 ] = $attribute_name13;
			}

			// here actually create new variation because sku not found.
			$zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
			$variation             = new WC_Product_Variation();
			$variation->set_parent_id( $group_id );
			$variation->set_status( 'publish' );
			$variation->set_regular_price( $this->get_filtered_regular_price( $item_price, $item, null ) );
			$variation->set_sku( $item_sku );
			$variation->set_weight( $weight );
			$variation->set_length( $length );
			$variation->set_width( $width );
			$variation->set_height( $height );
			if ( ! $zi_disable_stock_sync ) {
				$variation->set_stock_quantity( $item_stock );
				$variation->set_manage_stock( true );
				$variation->set_stock_status( '' );
			} else {
				$variation->set_manage_stock( false );
			}
			// Map taxes while syncing product from zoho.
			if ( $item['tax_id'] && ! $this->is_tax_enabled() ) {
				$zi_common_class = new CMBIRD_Common_Functions();
				$woo_tax_class   = $zi_common_class->get_tax_class_by_zoho_id( $item['tax_id'] )
								?? $zi_common_class->get_tax_class_by_percentage( $item['tax_percentage'] );
				$variation->set_tax_status( 'taxable' );
				$variation->set_tax_class( $woo_tax_class );
			}
			$variation->add_meta_data( 'zi_item_id', $item->item_id );
			$variation_id = $variation->save();

			// Get the variation attributes with correct attribute values.
			foreach ( $attribute_arr as $attribute => $term_name ) {
				$taxonomy = $attribute;
				// If taxonomy doesn't exists we create it.
				if ( ! taxonomy_exists( $taxonomy ) ) {
					register_taxonomy(
						$taxonomy,
						'product_variation',
						array(
							'hierarchical' => false,
							'label'        => ucfirst( $attribute ),
							'query_var'    => true,
							'rewrite'      => array( 'slug' => sanitize_title( $attribute ) ),
						),
					);
				}

				// Check if the Term name exist and if not we create it.
				if ( ! term_exists( $term_name, $taxonomy ) ) {
					wp_insert_term( $term_name, $taxonomy );
				}

				$term_slug = get_term_by( 'name', $term_name, $taxonomy )->slug;
				// Get the post Terms names from the parent variable product.
				$post_term_names = wp_get_post_terms( $group_id, $taxonomy, array( 'fields' => 'names' ) );
				// Check if the post term exist and if not we set it in the parent variable product.
				if ( ! in_array( $term_name, $post_term_names, true ) ) {
					wp_set_post_terms( $group_id, $term_name, $taxonomy, true );
				}
				// Set/save the attribute data in the product variation.
				update_post_meta( $variation_id, 'attribute_' . $taxonomy, $term_slug );
			}

			// featured image.
			$zi_disable_itemimage_sync = get_option( 'cmbird_zoho_disable_image_sync_status' );
			if ( ! empty( $item_image ) && ! $zi_disable_itemimage_sync ) {
				$image_class = new CMBIRD_Image_ZI();
				$image_class->cmbird_zi_get_image( $item_id, $item_name, $item_image, $variation_id );
			}

			update_post_meta( $variation_id, 'zi_item_id', $item_id );
			// Sync variation data with parent variable product.
			WC_Product_Variable::sync( $group_id );
			// Regenerate lookup table for attributes.
			$parent_product = wc_get_product( $group_id );
			if ( $parent_product ) {
				$lookup_data_store = new LookupDataStore();
				$lookup_data_store->create_data_for_product( $parent_product );
			}
			// End group item add process.
			unset( $attribute_arr );
		}

		wc_delete_product_transients( $group_id ); // Clear/refresh cache.
	}

	/**
	 * Handle simple Zoho items.
	 */
	private function process_simple_item_data( array $item, $group_name, $item_category, $custom_fields, $item_id, $item_name, $item_price, $item_sku, $item_description, $item_status, $item_brand, $item_image, $item_stock, float $weight, float $length, float $width, float $height ): void {
		global $wpdb;
		$row_item          = $wpdb->get_row(
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s", $item_id )
		); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared // item id is sanitized.
		$mapped_product_id = isset( $row_item->post_id ) ? (int) $row_item->post_id : 0;

		$pdt_id = '';
		if ( ! empty( $mapped_product_id ) && null !== $mapped_product_id ) {
			$product_found = wc_get_product( $mapped_product_id );
			if ( ! $product_found ) {
				// remove all postmeta of that product id.
				$wpdb->delete( $wpdb->postmeta, array( 'post_id' => $mapped_product_id ) );
			} else {
				$pdt_id = $mapped_product_id;
			}
		} elseif ( false === $item['is_combo_product'] ) {
			// Check if Category is selected before creating simple item.
			if ( 'publish' === $item_status ) {
				// cmbird_zoho_item_category is a plain array of Zoho category IDs.
				$opt_category = maybe_unserialize( get_option( 'cmbird_zoho_item_category' ) );
				$category_id  = $item['category_id'];
				if ( $opt_category ) {
					if ( in_array( $category_id, $opt_category, true ) ) {
						$item['rate']  = $this->get_filtered_regular_price( $item_price, $item, null );
						$item_price    = $item['rate'];
						$product_class = new CMBIRD_Products_ZI_Export();
						$pdt_id        = $product_class->cmbird_zi_product_to_woocommerce( $item, $item_stock );
					}
				}
			}
		}

		// If there is product id then update metadata.
		if ( ! empty( $pdt_id ) ) {
			$simple_product = wc_get_product( $pdt_id );
			if ( ! $simple_product ) {
				// Stale product mapping can exist if the WooCommerce product was deleted.
				$wpdb->delete( $wpdb->postmeta, array( 'post_id' => $pdt_id ) );
				return;
			}
			// update the name if its allowed.
			$zi_disable_itemname_sync = get_option( 'cmbird_zoho_disable_name_sync_status' );
			if ( ! $zi_disable_itemname_sync ) {
				$simple_product->set_name( $item_name );
				$slug = sanitize_title( $item_name );
				$simple_product->set_slug( $slug );
			}
			// update the zi_item_id using the product instance.
			$simple_product->update_meta_data( 'zi_item_id', $item_id );
			// update the status using set_status().
			$simple_product->set_status( $item_status );
			// Update the product SKU.
			$simple_product->set_sku( $item_sku );
			// price.
			$sale_price = $simple_product->get_sale_price();
			$item_price = $this->get_filtered_regular_price( $item_price, $item, (int) $pdt_id );
			$simple_product->set_regular_price( $item_price );
			if ( empty( $sale_price ) ) {
				$simple_product->set_price( $item_price );
			}
			// Update Purchase price.
			$simple_product->set_cogs_value( $item['purchase_rate'] );
			// description.
			$zi_disable_itemdescription_sync = get_option( 'cmbird_zoho_disable_description_sync_status' );
			if ( ! empty( $item_description ) && ! $zi_disable_itemdescription_sync ) {
				$simple_product->set_short_description( $item_description );
			}
			// Brand update if taxonomy product_brand(s) exists.
			if ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
				wp_set_object_terms( $pdt_id, $item_brand, 'product_brand' );
			} elseif ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
				wp_set_object_terms( $pdt_id, $item_brand, 'product_brand' );
			}
			// stock.
			$zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
			if ( ! $zi_disable_stock_sync ) {
				if ( 'NULL' !== gettype( $item_stock ) ) {
					// Set manage stock to yes.
					$simple_product->set_manage_stock( true );
					// Update stock for simple product.
					$simple_product->set_stock_quantity( number_format( $item_stock, 0, '.', '' ) );
					if ( $item_stock > 0 ) {
						// Update stock status.
						$simple_product->set_stock_status( 'instock' );
						wp_set_post_terms( $pdt_id, 'instock', 'product_visibility', true );
					} else {
						$stock_status = $simple_product->backorders_allowed() ? 'onbackorder' : 'outofstock';
						$simple_product->set_stock_status( $stock_status );
						wp_set_post_terms( $pdt_id, $stock_status, 'product_visibility', true );
					}
				}
			}
			// Update weight & dimensions of simple product.
			$simple_product->set_weight( $weight );
			$simple_product->set_length( $length );
			$simple_product->set_width( $width );
			$simple_product->set_height( $height );

			// featured image.
			$zi_disable_itemimage_sync = get_option( 'cmbird_zoho_disable_image_sync_status' );
			if ( ! empty( $item_image ) && ! $zi_disable_itemimage_sync ) {
				$image_class = new CMBIRD_Image_ZI();
				$image_class->cmbird_zi_get_image( $item_id, $item_name, $item_image, $pdt_id );
			}

			// category.
			if ( ! empty( $item_category ) ) {
				$term_slug = sanitize_title( $item_category );
				$term    = get_term_by( 'slug', $term_slug, 'product_cat' );
				$term_id = $term->term_id;
				if ( empty( $term_id ) ) {
					$term    = wp_insert_term(
						$item_category,
						'product_cat',
						array(
							'parent' => 0,
						)
					);
					$term_id = $term->term_id;
				}
				// Remove "uncategorized" category if assigned.
				$uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' );
				if ( $uncategorized_term && has_term( $uncategorized_term->term_id, 'product_cat', $pdt_id ) ) {
					wp_remove_object_terms( $pdt_id, $uncategorized_term->term_id, 'product_cat' );
				}
				if ( ! is_wp_error( $term_id ) && isset( $term->term_id ) ) {
					$existing_terms = wp_get_object_terms( $pdt_id, 'product_cat' );
					if ( $existing_terms && count( $existing_terms ) > 0 ) {
						$import_class  = new CMBIRD_Products_ZI();
						$is_term_exist = $import_class->zi_check_terms_exists( $existing_terms, $term_id );
						if ( ! $is_term_exist ) {
							$simple_product->update_meta_data( 'zi_category_id', $item['category_id'] );
							wp_add_object_terms( $pdt_id, $term_id, 'product_cat' );
						}
					} else {
						$simple_product->update_meta_data( 'zi_category_id', $item['category_id'] );
						wp_set_object_terms( $pdt_id, $term_id, 'product_cat' );
					}
				}
			}

			// Update the custom fields if the custom fields are not empty.
			if ( ! empty( $custom_fields ) ) {
				$import_class = new CMBIRD_Products_ZI();
				$import_class->sync_item_custom_fields( $custom_fields, $pdt_id );
			}

			// Map taxes while syncing product from zoho.
			if ( $item['tax_id'] && ! $this->is_tax_enabled() ) {
				$zi_common_class = new CMBIRD_Common_Functions();
				$woo_tax_class   = $zi_common_class->get_tax_class_by_zoho_id( $item['tax_id'] )
								?? $zi_common_class->get_tax_class_by_percentage( $item['tax_percentage'] );
				$simple_product->set_tax_status( 'taxable' );
				$simple_product->set_tax_class( $woo_tax_class );
			}
			$simple_product->save();
			wc_delete_product_transients( $pdt_id );
		}
	}

	/**
	 * Process queued webhook requests
	 * Called by WordPress cron system when queue processing is scheduled
	 */
	public function process_queued_requests() {
		$queue_key     = 'cmbird_request_queue';
		$current_queue = get_option( $queue_key, array() );

		if ( empty( $current_queue ) || ! is_array( $current_queue ) ) {
			return;
		}

		$current_time          = time();
		$processed_count       = 0;
		$max_process_per_batch = 10; // Process up to 10 requests per batch.

		// Process queue items.
		foreach ( $current_queue as $index => $queue_item ) {
			if ( $processed_count >= $max_process_per_batch ) {
				break; // Don't process too many at once.
			}

			// Check if request is too old (older than 5 minutes).
			if ( ( $current_time - $queue_item['timestamp'] ) > 300 ) {
				unset( $current_queue[ $index ] );
				continue;
			}

			// Simulate the original request processing.
			try {
				if ( isset( $queue_item['data'] ) && ! empty( $queue_item['data'] ) ) {
					$data = $queue_item['data'];

					// Convert JSONString if present.
					if ( array_key_exists( 'JSONString', $data ) ) {
						$data = str_replace( '\\', '', $data['JSONString'] );
					}

					// Process the data.
					$this->process( $data );
					++$processed_count;
				}
			} catch ( Exception $e ) {
				// Log error but continue processing other items.
				error_log( 'CommerceBird Webhook Queue Processing Error: ' . $e->getMessage() ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_error_log -- Required for security logging.
			}

			// Remove processed item from queue.
			unset( $current_queue[ $index ] );
		}

		// Re-index array after unsetting elements.
		$current_queue = array_values( $current_queue );

		// Update the queue.
		update_option( $queue_key, $current_queue );

		// Schedule next processing if queue still has items.
		if ( ! empty( $current_queue ) && ! wp_next_scheduled( 'cmbird_process_webhook_queue' ) ) {
			wp_schedule_single_event( $current_time + 30, 'cmbird_process_webhook_queue' );
		}
	}

	/**
	 * Cleanup old rate limiting data
	 * Called by WordPress scheduled delete action
	 */
	public function cleanup_rate_limit_data() {
		global $wpdb;

		// Clean up old transients related to rate limiting.
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$wpdb->options} 
				 WHERE option_name LIKE %s 
				 OR option_name LIKE %s",
				$wpdb->esc_like( '_transient_cmbird_rate_limit_' ) . '%',
				$wpdb->esc_like( '_transient_timeout_cmbird_rate_limit_' ) . '%'
			)
		); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- safe here.

		// Clean up old processing locks (older than 1 hour).
		$wpdb->query(
			$wpdb->prepare(
				"DELETE FROM {$wpdb->options} 
				 WHERE option_name LIKE %s 
				 AND option_value < %d",
				$wpdb->esc_like( 'cmbird_processing_payload_' ) . '%',
				time() - 3600
			)
		); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- time() is safe here.
	}

	/**
	 * Handles inventory adjustment webhook data.
	 *
	 * @param array $inventory_adjustment Inventory adjustment data.
	 *
	 * @return WP_REST_Response
	 */
	public function inventory_adjustment( $inventory_adjustment ): WP_REST_Response {
		global $wpdb;
		$item       = $inventory_adjustment;
		$line_items = $item['line_items'];
		// get first item from line items array.
		$item_id        = $line_items[0]['item_id'];
		$adjusted_stock = $line_items[0]['quantity_adjusted'];

		$row_item          = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s",
				$item_id
			)
		); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $item_id is prepared.
		$mapped_product_id = $row_item->post_id;

		if ( ! empty( $mapped_product_id ) ) {
			// stock.
			$zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
			$product               = wc_get_product( $mapped_product_id );
			// Check if the product is in stock.
			if ( ! $zi_disable_stock_sync ) {
				if ( $product->is_in_stock() ) {
					// Get stock quantity.
					$stock_quantity = $product->get_stock_quantity();
					$new_stock      = $stock_quantity + $adjusted_stock;
					$product->set_stock_quantity( $new_stock );
				} else {
					$product->set_stock_quantity( $adjusted_stock );
					$product->set_stock_status( 'instock' );
					$product->set_manage_stock( true );
				}
				$product->save();
			}
		}

		$response = new WP_REST_Response();
		$response->set_data( 'Inventory Adjustment successful' );
		$response->set_status( 200 );

		return $response;
	}
}
