<?php
use Automattic\WooCommerce\Utilities\OrderUtil; 
trait Wcmlim_Backend_Order_Functions{
public function action_woocommerce_saved_order( $order_id, $items = null ) {
    $postaction = isset($_POST['action']) ? $_POST['action'] : "";
    
    // Check if this is a shop order
    if(WC_HPOS_IS_ACTIVE){
      $post_type = OrderUtil::get_order_type( $order_id );
    } else {
      $post_type = get_post_type( $order_id ); 
    }

    if( 'shop_order' != $post_type ) {
      return;
    }
    
    $order = wc_get_order( $order_id );
    
    // Check order status - only process stock for specific statuses
    $order_status = $order->get_status();
    $allowed_statuses = array('pending', 'processing', 'completed', 'on-hold', 'auto-draft');
    
    $item_storeid = array(); 
    $locChanges = [];
    $locChanges2 = [];
    
    // Process each order item
    foreach ( $order->get_items() as $item_id => $item ) {
      // Get location data from POST or existing meta
      $order_s1 = '_locationtermid_' . $item_id;
      $order_s2 = '_locationKey_' . $item_id;
      $sltermid = filter_input( INPUT_POST, $order_s1 );
      $sltermkey = filter_input( INPUT_POST, $order_s2 );
      
      // If POST values are empty strings, treat as null
      if($sltermid === '') $sltermid = null;
      if($sltermkey === '') $sltermkey = null;
      
      $old_term_id = intval(wc_get_order_item_meta( $item_id, '_selectedLocTermId', true));      
      
      // Determine location term ID and key
      $term_id = ($sltermid === null || $sltermid === false) ? $old_term_id : intval($sltermid);
      $term_key = ($sltermkey === null || $sltermkey === false || $sltermkey === '0') ? 
                 intval(wc_get_order_item_meta( $item_id, '_selectedLocationKey', true)) : 
                 intval($sltermkey);      
      
      // Get location name from term
      $term = get_term($term_id);
      $term_name = ($term && !is_wp_error($term)) ? $term->name : 
                  wc_get_order_item_meta($item_id, 'Location', true);
            
      
      // Update order item meta FIRST before any stock operations      
      
      if($term_name) {
        wc_update_order_item_meta($item_id, 'Location', $term_name);        
      } else {
        wc_add_order_item_meta($item_id, 'Location', $term_name);        
      }
      
      if($term_key !== '') {
        wc_update_order_item_meta($item_id, '_selectedLocationKey', $term_key);        
      } else {
        wc_add_order_item_meta($item_id, '_selectedLocationKey', $term_key);        
      }
      
      if($term_id) {
        wc_update_order_item_meta($item_id, '_selectedLocTermId', $term_id);        
      } else {
        wc_add_order_item_meta($item_id, '_selectedLocTermId', $term_id);        
      }
      
      // Save the item to ensure meta is persisted before stock operations
      $item->save();      
      
      // Verify the meta was actually saved
      $saved_term_id = wc_get_order_item_meta($item_id, '_selectedLocTermId', true);
      $saved_location = wc_get_order_item_meta($item_id, 'Location', true);      
      
      // Now handle stock operations with the correct location data
      if($term_id && in_array($order_status, $allowed_statuses)) {        
        
        // Check if stock has already been reduced for this item
        $item_stock_reduced = $item->get_meta('_reduced_stock', true);        
        
        // Check if this is a location assignment (POST has new value different from old)
        $is_new_location_assignment = ($sltermid !== null && $sltermid !== false && intval($sltermid) != $old_term_id);
        
        // If stock was already reduced AND location changed from one location to another, handle transfer
        if($item_stock_reduced && $is_new_location_assignment && $old_term_id > 0) {          
          $this->handle_location_stock_transfer($order_id, $item_id, $old_term_id, $term_id, $item->get_quantity());
        } 
        // If stock was already reduced but no location was set (old_term_id = 0), and now we're assigning one
        else if($item_stock_reduced && $is_new_location_assignment && $old_term_id == 0) {
          // Stock was reduced from default location, now properly assign it
          // We need to reduce from the newly selected location since it wasn't reduced from there yet
          
          $product_id = $item->get_variation_id() ?: $item->get_product_id();
          $item_quantity = $item->get_quantity();
          
          // Reduce stock at the selected location
          $current_stock = get_post_meta($product_id, "wcmlim_stock_at_{$term_id}", true);
          $new_stock = max(0, intval($current_stock) - intval($item_quantity));
          update_post_meta($product_id, "wcmlim_stock_at_{$term_id}", $new_stock);
          
          // Update total stock
          $this->wcmlim_update_totaldata($product_id);
          
          $location_term = get_term($term_id);
          $location_name = $location_term ? $location_term->name : "Location #{$term_id}";
          
          $order->add_order_note(sprintf(
            "Stock levels reduced: %s from Location: %s %d → %d (first-time location assignment)",
            $item->get_name(),
            $location_name,
            $current_stock,
            $new_stock
          ));
        }
        else if(!$item_stock_reduced && $term_id) {
          // Stock not yet reduced - reduce stock for this specific order
          // This handles both new orders and first-time location assignments
          $this->wcmlim_maybe_reduce_stock_levels($order_id);
        }
      } else if (!$term_id && in_array($order_status, $allowed_statuses)) {
        // Also try to reduce stock for new items without term_id set
        $this->wcmlim_maybe_reduce_stock_levels($order_id);
      }
      
      // Track unique location IDs used in this order
      if(!in_array($term_id, $item_storeid) && $term_id) {
        $item_storeid[] = $term_id;
      }
    }
    
    // Prepare location data for order meta
    $dataLocate = array();
    if (!empty($item_storeid)) {
      foreach($item_storeid as $wcmlim_locid) {
        $term_object = get_term($wcmlim_locid);
        if ($term_object && !is_wp_error($term_object)) {
          $dataLocate[] = $term_object->term_id;
        }
      }
    }
    
    // Update order meta with location data
    if(!empty($dataLocate)) {
      if (WC_HPOS_IS_ACTIVE) {
        $order->update_meta_data('_multilocation', $dataLocate);
      } else {
        update_post_meta($order_id, "_multilocation", $dataLocate);
      }
    }

    if(!empty($term_name)) {
      if (WC_HPOS_IS_ACTIVE) {
        $order->update_meta_data('_location', $term_name);
      } else {
        update_post_meta($order_id, "_location", $term_name);
      }
    }
    
    // Add order notes if stock levels changed
    if (!empty($locChanges) || !empty($locChanges2)) {
      if (!empty($locChanges)) $order->add_order_note(implode(', ', $locChanges));
      if (!empty($locChanges2)) $order->add_order_note(implode(', ', $locChanges2));
      do_action('woocommerce_restore_order_stock', $order);
    }
    
    $order->save();
}

/**
 * Handle stock transfer between locations when location is changed
 */
private function handle_location_stock_transfer($order_id, $item_id, $old_location_id, $new_location_id, $quantity) {
  $order = wc_get_order($order_id);
  
  // Check order status - only handle 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 handle stock for this order status
  }
  
