<?php

trait Wcmlim_Backend_Stock_Functions{

public function wcmlim_maybe_reduce_stock_levels($order_id)
{    
    
    if (!$order_id) {        
        return;
    }

    $order = wc_get_order($order_id);
    if (!$order) {        
        return;
    }

    // Check order status - only reduce stock for specific statuses
    $order_status = $order->get_status();
    $allowed_statuses = array('pending', 'processing', 'completed', 'on-hold', 'auto-draft');
        
    
    if (!in_array($order_status, $allowed_statuses)) {
        return; // Don't reduce stock for this order status
    }

    $notes = [];
    $any_stock_reduced = false;
    

    foreach ($order->get_items() as $item_id => $item) {        
        
        // Skip if there's no item
        if (!$item) {            
            continue;
        }
        
        // Get product info
        $product_id = $item->get_variation_id() ?: $item->get_product_id();
        $product = wc_get_product($product_id);
                
        
        if (!$product || !$product->managing_stock()) {
            continue;
        }
        
        $item_quantity = $item->get_quantity();        
        
        // Check if stock for this item was already reduced
        $item_stock_reduced = $item->get_meta('_reduced_stock', true);        
        
        if ($item_stock_reduced) {
            continue; // Stock already reduced for this item
        }
        
        // Get location information
        $location_id = wc_get_order_item_meta($item_id, '_selectedLocTermId', true);
        $location_name = wc_get_order_item_meta($item_id, 'Location', true);
                
        
        // Only fallback to first location if no location is set at all
        // This should now rarely happen since we set location meta before calling this function
        if (!$location_id) {            
            $locations = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
            if (!empty($locations)) {
                $location_id = $locations[0]->term_id;
                $location_name = $locations[0]->name;
                                
                
                // Update the item with the default location
                wc_update_order_item_meta($item_id, '_selectedLocTermId', $location_id);
                wc_update_order_item_meta($item_id, 'Location', $location_name);
            } else {                
                continue; // No locations available, skip this item
            }
        } else {            
        }
        
        // Reduce stock at the selected location
        $current_stock = get_post_meta($product_id, "wcmlim_stock_at_{$location_id}", true);
        $new_stock = max(0, intval($current_stock) - intval($item_quantity));
        update_post_meta($product_id, "wcmlim_stock_at_{$location_id}", $new_stock);
        
        // Mark this item's stock as reduced
        $item->add_meta_data('_reduced_stock', $item_quantity, true);
        $item->save();
        
        // Update total stock across all locations
        $this->wcmlim_update_totaldata($product_id);
        
        // Add note about stock reduction
        $notes[] = "Stock levels reduced: {$item->get_name()} from Location: {$location_name} " .
                   "{$current_stock} → {$new_stock}";
                   
        $any_stock_reduced = true;
    }
    
    // Add notes if any changes were made
    if (!empty($notes)) {
        $order->add_order_note(implode("\n", $notes));
    }

    // Mark stock as reduced if any items had stock reduced
    if ($any_stock_reduced) {
        $order->get_data_store()->set_stock_reduced($order_id, true);
        if (WC_HPOS_IS_ACTIVE) {
            $order->update_meta_data('_order_stock_reduced', 'yes');
        } else {
            update_post_meta($order_id, '_order_stock_reduced', 'yes');
        }
        $order->save();
    }
}

/**
 * Update total inventory data across all locations
 * 
 * @param int $product_id The product ID to update
 * @return void
 */
public function wcmlim_update_totaldata($product_id)
{
    $total = 0;
    
    // Get only linked locations for this product
    $linked_locations = wp_get_object_terms($product_id, 'locations', array('fields' => 'ids'));
    
    if (!empty($linked_locations)) {
        // Calculate total stock from linked locations only
        foreach ($linked_locations as $location_id) {
            $stock = get_post_meta($product_id, "wcmlim_stock_at_{$location_id}", true);
            $total += intval($stock);
        }
    } else {
        // If no locations are linked, use the original stock value
        $original_stock = get_post_meta($product_id, '_original_stock', true);
        if ($original_stock !== '') {
            $total = intval($original_stock);
        } else {
            // Fallback: get current stock value
            $total = intval(get_post_meta($product_id, '_stock', true));
        }
    }
    
    // Update the main stock quantity
    update_post_meta($product_id, '_stock', $total);
    
    // Clear product transients
    wc_delete_product_transients($product_id);
}

/**
 * Update stock levels between locations when an item's location changes
 */
private function update_location_stock($product_id, $quantity, $old_location_id, $new_location_id, &$notes, $item, $location_name)
{
    // Restore stock to old location
    $old_stock = get_post_meta($product_id, "wcmlim_stock_at_{$old_location_id}", true);
    $restock_old_location = intval($old_stock) + intval($quantity);
    update_post_meta($product_id, "wcmlim_stock_at_{$old_location_id}", $restock_old_location);
    
    // Reduce stock at new location
    $new_stock_level = $this->reduce_location_stock($product_id, $quantity, $new_location_id);
    
    // Mark new location stock as reduced
    update_post_meta($product_id, "_wcmlim_stock_at_{$new_location_id}_reduced", true);
    
    // Add note about stock changes
    $notes[] = "Stock levels reduced: {$item->get_name()} from Location: {$location_name} " .
               (intval($new_stock_level) + intval($quantity)) . " &rarr; {$new_stock_level}";
}

/**
 * Reduce stock at a specific location
 */
private function reduce_location_stock($product_id, $quantity, $location_id)
{
    $current_stock = get_post_meta($product_id, "wcmlim_stock_at_{$location_id}", true);
    $new_stock = max(0, intval($current_stock) - intval($quantity));
    update_post_meta($product_id, "wcmlim_stock_at_{$location_id}", $new_stock);
    return $new_stock;
}

public function stock_fullfllment_for_next_loc($product_id, $item_quantity, $item_id, $order, $type)
{
  if ($type !== "most_inventory" || !empty(wc_get_order_item_meta($item_id, '_selectedLocTermId'))) {
    return array();
  }
    
  $locations = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
  $used_locations = array();
  
  $prepare_priority_loc = array();
  foreach($locations as $key=>$term){
    $product_id_loc_stock = get_post_meta($product_id, 'wcmlim_stock_at_' . $term->term_id, true);
    $prepare_priority_loc[] = array(
      "up_termid" => $term->term_id,
      "up_key" => $key,
      "up_name" => $term->name,
      "up_stock" => $product_id_loc_stock
    );   
  }
  
  // Sort location by most inventory
  usort($prepare_priority_loc, function($a, $b) {
    return $b['up_stock'] <=> $a['up_stock'];
  });
  
  // Find the original order item to preserve its tax data
  $original_item = false;
  foreach ($order->get_items() as $order_item) {
    if ($order_item->get_id() == $item_id) {
      $original_item = $order_item;
      break;
    }
  }
  
  if (!$original_item) {
    return array(); // Can't proceed without original item
  }
  
  // Get the product
  $product = wc_get_product($product_id);
  if (!$product) {
    return array();
  }
  
  // Calculate unit prices correctly based on WooCommerce tax settings
  $prices_include_tax = wc_prices_include_tax();
  $tax_display_cart = get_option('woocommerce_tax_display_cart');
  
  // Get the base price and tax data from the original item
  $original_subtotal = $original_item->get_subtotal();
  $original_total = $original_item->get_total(); 
  $original_subtotal_tax = $original_item->get_subtotal_tax();
  $original_total_tax = $original_item->get_total_tax();
  $original_taxes = $original_item->get_taxes();
  $original_qty = $original_item->get_quantity();
  
  // Calculate unit values (per item)
  $unit_subtotal = $original_subtotal / $original_qty;
  $unit_total = $original_total / $original_qty;
  $unit_subtotal_tax = $original_subtotal_tax / $original_qty;
  $unit_total_tax = $original_total_tax / $original_qty;
  
  // Store the first location's data for post-processing
  $first_location_item_id = null;
  
  // Remove the original item - we'll replace it with items from specific locations
  $order->remove_item($item_id);
  
  // Track remaining quantity to fulfill
  $remaining_qty = $item_quantity;
  
  // Process each location in order of stock availability (highest first)
  foreach ($prepare_priority_loc as $key => $value) {
    // Skip locations with no stock
    if ($remaining_qty <= 0) {
      break;
    }
    
    $location_stock = intval($value['up_stock']);
    if ($location_stock <= 0) {
      continue;
    }
    
    // Determine quantity to fulfill from this location
    $qty_from_location = min($remaining_qty, $location_stock);
    
    // Create new order item
    $new_item = new WC_Order_Item_Product();
    $new_item->set_product($product);
    $new_item->set_quantity($qty_from_location);
    
    // Set location metadata
    $new_item->add_meta_data('Location', $value['up_name']);
    $new_item->add_meta_data('_selectedLocTermId', $value['up_termid']);
    $new_item->add_meta_data('_old_selectedLocTermId', $value['up_termid']);
    $new_item->add_meta_data('_selectedLocationKey', $value['up_key']);
    
    // Track this location as used
    $used_locations[] = $value['up_termid'];
    
    // Set the price data exactly as the original item (per unit)
    $new_item->set_subtotal($unit_subtotal * $qty_from_location);
    $new_item->set_total($unit_total * $qty_from_location);
    
    // Set the tax data
    $new_item->set_subtotal_tax($unit_subtotal_tax * $qty_from_location);
    $new_item->set_total_tax($unit_total_tax * $qty_from_location);
    
    // Copy the original tax data structure but adjust quantities
    if (isset($original_taxes['total']) && is_array($original_taxes['total'])) {
      $new_taxes = ['total' => [], 'subtotal' => []];
      
      foreach ($original_taxes['total'] as $tax_id => $tax_amount) {
        $tax_per_unit = $tax_amount / $original_qty;
        $new_taxes['total'][$tax_id] = $tax_per_unit * $qty_from_location;
      }
      
      foreach ($original_taxes['subtotal'] as $tax_id => $tax_amount) {
        $tax_per_unit = $tax_amount / $original_qty;
        $new_taxes['subtotal'][$tax_id] = $tax_per_unit * $qty_from_location;
      }
      
      $new_item->set_taxes($new_taxes);
    }
    
    // Add item to order
    $order->add_item($new_item);
    
    // Store first location item ID for post-processing
    if ($key === 0) {
      $first_location_item_id = $new_item->get_id();
    }
    
    // Update stock level at this location
    $new_stock = $location_stock - $qty_from_location;
    update_post_meta($product_id, 'wcmlim_stock_at_' . $value['up_termid'], $new_stock);
    
    // Add a note about stock reduction
    $note = "Priority wise location Stock levels reduced: {$product->get_name()} from Location: {$value['up_name']} {$location_stock} → {$new_stock}";
    $order->add_order_note($note);
    
    // Reduce remaining quantity
    $remaining_qty -= $qty_from_location;
  }
  
  // If we couldn't fulfill the entire order, add a note
  if ($remaining_qty > 0) {
    $order->add_order_note("Warning: Could not fulfill {$remaining_qty} item(s) of {$product->get_name()} due to insufficient stock.");
  }
  
  // Save the order
  $order->save();
  
  return $used_locations;
}

/**
 * Get locations sorted by inventory level (highest first)
 */
private function get_locations_sorted_by_inventory($product_id)
{
    $locations = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
    if (empty($locations)) {
        return [];
    }
    
    $locations_with_stock = [];
    foreach ($locations as $key => $term) {
        $stock = get_post_meta($product_id, 'wcmlim_stock_at_' . $term->term_id, true);
        $locations_with_stock[] = [
            "up_termid" => $term->term_id,
            "up_key" => $key,
            "up_name" => $term->name,
            "up_stock" => intval($stock)
        ];
    }
    
    // Sort by stock level (highest first)
    usort($locations_with_stock, function($a, $b) {
        return $b['up_stock'] <=> $a['up_stock'];
    });
    
    return $locations_with_stock;
}

/**
 * Add product to order with location details
 */
private function add_product_to_order($order, $product_id, $quantity, $location_term_id, $location_name, $location_key)
{
    $order_item = $order->add_product(
        wc_get_product($product_id),
        $quantity,
        [
            '_selectedLocTermId' => $location_term_id,
            'Location' => $location_name,
            '_selectedLocationKey' => $location_key
        ]
    );
    
    // Add order item meta to ensure consistency
    wc_add_order_item_meta($order_item, '_selectedLocTermId', $location_term_id);
    wc_add_order_item_meta($order_item, '_old_selectedLocTermId', $location_term_id);
    wc_add_order_item_meta($order_item, 'Location', $location_name);
    wc_add_order_item_meta($order_item, '_selectedLocationKey', $location_key);
    
    return $order_item;
}

public function wcmlim_nearby_stock_adjustment($product_id,$match_dest,$distance,$item_id)
{    
  if(isset($distance[0]["termkey"]))
  {
    $dis_first_key = $distance[0]['termkey'];
    $dis_first_location = $distance[0]['locationname'];
  }
  else
  {
    $dis_first_key = $distance[0]['key'];
    $dis_first_location = $distance[0]['location'];
  }

  $fulfillment_stock_array = $distance;
  $nearby_first_matching_array = $match_dest[$dis_first_key];
  $nearby_first__matching_termid = $nearby_first_matching_array['termid'];
  $nearby_first__matching_termkey = $nearby_first_matching_array['termkey'];
  $nearby_first__matching_locationname = $nearby_first_matching_array['locationname'];
  $postmeta_stock_at_term = get_post_meta($product_id, 'wcmlim_stock_at_' . $nearby_first__matching_termid, true);
  $cart_item_quantity = WC()->cart->cart_contents[$item_id]["quantity"];
  $postmeta_backorders_product = get_post_meta($product_id, '_backorders', true);
  if($postmeta_backorders_product == "yes")
    {

      WC()->cart->cart_contents[$item_id]['select_location']['location_name'] = $nearby_first__matching_locationname;
      WC()->cart->cart_contents[$item_id]['select_location']['location_key'] = $nearby_first__matching_termkey;
      WC()->cart->cart_contents[$item_id]['select_location']['location_termId'] = $nearby_first__matching_termid;
      WC()->cart->cart_contents[$item_id]['quantity'] = $cart_item_quantity;
      WC()->cart->set_session();
      wc_clear_notices();
  }
  else if(intval($cart_item_quantity) <= intval($postmeta_stock_at_term))
  {
    WC()->cart->cart_contents[$item_id]['select_location']['location_name'] = $nearby_first__matching_locationname;
    WC()->cart->cart_contents[$item_id]['select_location']['location_key'] = $nearby_first__matching_termkey;
    WC()->cart->cart_contents[$item_id]['select_location']['location_termId'] = $nearby_first__matching_termid;
    WC()->cart->set_session();
    wc_clear_notices();
  }
  else
  {
      $updated_cart_item_quantity =  intval($cart_item_quantity) - intval($postmeta_stock_at_term);
      unset($fulfillment_stock_array[0]);
      WC()->cart->cart_contents[$item_id]['select_location']['location_name'] = $nearby_first__matching_locationname;
      WC()->cart->cart_contents[$item_id]['select_location']['location_key'] = $nearby_first__matching_termkey;
      WC()->cart->cart_contents[$item_id]['select_location']['location_termId'] = $nearby_first__matching_termid;
      WC()->cart->cart_contents[$item_id]['quantity'] = $postmeta_stock_at_term;
      WC()->cart->set_session();
      wc_clear_notices();
        $skip_term_id[] = $nearby_first__matching_termid;
        $this->wcmlim_nearby_stock_adjustment_with_priority($product_id,$match_dest,$fulfillment_stock_array,$item_id,$updated_cart_item_quantity,$skip_term_id);      
  }
  return 0;
  wp_die(); 
}

public function wcmlim_nearby_stock_adjustment_with_priority($product_id, $match_dest, $fulfillment_stock_array, $item_id, $updated_cart_item_quantity, $skip_term_id)
{
    // Get locations with priority values
    $prepare_priority_loc = $this->get_prioritized_locations($skip_term_id);
    if (empty($prepare_priority_loc)) {
        return;
    }
    
    // Sort by priority
    ksort($prepare_priority_loc);
    
    // Process each location in priority order
    foreach ($prepare_priority_loc as $priority_key => $location) {
        $term_id = $location['up_termid'];
        $term_key = $location['up_key'];
        $term_name = $location['up_name'];
        $current_stock = get_post_meta($product_id, "wcmlim_stock_at_{$term_id}", true);
        
        // Check if backorders are allowed
        $backorders_enabled = get_post_meta($product_id, '_backorders', true) === "yes";
        if ($backorders_enabled) {
            $this->add_to_cart_with_location($product_id, $updated_cart_item_quantity, $term_name, $term_id, $term_key);
            wc_clear_notices();
            return 0;
        }
        
        // Check if location has enough stock
        if (intval($updated_cart_item_quantity) <= intval($current_stock)) {
            $this->add_to_cart_with_location($product_id, $updated_cart_item_quantity, $term_name, $term_id, $term_key);
            wc_clear_notices();
            return 0;
        }
        
        // If not enough stock, use what's available and continue to next location
        $carry_stock = intval($updated_cart_item_quantity) - intval($current_stock);
        $this->add_to_cart_with_location($product_id, $current_stock, $term_name, $term_id, $term_key);
        wc_clear_notices();
        
        // Add term to skip list and process remaining quantity
        $skip_term_id[] = $term_id;
        $this->wcmlim_nearby_stock_adjustment_with_priority(
            $product_id, $match_dest, $fulfillment_stock_array, $item_id, $carry_stock, $skip_term_id
        );
    }
}

/**
 * Get locations with priority values
 */
private function get_prioritized_locations($skip_term_ids = [])
{
    $priority_locations = [];
    $locations = get_terms(['taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0]);
    
    if (!empty($locations)) {
        foreach ($locations as $key => $term) {
            if (in_array($term->term_id, $skip_term_ids)) {
                continue;
            }
            
            $priority = get_term_meta($term->term_id, 'wcmlim_location_priority', true);
            if ($priority !== null && $priority !== false) {
                $priority_locations[$priority] = [
                    "up_termid" => $term->term_id,
                    "up_key" => $key,
                    "up_name" => $term->name
                ];
            }
        }
    }
    
    return array_filter($priority_locations);
}

/**
 * Add product to cart with location data
 */
private function add_to_cart_with_location($product_id, $quantity, $location_name, $location_term_id, $location_key)
{
    $location_data = [
        'select_location' => [
            'location_name' => $location_name,
            'location_key' => $location_key,
            'location_qty' => $quantity,
            'location_termId' => $location_term_id
        ]
    ];
    
    WC()->cart->add_to_cart($product_id, $quantity, '0', [], $location_data);
}

public function wc_reduce_stock_levels($order_id) {

    if (is_a($order_id, 'WC_Order')) {
        $order    = $order_id;
        $order_id = $order->get_id();
    } else {
        $order = wc_get_order($order_id);
    }

    // We need an order, and a store with stock management to continue.
    if (!$order || 'yes' !== get_option('woocommerce_manage_stock') || !apply_filters('woocommerce_can_reduce_order_stock', true, $order)) {
        // return;
    }

    $changes = array();
    $item_mail = array();
    // Loop over all items.

    // Given URL
    $url = $_SERVER['REQUEST_URI']; 
    
    // Search substring 
    $key = 'wp-json/wc-pos';

    // *WooCommerce Point Of Sale by Actuality Extensions compatibility
    $wc_pos_compatiblity1 = get_option('wcmlim_wc_pos_compatiblity');
    if (($wc_pos_compatiblity1 == "on") && (in_array('woocommerce-point-of-sale/woocommerce-point-of-sale.php', apply_filters('active_plugins', get_option('active_plugins')))) && (strpos($url, $key) != false)) { 
                                    
        $blogURL = get_bloginfo('url');
        $referer = $_SERVER['HTTP_REFERER'];
        $referer = str_replace($blogURL, "", $referer);
        $refe = explode("/", $referer);
        foreach($refe as $r => $s) {
            if($s == "point-of-sale")
            {
                $outletSlug = $refe[$r+1];
                $registerSlug = $refe[$r+2];
            }
        }
        
        $rargs = array(
            'post_type' => 'pos_register',
            'name' => $registerSlug,
            'post_status' => 'publish',
            'fields' => 'ids',
        );

        $registerPOST = get_posts($rargs);
        $regPostID = $registerPOST[0];
        $assignedOutletID = get_post_meta($regPostID, 'outlet', true);
        
        global $wpdb; 
        $termMetaTable = $wpdb->prefix . 'termmeta';
        $getTermID = $wpdb->get_results($wpdb->prepare("SELECT term_id FROM $termMetaTable WHERE meta_key = %s AND meta_value = %d;", 'wcmlim_wcpos_compatiblity', $assignedOutletID));
        
        $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
        
        
        $exclExists = get_option("wcmlim_exclude_locations_from_frontend");
        if (!empty($exclExists)) {
            $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0, 'exclude' => $exclExists));
        } else {
            $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
        }

        foreach ($order->get_items() as $item) {

            if (!$item->is_type('line_item')) {
                continue;
            }

            // Only reduce stock once for each item.
            $product            = $item->get_product();
            $product_id = $product->get_id();
            $item_stock_reduced = $item->get_quantity();
            
            // *WooCommerce Point Of Sale by Actuality Extensions compatibility

            foreach ($getTermID as $key => $value) {
            
                $foundTermID= $value->term_id;
        
            if (!$product || !$product->managing_stock()) {
                continue;
            }

            $qty       = apply_filters('woocommerce_order_item_quantity', $item->get_quantity(), $order, $item);
            $item_name = $product->get_formatted_name();
        
            $order = wc_get_order( $order_id ); 

            $item->add_meta_data('Location',  $value->name);
            $item->add_meta_data('_selectedLocationKey', $key);
            $item->add_meta_data('_selectedLocTermId', $value->term_id);
            $item->add_meta_data('_wcmlim_reduced_stock', $qty, true);
            $item->save();
                
            $this->wcpos_reduce_product_stock($product_id, $qty, $foundTermID, $order);
            $order->get_data_store()->set_stock_reduced($order_id, true);
            
            $product->update_meta_data( 'wcmlim_sync_updated', true );
            $product->save();
            if (WC_HPOS_IS_ACTIVE) {
					$order->update_meta_data('_order_stock_reduced', 'yes');
				} else {
					update_post_meta($order_id, '_order_stock_reduced', 'yes');
				}
        
        }
                
        }
    
    }
    else{
    foreach ($order->get_items() as $item) {
        
        if (!$item->is_type('line_item')) {
            continue;
        }

        // Only reduce stock once for each item.
        $product            = $item->get_product();
        $item_stock_reduced = $item->get_meta('_reduced_stock', true);
        

            $item_selectedLocation_key = $item->get_meta('_selectedLocationKey', true);
                $itemSelLocTermId = $item->get_meta('_selectedLocTermId', true);
            $itemSelLocName = $item->get_meta('Location', true);
            $dataLocation = $item->get_meta('Location', true);
            if($itemSelLocTermId == '') {
                return;
              }

        $selLocQty = get_post_meta($product->get_id(), "wcmlim_stock_at_{$itemSelLocTermId}", true);

        if (!$item_stock_reduced || !$product || !$product->managing_stock()) {
            continue;
        }

        $qty       = apply_filters('woocommerce_order_item_quantity', $item->get_quantity(), $order, $item);


        // *WooCommerce Point Of Sale by Actuality Extensions compatibility
        $wc_pos_compatiblity1 = get_option('wcmlim_wc_pos_compatiblity');
        
        if (($wc_pos_compatiblity1 == "on") && (in_array('woocommerce-point-of-sale/woocommerce-point-of-sale.php', apply_filters('active_plugins', get_option('active_plugins'))))) { 
        //now we have to get the outlet id and update the stock if wc pos is active
        
        $outlet_id = get_term_meta($itemSelLocTermId , 'wcmlim_wcpos_compatiblity', true);
        $new_outlet_stock = wc_pos_update_product_outlet_stock( $product , array( $outlet_id => $qty ), 'decrease' );
        
        }



        $item_name = $product->get_formatted_name();
        $new_stock = $this->wc_update_product_stock($product, $qty, 'decrease', false, $item_selectedLocation_key);

        if (is_wp_error($new_stock)) {
            /* translators: %s item name. */
            $order->add_order_note(sprintf(_e('Unable to reduce stock for item %s.', 'woocommerce'), $item_name));
            continue;
        }
        
        $item->add_meta_data('_reduced_stock', $qty, true);
        $item->save();

        $changes[] = array(
            'product' => $product,
            'from'    => intval($new_stock) + intval($qty),
            'to'      => $new_stock,
        );

        $locChanges[] = array(
            'product' 	=> $product,
            'location'	=> $itemSelLocName,
            'from'    	=> $selLocQty,
            'to'      	=> intval($selLocQty) - intval($qty),
        );
        //send Mail
        if(!in_array( $itemSelLocTermId, $item_mail ) ) {
            $item_mail[] = $itemSelLocTermId;
        }
    }
    $dataLocate = array();
    $wcmlim_assign_location_shop_manager = get_option('wcmlim_assign_location_shop_manager');
    if($wcmlim_assign_location_shop_manager != 'on'){
      $item_mail = array();
    }
    foreach($item_mail as $wcmlim_email_val) {
        
        $wcmlim_emailadd = get_term_meta($wcmlim_email_val, 'wcmlim_email', true);
        $shop_manager = get_term_meta($wcmlim_email_val, 'wcmlim_shop_manager', true);
        $term_object = get_term( $wcmlim_email_val );
        $dataLo = $term_object->term_id;										
        $dataLocate[] = $dataLo;
        if ($shop_manager) {
            $author_id = 	$shop_manager[0];
            $author_obj = get_user_by('id', $author_id);
            $author_email = $author_obj->user_email;	
            if($wcmlim_emailadd) {
                $wcmlimemail = $author_email . ", " . $wcmlim_emailadd;	
            }  else {
                $wcmlimemail = $author_email;	
            }												
        } else {
            $wcmlimemail = $wcmlim_emailadd;
        }
        /*Regional code */
        $regM = get_term_meta($wcmlim_email_val, "wcmlim_locator", true);
        $regM2 = get_term_meta($regM, "wcmlim_shop_regmanager", true);
        $wcmlim_regemail = get_term_meta($regM, 'wcmlim_email_regmanager', true);
        if ($regM2) {
            $authorid = 	$regM2[0];
            $authorobj = get_user_by('id', $authorid);
            $authoremail = $authorobj->user_email;	
                if($wcmlim_regemail) {
                    $regwcmlimemail = $authoremail . ", " . $wcmlim_regemail;		
                } else {
                    $regwcmlimemail = $authoremail;		
                }	
        } else {
            $regwcmlimemail = $wcmlim_regemail;
        }
        
        if($regwcmlimemail) {
            $wcmlim_email = $regwcmlimemail . ", " . $wcmlimemail;		
        } else {
            $wcmlim_email = $wcmlimemail;		
        }	
        
        if (isset($wcmlim_email) && !empty($wcmlim_email)) {
            include(plugin_dir_path(dirname(__FILE__)) . 'public/partials/email-template.php');
        }
    }
    //update multiloc
    if(!empty($dataLocate)){
        if(WC_HPOS_IS_ACTIVE){
            $order->update_meta_data( '_multilocation', $dataLocate );
        }else{
            update_post_meta($order_id, "_multilocation", $dataLocate);
        }
    }
    
    $wordCount = explode(" ", $dataLocation);
    if (count($wordCount) > 1) {
        $_location = str_replace(' ', '-', strtolower($dataLocation));
    } else {
        $_location = $dataLocation;
    }

    if (preg_match('/"/', $_location)) {
        $_location = str_replace('"', '', $_location);
    }

    if(!empty($_location)){
        if(WC_HPOS_IS_ACTIVE){
            $order->update_meta_data( '_location', $_location );
        }else{
            update_post_meta($order_id, "_location", $_location);
        }
    }
    $this->wc_trigger_stock_change_notifications($order, $changes, $locChanges);

    do_action('woocommerce_reduce_order_stock', $order);
    }
    $order->save();
}
public function wc_trigger_stock_change_notifications($order, $changes, $locChanges)
	{
		if (empty($changes)) {
			return;
		}

		$order_notes     = array();
		$no_stock_amount = absint(get_option('woocommerce_notify_no_stock_amount', 0));

		foreach ($changes as $change) {
			$order_notes[]    = $change['product']->get_formatted_name() . ' ' . $change['from'] . '&rarr;' . $change['to'];
			$low_stock_amount = absint($this->wc_get_low_stock_amount(wc_get_product($change['product']->get_id())));
			if ($change['to'] <= $no_stock_amount) {
				do_action('woocommerce_no_stock', wc_get_product($change['product']->get_id()));
			} elseif ($change['to'] <= $low_stock_amount) {
				do_action('woocommerce_low_stock', wc_get_product($change['product']->get_id()));
			}

			if ($change['to'] < 0) {
				do_action(
					'woocommerce_product_on_backorder',
					array(
						'product'  => wc_get_product($change['product']->get_id()),
						'order_id' => $order->get_id(),
						'quantity' => abs($change['from'] - $change['to']),
					)
				);
			}
		}

		$order->add_order_note( implode(', ', $order_notes));				

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

		foreach ($locChanges as $locChange) {										
			$loc_order_notes[]    = "{ Stock levels reduced: {$locChange['product']->get_formatted_name()}  from Location: {$locChange['location']} {$locChange['from']} &rarr; {$locChange['to']} }";
		
			$low_stock_amount = absint($this->wc_get_low_stock_amount(wc_get_product($locChange['product']->get_id())));
			if ($locChange['to'] <= $no_stock_amount) {
				do_action('woocommerce_no_stock', wc_get_product($locChange['product']->get_id()));
			} elseif ($locChange['to'] <= $low_stock_amount) {
				do_action('woocommerce_low_stock', wc_get_product($locChange['product']->get_id()));
			}

			if ($locChange['to'] < 0) {
				do_action(
					'woocommerce_product_on_backorder',
					array(
						'product'  => wc_get_product($locChange['product']->get_id()),
						'order_id' => $order->get_id(),
						'quantity' => intval($locChange['from']) - intval($locChange['to']),
					)
				);
			}
		}

		$order->add_order_note(implode(', ', $loc_order_notes));
	}
    public function wcpos_reduce_product_stock($product_id, $qty, $location_id, $order)
	{
		
		$product_current_qty_at = get_post_meta($product_id, "wcmlim_stock_at_{$location_id}", true);
		$postmeta_backorders_product = get_post_meta($product_id, '_backorders', true);
		
		if((($product_current_qty_at <= 0 ) || ($product_current_qty_at >= 0 ) || ( $product_current_qty_at = ''))  && (($postmeta_backorders_product == "yes") || ($postmeta_backorders_product == "notify")))
		{

		$product_updated_qty = intval($product_current_qty_at) - intval($qty);
		$term_name = get_term( $location_id )->name;

		$product = wc_get_product( $product_id );

		$loc_order_notes[]    = "{ Stock levels reduced: {$product->get_formatted_name()}  from Location: {$term_name} {$product_current_qty_at} &rarr; {$product_updated_qty} }";
		$order->add_order_note(implode(', ', $loc_order_notes));

		update_post_meta($product_id, "wcmlim_stock_at_{$location_id}", $product_updated_qty);

		return 1;	
		}
		else{
			if($qty > $product_current_qty_at){
		$product_updated_qty = 0;

			}
			else
			{
		$product_updated_qty = intval($product_current_qty_at) - intval($qty);
			}
		$term_name = get_term( $location_id )->name;

		$product = wc_get_product( $product_id );

		$loc_order_notes[]    = "{ Stock levels reduced: {$product->get_formatted_name()}  from Location: {$term_name} {$product_current_qty_at} &rarr; {$product_updated_qty} }";
		$order->add_order_note(implode(', ', $loc_order_notes));

		update_post_meta($product_id, "wcmlim_stock_at_{$location_id}", $product_updated_qty);

		return 1;	
		}
	}