  $item = new WC_Order_Item_Product($item_id);
  $product_id = $item->get_variation_id() ?: $item->get_product_id();
  
  // Check if stock was already reduced for this item
  $item_stock_reduced = $item->get_meta('_reduced_stock', true);
  
  if ($item_stock_reduced) {
    // Stock was already reduced from old location, now transfer to new location
    
    // Restore stock to old location
    $old_stock = get_post_meta($product_id, "wcmlim_stock_at_{$old_location_id}", true);
    $restored_stock = intval($old_stock) + intval($quantity);
    update_post_meta($product_id, "wcmlim_stock_at_{$old_location_id}", $restored_stock);
    
    // Reduce stock from new location
    $new_stock = get_post_meta($product_id, "wcmlim_stock_at_{$new_location_id}", true);
    $reduced_stock = max(0, intval($new_stock) - intval($quantity));
    update_post_meta($product_id, "wcmlim_stock_at_{$new_location_id}", $reduced_stock);
    
    // Update total stock
    $this->wcmlim_update_totaldata($product_id);
    
    // Add order note
    $old_term = get_term($old_location_id);
    $new_term = get_term($new_location_id);
    $order->add_order_note("Stock transferred: {$item->get_name()} from {$old_term->name} to {$new_term->name}");
  } else {
    // Stock hasn't been reduced yet, just reduce from new location
    $this->wcmlim_maybe_reduce_stock_levels($order_id);
  }
}


/**
 * Function responsible for processing order items based on fulfillment rules
 * 
 * @since 3.0.7
 */
public function wcmlim_fulfil_saved_order_items($order_id) {
    if (!$order_id) {
        return;
    }
    
    $order = wc_get_order($order_id);
    if (!$order) {
        return;
    }
    
    // Check if order was already processed to prevent double processing
    $wcmlim_order_placed_once = (WC_HPOS_IS_ACTIVE) ? 
        $order->get_meta("wcmlim_order_placed_once", true) : 
        get_post_meta($order_id, "wcmlim_order_placed_once", true);
        
    if ($wcmlim_order_placed_once == 'yes') {
        return;
    }
    
    $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
    $routeRules = get_option("wcmlim_order_fulfilment_rules");
    
    // Normalize rule name
    if ($routeRules == "nearby_instock") {
        $routeRules = "clcsadd";
    }
    
    // Track locations used for order fulfillment
    $locations_with_stock = array();
    $primary_location_name = '';
    
    foreach ($order->get_items() as $item_id => $item) {
        $product_id = $item->get_variation_id() ?: $item->get_product_id();
        $item_quantity = $item->get_quantity();
        
        switch ($routeRules) {
            case "maxinvloc":
                $used_locations = $this->stock_fullfllment_for_next_loc($product_id, $item_quantity, $item_id, $order, "most_inventory");
                if (is_array($used_locations)) {
                    $locations_with_stock = array_merge($locations_with_stock, $used_locations);
                }
                break;
                
            case "locappriority":
                $this->process_location_priority($product_id, $item_id, $item, $item_quantity, $terms, $order, $order_id);
                break;
                
            case "nearby_instock":
                $used_locations = $this->process_nearby_instock($product_id, $item_quantity);
                if (is_array($used_locations)) {
                    $locations_with_stock = array_merge($locations_with_stock, $used_locations);
                }
                break;
        }
    }
    
    // For maxinvloc and nearby_instock, collect locations from order items meta
    if (in_array($routeRules, ['maxinvloc', 'nearby_instock'])) {
        $locations_with_stock = array();
        foreach ($order->get_items() as $item_id => $item) {
            $selected_location_id = $item->get_meta('_selectedLocTermId', true);
            if (!empty($selected_location_id)) {
                $locations_with_stock[] = $selected_location_id;
                
                // Get primary location name from first item
                if (empty($primary_location_name)) {
                    $location_term = get_term($selected_location_id);
                    if ($location_term && !is_wp_error($location_term)) {
                        $primary_location_name = $location_term->name;
                    }
                }
            }
        }
        $locations_with_stock = array_unique($locations_with_stock);
    }
    
    // Update order meta with location data - same logic as shipping zones function
    if (!empty($locations_with_stock)) {
        if (WC_HPOS_IS_ACTIVE) {
            $order->update_meta_data('_multilocation', $locations_with_stock);
            $order->update_meta_data("wcmlim_order_placed_once", 'yes');
        } else {
            update_post_meta($order_id, "_multilocation", $locations_with_stock);
            update_post_meta($order_id, 'wcmlim_order_placed_once', 'yes');
        }
    }
    
    // Update order meta with primary location name if available
    if (!empty($primary_location_name)) {
        if (WC_HPOS_IS_ACTIVE) {
            $order->update_meta_data('_location', $primary_location_name);
        } else {
            update_post_meta($order_id, "_location", $primary_location_name);
        }
    }
    
    $order->save();
}