    public function wc_update_product_stock($product, $stock_quantity = null, $operation = 'set', $updating = false, $item_selectedLocation_key=null)
	{

		if (!is_a($product, 'WC_Product')) {
			$product = wc_get_product($product);
		}

		if (!$product) {
			return false;
		}

		if (!is_null($stock_quantity) && $product->managing_stock()) {
			// Some products (variations) can have their stock managed by their parent. Get the correct object to be updated here.
			$product_id_with_stock = $product->get_stock_managed_by_id();
			$product_with_stock    = $product_id_with_stock !== $product->get_id() ? wc_get_product($product_id_with_stock) : $product;

			$data_store            = WC_Data_Store::load('product');

			$product_id = $product_with_stock->get_id();

			$exclExists = get_option("wcmlim_exclude_locations_from_frontend");
			if (!empty($exclExists)) {
				$terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0, 'exclude' => $exclExists));
			} else {
				$terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
			}
			
			// Fire actions to let 3rd parties know the stock is about to be changed.
			if ($product_with_stock->is_type('variation')) {
				foreach ($terms as $k => $term) {
					if ($k == $item_selectedLocation_key) {
						$variationParentTerms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => $term->term_id));
						if (!empty($variationParentTerms)) {
							foreach ($variationParentTerms as $vParentTerm) {
								$stockInpVariation[$vParentTerm->term_id] = get_post_meta($product_id, "wcmlim_stock_at_{$vParentTerm->term_id}", true);
							}
							$varParentValue = max($stockInpVariation);
							$varParentKey = array_search($varParentValue, $stockInpVariation);
							if ($varParentKey) {
								$maxStockAtVarSub = get_post_meta($product_id, "wcmlim_stock_at_{$varParentKey}", true);
								if ($operation == "decrease") {
									$varSubStock = ((int)$maxStockAtVarSub - (int)$stock_quantity);
								} else {
									$varSubStock = ((int)$maxStockAtVarSub + (int)$stock_quantity);
								}
								if (class_exists('SitePress')) {
									global $sitepress;
									$trid = $sitepress->get_element_trid($product_id, 'post_product');
									$translations = $sitepress->get_element_translations($trid, 'product');
									foreach ($translations as $lang => $translation) {
										if ($translation->element_id != $product_id) {
											update_post_meta($translation->element_id, "wcmlim_stock_at_{$varParentKey}", $varSubStock);
										}
									}
									if (!$updating) {
										$product_with_stock->save();
									}
								}
								
								update_post_meta($product_id, "wcmlim_stock_at_{$varParentKey}", $varSubStock);
								//OpenPos - Outlet stock updated
								$wcmlim_pos_compatiblity = get_option('wcmlim_pos_compatiblity');
								if ($wcmlim_pos_compatiblity == "on" && in_array('woocommerce-openpos/woocommerce-openpos.php', apply_filters('active_plugins', get_option('active_plugins')))) {
									$wcmlim_pos_id =  get_term_meta($term->term_id, 'wcmlim_pos_compatiblity', true);
									update_post_meta($product_id, "_op_qty_warehouse_{$wcmlim_pos_id}", $varSubStock);
								}
							}
						}
						$stock_in_location_variation = get_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", true);
						if ($operation == "decrease") {
							$stock = ((int)$stock_in_location_variation - (int)$stock_quantity);
						} else {
							$stock = ((int)$stock_in_location_variation + (int)$stock_quantity);
						}
						if (class_exists('SitePress')) {
							global $sitepress;
							$trid = $sitepress->get_element_trid($product_id, 'post_product');
							$translations = $sitepress->get_element_translations($trid, 'product');
							foreach ($translations as $lang => $translation) {
								if ($translation->element_id != $product_id) {
									update_post_meta($translation->element_id, "wcmlim_stock_at_{$term->term_id}", $stock);
								
								}
							}
							if (!$updating) {
								$product_with_stock->save();
							}
						}
						update_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", $stock);
						//OpenPos - Outlet stock updated
						$wcmlim_pos_compatiblity = get_option('wcmlim_pos_compatiblity');
						if ($wcmlim_pos_compatiblity == "on" && in_array('woocommerce-openpos/woocommerce-openpos.php', apply_filters('active_plugins', get_option('active_plugins')))) {
							$wcmlim_pos_id =  get_term_meta($term->term_id, 'wcmlim_pos_compatiblity', true);
							update_post_meta($product_id, "_op_qty_warehouse_{$wcmlim_pos_id}", $stock);
						}
					}
					
				}
				$locations = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
				$stock = '';
				foreach($locations as $key=>$term){
						$stock  = intval(get_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", true));
						if($stock == '' || $stock == 0){
							$removetermName[] = $term->slug;
						}else{
							$termName[] = $term->slug;
						}
					}
				wp_set_object_terms( $product_id, $termName, 'locations' );
				wp_remove_object_terms( $product_id, $removetermName, 'locations' );
				do_action('woocommerce_variation_before_set_stock', $product_with_stock);
			} else {

				foreach ($terms as $k => $term) {
					if ($k == $item_selectedLocation_key) {
						$parentTerms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => $term->term_id));
						if (!empty($parentTerms)) {
							foreach ($parentTerms as $parentTerm) {
								$stockInParentLocation[$parentTerm->term_id] = get_post_meta($product_id, "wcmlim_stock_at_{$parentTerm->term_id}", true);
							}
							$parentValue = max($stockInParentLocation);
							$parentKey = array_search($parentValue, $stockInParentLocation);
							if ($parentKey) {
								$maxStockAtSub = get_post_meta($product_id, "wcmlim_stock_at_{$parentKey}", true);
								if ($operation == "decrease") {
									$subStock = ((int)$maxStockAtSub - (int)$stock_quantity);
								} else {
									$subStock = ((int)$maxStockAtSub + (int)$stock_quantity);
								}
								if (class_exists('SitePress')) {
									global $sitepress;
									$trid = $sitepress->get_element_trid($product_id, 'post_product');
									$translations = $sitepress->get_element_translations($trid, 'product');
									foreach ($translations as $lang => $translation) {
										if ($translation->element_id != $product_id) {
											update_post_meta($translation->element_id, "wcmlim_stock_at_{$parentKey}", $subStock);
										}
									}
									if (!$updating) {
										$product_with_stock->save();
									}
								}
								update_post_meta($product_id, "wcmlim_stock_at_{$parentKey}", $subStock);
							}
						}
						$stock_in_location = get_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", true);
						if ($operation == "decrease") {
							$stock = ((int)$stock_in_location - (int)$stock_quantity);
						} else {
							$stock = ((int)$stock_in_location + (int)$stock_quantity);
						}
						if (class_exists('SitePress')) {
							global $sitepress;
							$trid = $sitepress->get_element_trid($product_id, 'post_product');
							$translations = $sitepress->get_element_translations($trid, 'product');
							foreach ($translations as $lang => $translation) {
								if ($translation->element_id != $product_id) {
									update_post_meta($translation->element_id, "wcmlim_stock_at_{$term->term_id}", $stock);
								}
							}if($stock == '' || $stock == 0){
								$removetermName[] = $term->slug;
								}
								wp_remove_object_terms( $product_id, $removetermName, 'locations' );
							if (!$updating) {
								$product_with_stock->save();
							}
						}

						update_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", $stock);
						//OpenPos - Outlet stock updated
						$wcmlim_pos_compatiblity = get_option('wcmlim_pos_compatiblity');

						if ($wcmlim_pos_compatiblity == "on" && in_array('woocommerce-openpos/woocommerce-openpos.php', apply_filters('active_plugins', get_option('active_plugins')))) {
							$wcmlim_pos_id =  get_term_meta($term->term_id, 'wcmlim_pos_compatiblity', true);
							update_post_meta($product_id, "_op_qty_warehouse_{$wcmlim_pos_id}", $stock);
						}
					}
				}

				$locations = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
				$stock = '';
				$terms = wp_get_object_terms($product_id, 'locations'); // Get only linked locations for the product
				foreach($terms as $key=>$term){
						$stock  = intval(get_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", true));
						$termName[] = $term->slug; // do not remove location linking who hase 0 stock
					}
				wp_set_object_terms( $product_id, $termName, 'locations' );
				wp_remove_object_terms( $product_id, $removetermName, 'locations' );
				do_action('woocommerce_product_before_set_stock', $product_with_stock);
			}

			// Update the database.

			if($operation != "decrease"){

			$new_stock = $data_store->update_product_stock($product_id_with_stock, $stock_quantity, $operation);
			}
			// Update the product object.
			$data_store->read_stock_quantity($product_with_stock, $new_stock);

			// If this is not being called during an update routine, save the product so stock status etc is in sync, and caches are cleared.
			if (!$updating) {
				$product_with_stock->save();
			}

			// Fire actions to let 3rd parties know the stock changed.
			if ($product_with_stock->is_type('variation')) {
				do_action('woocommerce_variation_set_stock', $product_with_stock);
			} else {
				do_action('woocommerce_product_set_stock', $product_with_stock);
			}

			return $product_with_stock->get_stock_quantity();
		}
		return $product->get_stock_quantity();
	}

    public function wc_get_low_stock_amount(WC_Product $product)
	{
		if ($product->is_type('variation')) {
			$product = wc_get_product($product->get_parent_id());
		}
		$low_stock_amount = $product->get_low_stock_amount();
		if ('' === $low_stock_amount) {
			$low_stock_amount = get_option('woocommerce_notify_low_stock_amount', 2);
		}

		return $low_stock_amount;
	}
}