/**
 * Process orders using location priority rule
 */
private function process_location_priority($product_id, $item_id, $item, $item_quantity, $terms, $order, $order_id) {
    $priority = [];
    $lker = [];
    $locPriority = [];
    
    // Build location priority arrays
    foreach ($terms as $k => $t) {
        $locPriority[$t->term_id] = get_post_meta($product_id, 'wcmlim_stock_at_' . $t->term_id, true);
        $cvalterm = get_term_meta($t->term_id, 'wcmlim_location_priority', true);
        if ($cvalterm !== null && $cvalterm !== false) {
            $priority[$cvalterm] = $t->term_id;
            $lker[$cvalterm] = $k;
        }
    }
    
    if (!empty($priority) && is_array($priority)) {
        ksort($priority); // Sort by priority
        
        $remaining_quantity = $item_quantity;
        $processed_locations = [];
        
        foreach ($priority as $key => $val) {
            if ($remaining_quantity <= 0) {
                break; // All quantity processed
            }
            
            $location_stock = (int)get_post_meta($product_id, "wcmlim_stock_at_{$val}", true);
            if ($location_stock <= 0) {
                continue; // Skip locations with no stock
            }
            
            $termname = get_term($val)->name;
            $getKey = $lker[$key];
            $set_location = wc_get_order_item_meta($item_id, 'Location', true);
            
            // Set location meta if not already set
            if (empty($set_location)) {
                wc_add_order_item_meta($item_id, '_selectedLocTermId', $val);
                wc_add_order_item_meta($item_id, '_old_selectedLocTermId', $val);
                wc_add_order_item_meta($item_id, 'Location', $termname);
                wc_add_order_item_meta($item_id, '_selectedLocationKey', $getKey);
                $processed_locations[] = $val;
            }
            
            if ($remaining_quantity <= $location_stock) {
                // Location has enough stock for remaining quantity
                update_post_meta($product_id, 'wcmlim_stock_at_' . $val, $location_stock - $remaining_quantity);
                $note = "Priority wise location Stock levels reduced: {$item->get_name()} from Location: {$termname} {$location_stock} → " . ($location_stock - $remaining_quantity);
                $order->add_order_note($note);
                $remaining_quantity = 0;
            } else {
                // Location doesn't have enough stock - use what's available
                // Update original item to use all stock from this location
                wc_update_order_item_meta($item_id, '_qty', $location_stock);
                update_post_meta($product_id, 'wcmlim_stock_at_' . $val, 0);
                $note = "Priority wise location Stock levels reduced: {$item->get_name()} from Location: {$termname} {$location_stock} → 0";
                $order->add_order_note($note);
                
                // Create new item for remaining quantity
                $remaining_quantity -= $location_stock;
                if ($remaining_quantity > 0) {
                    $this->create_new_order_item_for_remaining($item, $product_id, $remaining_quantity, $order, $priority, $key, $lker, $val);
                }
            }
            
            // Update order meta with location data
            $this->update_order_location_meta($order, $order_id, $processed_locations, $termname);
            $this->sendnotification_formanager($val, $order_id);
            $this->wcmlim_update_totaldata($product_id);
            
            // If all quantity has been processed, break out of the loop
            if ($remaining_quantity <= 0) {
                break;
            }
        }
    }
}

/**
 * Create a new order item for remaining quantity when splitting between locations
 */
private function create_new_order_item_for_remaining($original_item, $product_id, $remaining_quantity, $order, $priority, $current_key, $lker, $current_val) {
    // Get product
    $product = wc_get_product($product_id);
    if (!$product) {
        return;
    }
    
    // Create new item
    $new_item = new WC_Order_Item_Product();
    $new_item->set_product($product);
    $new_item->set_quantity($remaining_quantity);
    
    // Get original item quantities and values
    $original_qty = $original_item->get_quantity();
    
    // Get prices and tax data from 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();
    
    // Calculate per-unit values
    $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;
    
    // Set exact pricing values for new item
    $new_item->set_subtotal($unit_subtotal * $remaining_quantity);
    $new_item->set_total($unit_total * $remaining_quantity);
    $new_item->set_subtotal_tax($unit_subtotal_tax * $remaining_quantity);
    $new_item->set_total_tax($unit_total_tax * $remaining_quantity);
    
    // Copy the original tax data with adjusted amounts
    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 * $remaining_quantity;
        }
        
        foreach ($original_taxes['subtotal'] as $tax_id => $tax_amount) {
            $tax_per_unit = $tax_amount / $original_qty;
            $new_taxes['subtotal'][$tax_id] = $tax_per_unit * $remaining_quantity;
        }
        
        $new_item->set_taxes($new_taxes);
    }
    
    // Find next location with stock
    $next_location_set = false;
    
    foreach ($priority as $new_key => $new_val) {
        // Skip current and previous locations
        if ($new_key <= $current_key) {
            continue;
        }
        
        $next_stock = (int)get_post_meta($product_id, "wcmlim_stock_at_{$new_val}", true);
        if ($next_stock > 0) {
            $next_term = get_term($new_val);
            if ($next_term && !is_wp_error($next_term)) {
                $new_termname = $next_term->name;
                $new_item->add_meta_data('Location', $new_termname);
                $new_item->add_meta_data('_selectedLocTermId', $new_val);
                $new_item->add_meta_data('_old_selectedLocTermId', $new_val); // stock-update-fix
                $new_item->add_meta_data('_selectedLocationKey', $lker[$new_key]);
                $next_location_set = true;
                break;
            }
        }
    }
    
    if (!$next_location_set) {
        // If no location with stock was found, use the first location in priority list
        foreach ($priority as $new_key => $new_val) {
            $next_term = get_term($new_val);
            if ($next_term && !is_wp_error($next_term) && $new_val != $current_val) {
                $new_termname = $next_term->name;
                $new_item->add_meta_data('Location', $new_termname);
                $new_item->add_meta_data('_selectedLocTermId', $new_val);
                $new_item->add_meta_data('_old_selectedLocTermId', $new_val); // stock-update-fix
                $new_item->add_meta_data('_selectedLocationKey', $lker[$new_key]);
                break;
            }
        }
    }
    
    // Add the new item to the order
    $order->add_item($new_item);
}

/**
 * Update order meta with location data
 */
private function update_order_location_meta($order, $order_id, $location_ids, $location_name) {
    if (empty($location_ids)) {
        return;
    }
    
    $dataLocate = [];
    foreach ($location_ids as $loc_id) {
        $term = get_term($loc_id);
        if ($term && !is_wp_error($term)) {
            $dataLocate[] = $term->term_id;
        }
    }
    
    if (!empty($dataLocate)) {
        if (WC_HPOS_IS_ACTIVE) {
            $order->update_meta_data('_multilocation', $dataLocate);
        } else {
            update_post_meta($order_id, "_multilocation", $dataLocate);
        }
    }
    
    if (!empty($location_name)) {
        if (WC_HPOS_IS_ACTIVE) {
            $order->update_meta_data('_location', $location_name);
        } else {
            update_post_meta($order_id, "_location", $location_name);
        }
    }
}

/**
 * Process nearby instock rule
 */
private function process_nearby_instock($product_id, $item_quantity) {
    global $woocommerce;
    $from_address = get_option('from_address');
    $used_locations = array();
    
    // Find the product in from_address
    $id_pml = -1;
    if (is_array($from_address)) {
        foreach ($from_address as $index => $item) {
            if (isset($item['product_id']) && $item['product_id'] == $product_id) {
                $id_pml = $index;
                break;
            }
        }
    }
    
    if ($id_pml >= 0 && isset($from_address[$id_pml]['nearby_id_location'])) {
        $location_id = $from_address[$id_pml]['nearby_id_location'];
        $postmeta_stock_at_term = get_post_meta($product_id, 'wcmlim_stock_at_' . $location_id, true);
        update_post_meta($product_id, 'wcmlim_stock_at_' . $location_id, $postmeta_stock_at_term - $item_quantity);
        $used_locations[] = $location_id;
    }
    
    return $used_locations;
}

/**
 * Function responsible for adding location dropdown to each line item
 * Optimized version with consolidated logic
 */
public function add_orders_multi_inventory_ui($item_id, $item, $order = NULL) {
    if (!$item) {
        return;
    }
    
    $product_id = $item->get_variation_id() ? $item->get_variation_id() : $item->get_product_id();

    $loc_ids_as_per_user = $this->get_user_available_location_ids();
    $terms = get_terms(array(
        'taxonomy' => 'locations',
        'hide_empty' => false,
        'parent' => 0,
        'include' => $loc_ids_as_per_user,
    ));
   
    // Get existing location
    $result = wc_get_order_item_meta($item_id, 'Location', true);
    $location_term_id = '';
    
    if (!empty($result) || $result === '0') {
        $termtax = get_term_by('name', $result, 'locations');
        if ($termtax) {
            $location_term_id = $termtax->term_id;
        }
    }
    
    // Get fulfillment rule
    $routeRules = get_option("wcmlim_order_fulfilment_rules");
    if ($routeRules == "nearby_instock") {
        $routeRules = "clcsadd";
    }
    
    // Get nearby location data if needed
    $nearby_location = '';
    $nearby_name = '';
    $from_address = get_option('from_address');
    
    if (isset($from_address) && is_array($from_address)) {
        foreach ($from_address as $value) {
            if ($value['product_id'] == $item->get_product_id() || $value['product_id'] == $item->get_variation_id()) {
                $nearby_location = $value['nearby_id_location'];
                $nearby_name = $value['name'];
                break;
            }
        }
    }
    
    // Prepare location data based on rule
    $lk = [];
    $lk2 = [];
    
    // Generate dropdown HTML
    ?>
    <tr class="order-item-wcml-panel" data-sort-ignore="true" data-order_item_id="<?php echo $item_id; ?>">
        <td colspan="100">
            <div class="order-item-wcml-wrapper">
                <div class="form-group">
                    <label for="_bom_location"><?php _e('Location:', 'wcmlim'); ?></label> 
                    <select id="_bom_location_<?= $item_id ?>" name="_bom_location_<?= $item_id ?>" style="width:auto">
                        <option value=""><?php _e('Select location', 'wcmlim'); ?></option>
                        <?php
                        $selected_quantity = $item->get_quantity();
                        $this->render_default_location_options($product_id, $terms, $location_term_id, $selected_quantity, $lk, $lk2);
                        ?>
                    </select>
                    <input id="_locationKey_<?= $item_id ?>" type="hidden" name="_locationKey_<?= $item_id ?>" 
                           value="<?php echo (!empty($lk)) ? $lk[0] : ''; ?>" />
                    <input id="_locationtermid_<?= $item_id ?>" type="hidden" name="_locationtermid_<?= $item_id ?>" 
                           value="<?php echo (!empty($lk2)) ? $lk2[0] : ''; ?>" />
                </div>
            </div>
        </td>
    </tr>
    <script>
    jQuery(document).ready(function() {
        jQuery(document).on("change", ".order-item-wcml-wrapper select", function() {
            const selectedtermid = jQuery(this).find("option:selected").val();
            const locationKey = jQuery(this).find("option:selected").attr('data-lc-key');
            let itemid = jQuery(this).closest(".order-item-wcml-panel").data("order_item_id");
            jQuery(this).closest(".order-item-wcml-panel").find("#_locationKey_" + itemid).val(locationKey);
            jQuery(this).closest(".order-item-wcml-panel").find("#_locationtermid_" + itemid).val(selectedtermid);
        });
    });
    </script>
    <?php
}

/**
 * Render max inventory location options
 */
private function render_maxinvloc_options($product_id, $terms, $location_term_id) {
    $maxStockLoc = [];
    $lker = [];
    
    // Gather stock information
    foreach ($terms as $k => $t) {
        $maxStockLoc[$t->term_id] = get_post_meta($product_id, 'wcmlim_stock_at_' . $t->term_id, true);
        $lker[$t->term_id] = $k;
    }
    
    // Find location with maximum stock
    $maxValue = !empty($maxStockLoc) ? max($maxStockLoc) : 0;
    $maxKey = array_search($maxValue, $maxStockLoc);
    
    if ($location_term_id != $maxKey && $location_term_id) {
        // Show selected location if different from max inventory location
        $location_term = get_term($location_term_id);
        if ($location_term && !is_wp_error($location_term)) {
            $location_stock = get_post_meta($product_id, "wcmlim_stock_at_{$location_term_id}", true);
            echo '<option class="maxinvloc" data-lc-key="' . $location_term_id . '" value="' . 
                  esc_attr($location_term_id) . '" selected="selected">' . 
                  $location_term->name . ' - ' . $location_stock . '</option>';
        }
    } else if ($maxKey) {
        // Show max inventory location
        $maxTerm = get_term($maxKey);
        if ($maxTerm && !is_wp_error($maxTerm)) {
            $maxStockAtLoc = get_post_meta($product_id, "wcmlim_stock_at_{$maxKey}", true);
            echo '<option class="maxinvloc" data-lc-key="' . $lker[$maxKey] . '" value="' . 
                  esc_attr($maxKey) . '" ' . 
                  (($location_term_id == $maxKey) ? 'selected="selected"' : '') . '>' . 
                  $maxTerm->name . ' - ' . $maxStockAtLoc . '</option>';
        }
    }
}

/**
 * Render location priority options
 */
private function render_locappriority_options($product_id, $terms, $location_term_id, $selected_quantity) {
    $priority = [];
    $lker = [];
    
    // Build priority array
    foreach ($terms as $k => $t) {
        $cvalterm = get_term_meta($t->term_id, 'wcmlim_location_priority', true);
        if ($cvalterm !== null && $cvalterm !== false) {
            $priority[$cvalterm] = $t->term_id;
            $lker[$cvalterm] = $k;
        }
    }
    
    if (isset($priority) && is_array($priority)) {
        ksort($priority); // Sort by priority
        
        foreach ($priority as $key => $val) {
            $stock = (int)get_post_meta($product_id, "wcmlim_stock_at_{$val}", true);
            if ($stock > 0) {
                $term = get_term($val);
                if ($term && !is_wp_error($term)) {
                    $disabled = ($stock < $selected_quantity) ? 'disabled' : '';
                    echo '<option class="priority" data-lc-key="' . $key . '" value="' . 
                          esc_attr($val) . '" ' . 
                          (($location_term_id == $val) ? 'selected="selected"' : '') . ' ' . 
                          $disabled . '>' . 
                          $term->name . ' - (' . $stock . ')</option>';
                }
            }
        }
    }
}

/**
 * Render default location options
 */
private function render_default_location_options($product_id, $terms, $location_term_id, $selected_quantity, &$lk, &$lk2) {
    foreach ($terms as $id => $value) {
        $stock = get_post_meta($product_id, "wcmlim_stock_at_{$value->term_id}", true);
        
        // Track selected location
        if (!empty($location_term_id) && $value->term_id == $location_term_id) {
            $lk[] = $id;
            $lk2[] = $value->term_id;
        }
        
        // Only show locations with stock
        if ($stock !== null && $stock !== false) {
            $stock = (int)$stock;
            if ($stock > 0) {
                $is_disabled = ($selected_quantity > $stock) ? 'disabled' : '';
                $selected = ($location_term_id == $value->term_id) ? 'selected' : '';
                
                echo '<option class="default" ' . $selected . ' data-lc-key="' . $id . '" value="' . 
                      $value->term_id . '" ' . $is_disabled . '>' . 
                      $value->name . ' - (' . $stock . ')</option>';
            }
        }
    }
}

/**
 * Hide Order Item Meta
 */
public function wcmlim_hidden_order_itemmeta($args) {
    $args[] = '_selectedLocationKey';
    $args[] = '_selectedLocTermId';
    $args[] = '_old_selectedLocTermId'; // stock-update-fix
    return $args;
}

/**
 * Add location meta to order items
 */
public function add_order_item_meta($item_id, $cart_item, $cart_item_key) {
    if (isset($cart_item['select_location'])) {
        $values = $cart_item['select_location'];
        
        // Add all required meta in one go
        wc_add_order_item_meta($item_id, "Location", $values["location_name"]);
        wc_add_order_item_meta($item_id, "_selectedLocationKey", $values["location_key"]);
        wc_add_order_item_meta($item_id, "_selectedLocTermId", $values["location_termId"]);
        wc_add_order_item_meta($item_id, "_old_selectedLocTermId", $values["location_termId"]); // stock-update-fix
        
        setLocation("wcmlim_selected_location", $values["location_key"], 36000);
    }
}

/**
 * Get locations managed by regional manager
 */
public function getShopRegional_MangersLocation($current_user_id) {
    $taxonomies = get_terms(array('taxonomy' => 'location_group', 'hide_empty' => false, 'parent' => 0));
    $result = array();
    
    if (!empty($taxonomies)) {
        foreach ($taxonomies as $term) {            
            $regshopManager = get_term_meta($term->term_id, "wcmlim_shop_regmanager", true);            
            
            if (!empty($regshopManager)) {
                if (in_array($current_user_id, $regshopManager)) {
                    $locationId1 = $term->term_id;
                    $terms_ID = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
                    $items = array();
                    
                    foreach ($terms_ID as $k => $term2) {
                        $locationgID2 = get_term_meta($term2->term_id, "wcmlim_locator", true);
                        if ($locationId1 == $locationgID2) {
                            $locationNames = $term2->term_id;
                            $wordCount = explode(" ", $locationNames);
                            if (count($wordCount) > 1) {
                                $_location = str_replace(' ', '-', strtolower($locationNames));
                            } else {
                                $_location = $locationNames;
                            }
                            if (preg_match('/"/', $_location)) {
                                $_location = str_replace('"', '', $_location);
                            }
                            $items[] = $_location;
                        }
                    }
                    
                    $result[] = $items;
                } else {
                    $url = admin_url('edit.php?post_type=shop_order');
                    wp_safe_redirect($url);
                    exit;
                }
            }
        }
        return $result;
    }
    return array();
}

/**
 * Get available location IDs for current user based on role.
 * Returns array of location term IDs.
 */
private function get_user_available_location_ids() {
    $current_user = wp_get_current_user();
    $cuserId = $current_user->ID;
    $cuserRoles = $current_user->roles;

    // Administrator: return all location IDs
    if (in_array('administrator', $cuserRoles)) {
        $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
        return wp_list_pluck($terms, 'term_id');
    }

    $available_location_ids = [];

    // Regional Manager: get locations managed by this user
    if (in_array('location_regional_manager', $cuserRoles) && method_exists($this, 'getShopRegional_MangersLocation')) {
        $regional_locations = $this->getShopRegional_MangersLocation($cuserId);
        foreach ($regional_locations as $locations_group) {
            if (is_array($locations_group)) {
                foreach ($locations_group as $loc_id) {
                    $available_location_ids[] = $loc_id;
                }
            }
        }
        return array_unique($available_location_ids);
    }

    // Shop Manager: get locations managed by this user
    if (in_array('location_shop_manager', $cuserRoles)) {
        $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
        foreach ($terms as $term) {
            $shopM = get_term_meta($term->term_id, 'wcmlim_shop_manager', true);
            if (is_array($shopM) && in_array($cuserId, $shopM)) {
                $available_location_ids[] = $term->term_id;
            }
        }
        return array_unique($available_location_ids);
    }

    // Default: no locations
    return [];
}

}
?>