<?php

/**
 * The admin-specific functionality of the plugin.
 *
 * Defines the plugin name, version, and two examples hooks for how to
 * enqueue the admin-specific stylesheet and JavaScript.
 * 
 * @link       http://www.techspawn.com
 * @since      1.0.0
 * @package    Wcmlim
 * @subpackage Wcmlim/includes
 * @author     techspawn1 <contact@techspawn.com>
 */

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
  exit;
}

// Load WP_List_Table if not loaded
if ( ! class_exists( 'WP_List_Table' ) ) {
  require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}

class Multiloc_Product_Central extends WP_List_Table
{
  private $products_query;
  
  function __construct()
  {
    global $status, $page;

    parent::__construct(array(
      'singular' => 'product_bulk_edit',
      'plural' => 'prodcentral_bulk_edit',
    ));
  }

  public function no_items()
  {
    esc_html_e('No Products found.');
  }

  /**
   * Override get_pagenum to use custom pagination parameter
   * 
   * @return int Current page number
   */
  public function get_pagenum() {
    $pagenum = isset($_REQUEST['c_paged']) ? absint($_REQUEST['c_paged']) : 0;
    if (isset($this->_pagination_args['total_pages']) && $pagenum > $this->_pagination_args['total_pages']) {
      $pagenum = $this->_pagination_args['total_pages'];
    }
    return max(1, $pagenum);
  }

  /**
   * Override pagination display to use custom parameter name
   * 
   * @param string $which Position of pagination (top or bottom)
   */
  protected function pagination($which) {
    if (empty($this->_pagination_args)) {
      return;
    }

    $total_items = $this->_pagination_args['total_items'];
    $total_pages = $this->_pagination_args['total_pages'];
    $infinite_scroll = false;

    if (isset($this->_pagination_args['infinite_scroll'])) {
      $infinite_scroll = $this->_pagination_args['infinite_scroll'];
    }

    if ('top' === $which && $total_pages > 1) {
      $this->screen->render_screen_reader_content('heading_pagination');
    }

    $output = '<span class="displaying-num">' . sprintf(
      _n('%s item', '%s items', $total_items),
      number_format_i18n($total_items)
    ) . '</span>';

    $current = $this->get_pagenum();
    $removable_query_args = wp_removable_query_args();

    $current_url = set_url_scheme('http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
    $current_url = remove_query_arg($removable_query_args, $current_url);
    
    // Ensure tab parameter is preserved
    if (!isset($_GET['tab'])) {
      $current_url = add_query_arg('tab', 'tab-1', $current_url);
    }

    $page_links = array();

    $total_pages_before = '<span class="paging-input">';
    $total_pages_after  = '</span></span>';

    $disable_first = $disable_last = $disable_prev = $disable_next = false;

    if ($current == 1) {
      $disable_first = true;
      $disable_prev  = true;
    }
    if ($current == 2) {
      $disable_first = true;
    }
    if ($current == $total_pages) {
      $disable_last = true;
      $disable_next = true;
    }
    if ($current == $total_pages - 1) {
      $disable_last = true;
    }

    if ($disable_first) {
      $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&laquo;</span>';
    } else {
      $page_links[] = sprintf(
        "<a class='first-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
        esc_url(remove_query_arg('c_paged', $current_url)),
        __('First page'),
        '&laquo;'
      );
    }

    if ($disable_prev) {
      $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&lsaquo;</span>';
    } else {
      $page_links[] = sprintf(
        "<a class='prev-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
        esc_url(add_query_arg('c_paged', max(1, $current - 1), $current_url)),
        __('Previous page'),
        '&lsaquo;'
      );
    }

    if ('bottom' === $which) {
      $html_current_page  = $current;
      $total_pages_before = '<span class="screen-reader-text">' . __('Current Page') . '</span><span id="table-paging" class="paging-input"><span class="tablenav-paging-text">';
    } else {
      $html_current_page = sprintf(
        "%s<input class='current-page' id='current-page-selector' type='text' name='c_paged' value='%s' size='%d' aria-describedby='table-paging' /><span class='tablenav-paging-text'>",
        '<label for="current-page-selector" class="screen-reader-text">' . __('Current Page') . '</label>',
        $current,
        strlen($total_pages)
      );
    }
    $html_total_pages = sprintf("<span class='total-pages'>%s</span>", number_format_i18n($total_pages));
    $page_links[]     = $total_pages_before . sprintf(_x('%1$s of %2$s', 'paging'), $html_current_page, $html_total_pages) . $total_pages_after;

    if ($disable_next) {
      $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
    } else {
      $page_links[] = sprintf(
        "<a class='next-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
        esc_url(add_query_arg('c_paged', min($total_pages, $current + 1), $current_url)),
        __('Next page'),
        '&rsaquo;'
      );
    }

    if ($disable_last) {
      $page_links[] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&raquo;</span>';
    } else {
      $page_links[] = sprintf(
        "<a class='last-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
        esc_url(add_query_arg('c_paged', $total_pages, $current_url)),
        __('Last page'),
        '&raquo;'
      );
    }

    $pagination_links_class = 'pagination-links';
    if (!empty($infinite_scroll)) {
      $pagination_links_class .= ' hide-if-js';
    }
    $output .= "\n<span class='$pagination_links_class'>" . join("\n", $page_links) . '</span>';

    if ($total_pages) {
      $page_class = $total_pages < 2 ? ' one-page' : '';
    } else {
      $page_class = ' no-pages';
    }
    $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";

    echo $this->_pagination;
  }

  /**
   * Render stock status column
   * 
   * @param array $item Product data
   * @return string HTML output
   */
  private function render_stock_status($item) {
    $checked_val = ($item['stock_status'] == 'instock') ? 'checked' : '';
    $cust_stock_val = ($item['stock_status'] == 'instock') ? 'Yes' : 'No';
    
    return sprintf(
      '<label class="switch"><input type="checkbox" %s id="check_%s"><span class="slider round"></span></label>' .
      '<label class="stckup_product_stock_status check_%s %s %%s"> %s</label>' .
      '<div class="empty_to_cll_action"> </div>' .
      '<input class="clickedit check_%s" data-id="%%s" data-name="stckup_product_stock_status" type="hidden" />' .
      '<div class="clearfix"></div>',
      $checked_val,
      $item['id'],
      $item['id'],
      $cust_stock_val,
      $cust_stock_val,
      $item['id']
    );
  }

  /**
   * Render manage stock column
   * 
   * @param array $item Product data
   * @return string HTML output
   */
  private function render_manage_stock($item) {
    $check_val = ($item['manage_stock'] == "yes" || $item['manage_stock'] == 1) ? 'checked' : '';
    $cus_stock_manage = ($item['manage_stock'] == "yes" || $item['manage_stock'] == 1) ? 'Yes' : 'No';
    
    return sprintf(
      '<label class="switch"><input type="checkbox" %s id="check_%s"><span class="slider round"></span></label>' .
      '<label class="product_stock_manage check_%s %s %%s"> %s</label>' .
      '<div class="empty_to_cll_action"> </div>' .
      '<input class="clickedit check_%s" data-id="%%s" data-name="product_stock_manage" type="hidden" />' .
      '<div class="clearfix"></div>',
      $check_val,
      $item['id'],
      $item['id'],
      $cus_stock_manage,
      $cus_stock_manage,
      $item['id']
    );
  }

  /**
   * Render backorders column
   * 
   * @param array $item Product data
   * @return string HTML output
   */
  private function render_backorders($item) {
    if (!empty($item['backorders'])) {
      $backorderlbl = $item['backorders'];
      if ($backorderlbl == "notify") {
        $backorderlbl = "Allow, but notify customer";
      } else if($backorderlbl == "yes") {
        $backorderlbl = "Allow";
      } else {
        $backorderlbl = "Do not allow";
      }
      
      return sprintf(
        '<label class="lbledit stckup_product_backorders" >%s</label>' .
        '<select class="clickedit bulk_product_backorder_edit" data-name="stckup_product_backorders" Pid="pid_%s" data-id="%s">' .
        '<option value="-1">Select Below</option>' .
        '<option value="no">NO Backdoor</option>' .
        '<option value="notify">Backorder notify</option>' .
        '<option value="yes">yes backdoor</option>' .
        '</select>' .
        '<input class="pid_%s"  class="clickedit" data-name="stckup_product_backorders" data-id="%s" type="hidden" />' .
        '<div class="clearfix"></div>',
        $backorderlbl,
        $item['id'],
        $item['id'],
        $item['id'],
        $item['id'],
      );
    }
    
    return sprintf(
      '<label class="lbledit stckup_product_backorders" >%s</label>' .
      '<input value="%s" class="clickedit" data-name="stckup_product_backorders" data-id="%s" type="text" />' .
      '<div class="clearfix"></div>',
      '--',
      '--',
      $item['id']
    );
  }

  /**
   * Render stock at location column
   * 
   * @param array $item Product data
   * @return string HTML output
   */
  private function render_stock_at_location($item) {
    $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
    $stock_at_location = '';
    
    if (empty($terms)) {
      return '';
    }
    
    $managesimple_stock = get_post_meta($item['id'], '_manage_stock', true);
    if (!$managesimple_stock || $managesimple_stock == 'no') {
      return sprintf(
        '<label class="lbledit stckup_product_stock_at_location">%s</label>' .
        '<input class="stock_at_location" data-id="%s" data-name="stckup_product_stock_at_location" type="text" />' .
        '<div class="clearfix"></div>', 
        '<span style="font-weight: 800;color: #e2401c;">Manage Stock Option Disabled</span>',
        $item['id']
      );
    }
    
    // Build location HTML only once with a loop
    foreach ($terms as $term) {
      if (!isset($term->term_id)) {
        continue;
      }
      
      // Force $stock_location to integer for consistency and safe comparison
      $stock_location = (int) get_post_meta($item['id'], "wcmlim_stock_at_{$term->term_id}", true);

      $product = wc_get_product($item['id']);
      $product_type = $product->get_type();
      $parent_id = false;
      if ($product_type == 'variation') {
        $parent_id = wp_get_post_parent_id($item['id']);
      }
      $current_terms = wp_get_object_terms( ($parent_id != false)? $parent_id : $item['id'], 'locations', array('fields' => 'ids'));
      $term_is_linked = false;
      if(!in_array($term->term_id, $current_terms)) {
        // Check if the location is not empty , Stock can be 0 or greater
        $display_value = ($stock_location <= 0) ? '--' : $stock_location;
        $input_value = ($stock_location <= 0) ? '0' : $stock_location;
      } else {
        $term_is_linked = true;
        // Check if the location is not empty , Stock can be 0 or greater
        $display_value = $stock_location;
        $input_value = $stock_location;
      }
      

      $stock_at_location .= sprintf(
        '<strong><label class="stckup_product_stock_at_location">' . 
            ($term_is_linked ? '<span class="stock-tick">✅</span>' : '<span class="stock-tick">❌</span>') . ' %s : </label></strong>' .
        '<label class="lbledit stckup_product_stock_at_location">%s</label>' .
        '<input class="stock_at_location" value="%s" data-id="%s" data-name="stckup_product_stock_at_location" ' .
        'data-location="%s" type="text" /><div class="clearfix"></div>',
        $term->name,
        $display_value,
        $input_value,
        $item['id'],
        $term->term_id
    );
    }
    
    return $stock_at_location;
  }

  /**
   * Render product dimensions columns (weight, length, width, height)
   * 
   * @param array $item Product data
   * @param object $product WC_Product object
   * @param string $dimension_type Type of dimension
   * @return string HTML output
   */
  private function render_product_dimension($product, $product_id, $dimension_type) {
    $getter = "get_{$dimension_type}";
    
    if (method_exists($product, $getter) && !empty($product->$getter())) {
      $value = $product->$getter();
      return sprintf(
        '<label class="lbledit stckup_product_%s" >%s</label>' .
        '<input value="%s" class="clickedit" data-name="stckup_product_%s" data-id="%s" type="text" />' .
        '<div class="clearfix"></div>',
        $dimension_type,
        esc_html__($value, 'stckup'),
        esc_html__($value, 'stckup'),
        $dimension_type,
        $product_id
      );
    }
    
    return sprintf(
      '<label class="lbledit stckup_product_%s" >%s</label>' .
      '<input value="%s" class="clickedit" data-name="stckup_product_%s" data-id="%s" type="text" />' .
      '<div class="clearfix"></div>',
      $dimension_type,
      '--',
      '--',
      $dimension_type,
      $product_id
    );
  }

  function column_default($item, $column_name)
  {  
    $product_id = $item['id']; 
    
    // Only get product object once per row
    static $products = array();
    if (!isset($products[$product_id])) {
      $products[$product_id] = wc_get_product($product_id);
    }
    $product = $products[$product_id];
    
    switch ($column_name) {
      case 'thumbnail':
        $thumbnail_id = $item['thumbnail'];
        if ($thumbnail_id) {
          $thumbnail = wp_get_attachment_image_src($thumbnail_id, 'thumbnail'); 
          if ($thumbnail) {
            $thumbnail_url = $thumbnail[0];
            return '<img src="' . esc_url($thumbnail_url) . '" alt="Thumbnail" width="30px" height="30px">';
          }
        }
        return '';
        
      case 'stock_status':
        return sprintf($this->render_stock_status($item), esc_html__($item['stock_status'], 'stckup'), $item['id']);
        
      case 'stock_at_location':
        return $this->render_stock_at_location($item);
        
      case 'manage_stock':
        return sprintf($this->render_manage_stock($item), esc_html__($item['manage_stock'], 'stckup'), $item['id']);
        
      case 'backorders':
        return $this->render_backorders($item);
        
      case 'type':
        $product_type = $product ? $product->get_type() : '';
        if (!empty($product_type)) {
          return sprintf(
            '<label class="stckup_product_type" >%s</label>' .
            '<input class="" data-name="stckup_product_type" data-id="%s" type="hidden" />' .
            '<div class="clearfix"></div>',
            $product_type,
            $product_id
          );
        }
        return sprintf(
          '<label class="stckup_product_type" >%s</label>' .
          '<input class="" data-name="stckup_product_type" data-id="%s" type="hidden" />' .
          '<div class="clearfix"></div>',
          '--',
          $product_id
        );
        
      case 'weight':
      case 'length':
      case 'width':
      case 'height':
        return $this->render_product_dimension($product, $product_id, $column_name);
        
      default:
        return isset($item[$column_name]) ? $item[$column_name] : '';
    }
  }
  
  function column_cb($item) {
    $pid = $item['id']; 
    return '<input type="checkbox" name="bulk-edit[]" value="' . esc_attr($pid) . '" />';
  }

  function get_columns()
  {
    $columns = array(
      'cb' => '<input type="checkbox" id="select_all_cb" style="display: none;" />', 
      'id' => esc_html__('Product ID', 'stckup'),
      'thumbnail' =>  esc_html__('Thumbnail', 'stckup'),
      'name' => esc_html__('Name', 'stckup'),
      'sku' => esc_html__('SKU', 'stckup'),
      'type' =>  esc_html__('Type', 'stckup'),
      'regular_price' => esc_html__('Regular Price', 'stckup'),
      'sale_price' => esc_html__('Sale Price', 'stckup'),      
      'stock_status' => esc_html__('Stock Status', 'stckup'),
      'manage_stock' =>  esc_html__('Manage Stock', 'stckup'),
      'stock_at_location' => esc_html__('Stock At Locations', 'stckup'),
      'stock_quantity' => esc_html__('Stock Quantity', 'stckup'),
      'short_description' =>  esc_html__('Short Description', 'stckup'),
      'description' =>  esc_html__('Description', 'stckup'),     
      'status' =>  esc_html__('Status', 'stckup'),      
      'backorders' =>  esc_html__('Backorders', 'stckup'),
      'weight' =>  esc_html__('Weight', 'stckup'),
      'length' =>  esc_html__('Length', 'stckup'),
      'width' =>  esc_html__('Width', 'stckup'),
      'height' =>  esc_html__('Height', 'stckup'),  
    );
    return $columns;
  }

  /**
   * Get hidden columns based on user preferences
   * Default behavior: All columns are visible unless explicitly set to 'Hide'
   */
  function get_hidden_columns() {
    // Get column preferences from options table
    $saved_columns = get_option('ProductCentralControlOptions', array());
    
    // If no saved preferences, show all columns by default
    if (!is_array($saved_columns) || empty($saved_columns)) {
      return array(); // Show all columns by default
    }
    
    $hidden = array();
    // Only hide columns that are explicitly set to 'Hide'
    foreach ($saved_columns as $column => $visibility) {
      if ($visibility === 'Hide') {
        $hidden[] = $column;
      }
    }
    
    return $hidden;
  }

  function get_sortable_columns()
  {
    $sortable_columns = array(
      'id' => array('id', true),
      'thumbnail' =>  esc_html__('thumbnail', 'stckup'),
      'name' => array('name', true),
      'sku' => array('sku', true),
      'type' =>  esc_html__('type', 'stckup'),
      'regular_price' => array('regular_price', true),
      'sale_price' => array('sale_price', true),      
      'stock_status' => array('stock_status', true),
      'manage_stock' =>  esc_html__('manage_stock', 'stckup'),
      'stock_at_location' => esc_html__('stock_at_location', 'stckup'),
      'stock_quantity' => array('stock_quantity', true),     
      'short_description' =>  esc_html__('short_description', 'stckup'),
      'description' =>  esc_html__('description', 'stckup'),     
      'status' =>  esc_html__('status', 'stckup'),      
      'backorders' =>  esc_html__('backorders', 'stckup'),
      'weight' =>  esc_html__('weight', 'stckup'),
      'length' =>  esc_html__('length', 'stckup'),
      'width' =>  esc_html__('width', 'stckup'),
      'height' =>  esc_html__('height', 'stckup'),     
    );
    return $sortable_columns;
  }

  /**
   * Build args for wc_get_products based on request parameters
   * 
   * @return array Args for wc_get_products
   */
  private function build_product_args($search = '', $per_page = 20, $paged = 1) {
    // Apply sorting
    $orderby = isset($_REQUEST['orderby']) ? sanitize_sql_orderby($_REQUEST['orderby']) : 'ID';
    $order = isset($_REQUEST['order']) && in_array($_REQUEST['order'], array('asc', 'desc')) ? $_REQUEST['order'] : 'asc';
    $offset = ($paged - 1) * $per_page;

    $args = [
        'limit' => $per_page,
        'offset' => $offset,
        'status' => 'publish',
        'orderby' => $orderby,
        'order' => $order,
        'return' => 'objects',
    ];

    // Add search
    if (!empty($search)) {
        $args['s'] = $search;
    }

    // Filter by category
    if (!empty($_GET['cat-filter'])) {
        $cat_filter = sanitize_text_field($_GET['cat-filter']);
        if (strpos($cat_filter, '&cat-filter=') === 0) {
            $cat_filter = substr($cat_filter, strlen('&cat-filter='));
        }
        $cat_filter_id = absint($cat_filter);
        if ($cat_filter_id > 0 && term_exists($cat_filter_id, 'product_cat')) {
            $term = get_term($cat_filter_id, 'product_cat');
            if ($term && !is_wp_error($term)) {
                $args['category'] = array($term->slug);
            }
        }
    }

    // Filter by product type
    if (!empty($_GET['type-filter'])) {
        $type_filter = sanitize_text_field($_GET['type-filter']);
        // Extract the type from "&type-filter=XX" format if needed
        if (strpos($type_filter, '&type-filter=') === 0) {
            $type_filter = substr($type_filter, strlen('&type-filter='));
        }
        $args['type'] = $type_filter;
    }

    // Filter by stock status
    if (!empty($_GET['stock-status-filter'])) {
        $stock_status_filter = sanitize_text_field($_GET['stock-status-filter']);
        // Extract the stock status from "&stock-status-filter=XX" format if needed
        if (strpos($stock_status_filter, '&stock-status-filter=') === 0) {
            $stock_status_filter = substr($stock_status_filter, strlen('&stock-status-filter='));
        }
        $stock_value = $stock_status_filter == 'in_stock' ? 'instock' : 'outofstock';
        $args['stock_status'] = $stock_value;
    }

    return $args;
  }

  /**
   * Count total products including variations (for pagination)
   */
  /**
   * Count total regular products (not variations) with current filters
   * This is needed for proper variation offset calculation
   */
  private function count_regular_products_total($search = '') {
    // Get count of regular products (not variations) with current filters
    $args = [
        'limit' => -1,
        'status' => 'publish',
        'type' => ['simple', 'grouped', 'external'],
        'return' => 'ids',
    ];
    
    // Apply same filters as main query
    if (!empty($search)) {
        $args['s'] = $search;
    }
    
    if (!empty($_GET['cat-filter'])) {
        $cat_filter = sanitize_text_field($_GET['cat-filter']);
        if (strpos($cat_filter, '&cat-filter=') === 0) {
            $cat_filter = substr($cat_filter, strlen('&cat-filter='));
        }
        $cat_filter_id = absint($cat_filter);
        if ($cat_filter_id > 0 && term_exists($cat_filter_id, 'product_cat')) {
            $term = get_term($cat_filter_id, 'product_cat');
            if ($term && !is_wp_error($term)) {
                $args['category'] = array($term->slug);
            }
        }
    }
    
    if (!empty($_GET['stock-status-filter'])) {
        $stock_status_filter = sanitize_text_field($_GET['stock-status-filter']);
        if (strpos($stock_status_filter, '&stock-status-filter=') === 0) {
            $stock_status_filter = substr($stock_status_filter, strlen('&stock-status-filter='));
        }
        $stock_value = $stock_status_filter == 'in_stock' ? 'instock' : 'outofstock';
        $args['stock_status'] = $stock_value;
    }
    
    $product_ids = wc_get_products($args);
    return count($product_ids);
  }

  private function count_total_products($search = '') {
    global $wpdb;
    
    // Start with regular products
    $args = [
        'limit' => -1,
        'status' => 'publish',
        'type' => ['simple', 'grouped', 'external'],
        'return' => 'ids',
    ];
    
    // Apply filters
    if (!empty($search)) {
        $args['s'] = $search;
    }
    
    if (!empty($_GET['cat-filter'])) {
        $cat_filter = sanitize_text_field($_GET['cat-filter']);
        if (strpos($cat_filter, '&cat-filter=') === 0) {
            $cat_filter = substr($cat_filter, strlen('&cat-filter='));
        }
        $cat_filter_id = absint($cat_filter);
        if ($cat_filter_id > 0 && term_exists($cat_filter_id, 'product_cat')) {
            $term = get_term($cat_filter_id, 'product_cat');
            if ($term && !is_wp_error($term)) {
                $args['category'] = array($term->slug);
            }
        }
    }
    
    if (!empty($_GET['stock-status-filter'])) {
        $stock_status_filter = sanitize_text_field($_GET['stock-status-filter']);
        // Extract the stock status from "&stock-status-filter=XX" format if needed
        if (strpos($stock_status_filter, '&stock-status-filter=') === 0) {
            $stock_status_filter = substr($stock_status_filter, strlen('&stock-status-filter='));
        }
        $stock_value = $stock_status_filter == 'in_stock' ? 'instock' : 'outofstock';
        $args['stock_status'] = $stock_value;
    }
    
    // For product type filter
    if (!empty($_GET['type-filter'])) {
        $type_filter = sanitize_text_field($_GET['type-filter']);
        if ($type_filter === 'simple') {
            // Already covered in default types
        } else if ($type_filter === 'variable') {
            // Count only variations
            $args['type'] = 'variable';
            $variable_ids = wc_get_products($args);
            
            // Get variations from these variable products
            $variation_count = 0;
            if (!empty($variable_ids)) {
                $variation_query = "
                    SELECT COUNT(ID)
                    FROM {$wpdb->posts}
                    WHERE post_type = 'product_variation'
                    AND post_status = 'publish'
                    AND post_parent IN (" . implode(',', $variable_ids) . ")";
                
                if (!empty($search)) {
                    $like_search = '%' . $wpdb->esc_like($search) . '%';
                    $variation_query .= $wpdb->prepare(
                        " AND (post_title LIKE %s OR ID IN (
                            SELECT post_id FROM {$wpdb->postmeta}
                            WHERE meta_key = '%s' AND meta_value LIKE %s
                        ))",
                        $like_search,
                        '_sku',
                        $like_search
                    );
                }
                
                $variation_count = (int) $wpdb->get_var($variation_query);
            }
            
            return $variation_count;
        }
    }
    
    $product_ids = wc_get_products($args);
    $regular_count = count($product_ids);
    
    // Count variations from variable products
    $variable_args = [
        'limit' => -1,
        'status' => 'publish',
        'type' => 'variable',
        'return' => 'ids',
    ];
    
    // Apply filters
    if (!empty($search)) {
        $variable_args['search'] = $search;
    }
    
    if (!empty($_GET['cat-filter'])) {
        $variable_args['category'] = [$cat_filter];
    }
    
    if (!empty($_GET['stock-status-filter'])) {
        $variable_args['stock_status'] = $stock_value;
    }
    
    $variable_ids = wc_get_products($variable_args);
    
    $variation_count = 0;
    if (!empty($variable_ids)) {
        $variation_query = "
            SELECT COUNT(ID)
            FROM {$wpdb->posts}
            WHERE post_type = 'product_variation'
            AND post_status = 'publish'
            AND post_parent IN (" . implode(',', $variable_ids) . ")";
        
        if (!empty($search)) {
            $like_search = '%' . $wpdb->esc_like($search) . '%';
            $variation_query .= $wpdb->prepare(
                " AND (post_title LIKE %s OR ID IN (
                    SELECT post_id FROM {$wpdb->postmeta}
                    WHERE meta_key = '%s' AND meta_value LIKE %s
                ))",
                $like_search,
                '_sku',
                $like_search
            );
        }
        
        $variation_count = (int) $wpdb->get_var($variation_query);
    }
    
    return $regular_count + $variation_count;
  }

  function prepare_items($search = '', $paged = 1) {
    global $wpdb;

    // Get per page value from screen options
    $user_id = get_current_user_id();
    $per_page = get_user_meta($user_id, 'product_central_pagination', true);
    if (empty($per_page) || $per_page < 1) {
        $per_page = 20; // Default value
    }

    // Use the passed paged parameter, but fallback to GET parameter if not provided properly
    if ($paged <= 0) {
        $paged = isset($_GET['c_paged']) ? absint($_GET['c_paged']) : 1;
    }

    $columns = $this->get_columns();
    $hidden = $this->get_hidden_columns();
    $sortable = $this->get_sortable_columns();
    $this->_column_headers = array($columns, $hidden, $sortable);

    if (!empty($_GET['search'])){
      $search = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '';
    }
    else {
      $search = '';
    }

    // Get total items for pagination
    $total_items = $this->count_total_products($search);

    // Get products with pagination
    $data = [];
    $count = 0;
    
    // Step 1: Get regular products (not variations)
    $regular_args = $this->build_product_args($search, $per_page, $paged);
    
    // Handle variable products specially
    if (!empty($_GET['type-filter']) && $_GET['type-filter'] === 'variable') {
        // If filtering by variable type, we want only variations, not the parent products
        $regular_args['type'] = 'variable';
        $regular_products = wc_get_products($regular_args);
        
        // Skip adding variable products themselves
    } else {
        // Default case: Get simple, grouped, external products
        $regular_args['type'] = ['simple', 'grouped', 'external'];
        $regular_products = wc_get_products($regular_args);
        
        // Convert to the format expected by the table
        foreach ($regular_products as $product) {
            if ($count >= $per_page) break;
            
            $product_data = $this->format_product_for_table($product);
            $data[] = $product_data;
            $count++;
        }
    }
    
    // Step 2: Get variations if we still need more items
    if ($count < $per_page) {
        $remaining = $per_page - $count;
        $offset = ($paged - 1) * $per_page;
        
        // Calculate total regular products that exist with current filters
        $total_regular_count = $this->count_regular_products_total($search);
        
        // Calculate variation offset: if we're past all regular products, 
        // then we need to skip (current_offset - total_regular_products) variations
        $variations_offset = max(0, $offset - $total_regular_count);
        
        // Get variable products to extract their variations
        $variable_args = [
            'limit' => -1,
            'status' => 'publish',
            'type' => 'variable',
            'return' => 'ids'
        ];
        
        // Apply filters to variable products
        if (!empty($search)) {
            $variable_args['search'] = $search;
        }
        
        if (!empty($_GET['cat-filter'])) {
            $cat_filter = sanitize_text_field($_GET['cat-filter']);
            if (strpos($cat_filter, '&cat-filter=') === 0) {
                $cat_filter = substr($cat_filter, strlen('&cat-filter='));
            }
            $cat_filter_id = absint($cat_filter);
            if ($cat_filter_id > 0 && term_exists($cat_filter_id, 'product_cat')) {
                $term = get_term($cat_filter_id, 'product_cat');
                if ($term && !is_wp_error($term)) {
                    $variable_args['category'] = [$term->slug];
                }
            }
        }
        
        if (!empty($_GET['stock-status-filter'])) {
            $stock_status_filter = sanitize_text_field($_GET['stock-status-filter']);
            // Extract the stock status from "&stock-status-filter=XX" format if needed
            if (strpos($stock_status_filter, '&stock-status-filter=') === 0) {
                $stock_status_filter = substr($stock_status_filter, strlen('&stock-status-filter='));
            }
            $stock_value = $stock_status_filter == 'in_stock' ? 'instock' : 'outofstock';
            $variable_args['stock_status'] = $stock_value;
        }
        
        $variable_ids = wc_get_products($variable_args);
        
        if (!empty($variable_ids)) {
            // Apply ordering to match the requested sort
            $orderby = isset($_REQUEST['orderby']) ? sanitize_sql_orderby($_REQUEST['orderby']) : 'ID';
            $order = isset($_REQUEST['order']) && in_array($_REQUEST['order'], array('asc', 'desc')) ? $_REQUEST['order'] : 'asc';
            
            // Query variations directly
            $variations_query = "
                SELECT ID
                FROM {$wpdb->posts} 
                WHERE post_type = 'product_variation'
                AND post_status = 'publish'
                AND post_parent IN (" . implode(',', $variable_ids) . ")";
            
            // Add search condition if needed
            if (!empty($search)) {
                $like_search = '%' . $wpdb->esc_like($search) . '%';
                $variations_query .= $wpdb->prepare(
                    " AND (post_title LIKE %s OR ID IN (
                        SELECT post_id FROM {$wpdb->postmeta} 
                        WHERE meta_key = '%s' AND meta_value LIKE %s
                    ))",
                    $like_search,
                    '_sku',
                    $like_search
                );
            }
            
            // Add stock status filter if needed
            if (!empty($_GET['stock-status-filter'])) {
                $stock_status_filter = sanitize_text_field($_GET['stock-status-filter']);
                // Extract the stock status from "&stock-status-filter=XX" format if needed
                if (strpos($stock_status_filter, '&stock-status-filter=') === 0) {
                    $stock_status_filter = substr($stock_status_filter, strlen('&stock-status-filter='));
                }
                $stock_value = $stock_status_filter == 'in_stock' ? 'instock' : 'outofstock';
                $variations_query .= $wpdb->prepare(
                    " AND ID IN (
                        SELECT post_id FROM {$wpdb->postmeta}
                        WHERE meta_key = '%s' AND meta_value = %s
                    )",
                    '_stock_status',
                    $stock_value
                );
            }
            
            // Add sorting and pagination
            $variations_query .= " ORDER BY ID {$order} LIMIT {$remaining} OFFSET {$variations_offset}";
            
            $variation_ids = $wpdb->get_col($variations_query);
            
            // Add variations to data
            foreach ($variation_ids as $variation_id) {
                $variation_product = wc_get_product($variation_id);
                if (!$variation_product) continue;
                
                $product_data = $this->format_product_for_table($variation_product);
                $data[] = $product_data;
                
                $count++;
                if ($count >= $per_page) break;
            }
        }
    }

    $this->items = $data;
    
    // Filter columns based on options
    $options_table = $wpdb->prefix . 'options';
    $ProductCentralControlOptions = $wpdb->get_results($wpdb->prepare(
        "SELECT option_value FROM {$options_table} WHERE option_name = %s LIMIT 1",
        'ProductCentralControlOptions'
    ));
    
    if (!empty($ProductCentralControlOptions)) {
      $PCFOR = maybe_unserialize($ProductCentralControlOptions[0]->option_value);
      
      $filtered_columns = array();
      foreach ($columns as $key => $value) {
        if (isset($PCFOR[0]) && isset($PCFOR[0][$key])) {
          $col_val_shw = $PCFOR[0][$key];
        } elseif (isset($PCFOR[$key])) {
          $col_val_shw = $PCFOR[$key];
        } else {
          $col_val_shw = 'Show'; // Default to show if not specified
        }
        
        if ($col_val_shw == 'Show') {
          $filtered_columns[$key] = $value;
        }
      }
      
      $columns = $filtered_columns;
      $this->_column_headers[0] = $columns;
    }

    // Set pagination
    $this->set_pagination_args(array(
      'total_items' => $total_items,
      'per_page'    => $per_page,
      'total_pages' => ceil($total_items / $per_page)
    ));
  }

  /**
   * Format a product object for the table display
   */
  private function format_product_for_table($product) {
    if (!$product) return [];

    $product_data = [
        'id' => $product->get_id(),
        'name' => $product->get_name(),
        'thumbnail' => $product->get_image_id(),
        'sku' => $product->get_sku(),
        'regular_price' => $product->get_regular_price(),
        'sale_price' => $product->get_sale_price(),
        'stock_quantity' => $product->get_stock_quantity(),
        'stock_status' => $product->get_stock_status(),
        'manage_stock' => $product->get_manage_stock() ? 'yes' : 'no',
        'backorders' => $product->get_backorders(),
        'weight' => $product->get_weight(),
        'length' => $product->get_length(),
        'width' => $product->get_width(),
        'height' => $product->get_height(),
        'short_description' => $product->get_short_description(),
        'description' => $product->get_description(),
        'status' => $product->get_status()
    ];

    return $product_data;
  }

  /**
   * Build SQL conditions based on request parameters
   * 
   * @return array Array of SQL conditions
   */
  private function build_query_conditions() {
    $tax_cond = '';
    $search_query = '';
    $stock_cond = '';

    // Check for category filter
    if (!empty($_GET['cat-filter'])) {
      $cat_filter = sanitize_text_field($_GET['cat-filter']);
      if (strpos($cat_filter, '&cat-filter=') === 0) {
          $cat_filter = substr($cat_filter, strlen('&cat-filter='));
      }
      $cat_filter_id = absint($cat_filter);
      if ($cat_filter_id > 0 && term_exists($cat_filter_id, 'product_cat')) {
          $tax_cond .= " AND tt.taxonomy = 'product_cat' AND t.term_id = '$cat_filter_id'";
      }
    }

    // Check for product type filter
    if (!empty($_GET['type-filter'])){
      $type_filter = sanitize_text_field($_GET['type-filter']);
      // Extract the type from "&type-filter=XX" format if needed
      if (strpos($type_filter, '&type-filter=') === 0) {
          $type_filter = substr($type_filter, strlen('&type-filter='));
      }
      $type_value = ($type_filter == 'simple') ? 'product' : 'product_variation' ;
      $tax_cond .= " AND (posts.post_type IN ('$type_value'))";
    }

    // Check for stock status filter
    if (!empty($_GET['stock-status-filter'])) {
      $stock_status_filter = sanitize_text_field($_GET['stock-status-filter']);
      // Extract the stock status from "&stock-status-filter=XX" format if needed
      if (strpos($stock_status_filter, '&stock-status-filter=') === 0) {
          $stock_status_filter = substr($stock_status_filter, strlen('&stock-status-filter='));
      }
      $stock_value = $stock_status_filter == 'in_stock' ? 'instock' : 'outofstock';
      $stock_cond .= " AND pm_stock_status.meta_key = '_stock_status' AND pm_stock_status.meta_value = '$stock_value'";
    }

    // Search filter
    if (!empty($_GET['s'])){
      $search = isset($_GET['s']) ? sanitize_text_field($_GET['s']) : '';
      if (!empty($search)) {
        $search_query .= " AND posts.post_title LIKE '%$search%'";
      }
    }
    
    return array(
      'tax_cond' => $tax_cond,
      'search_query' => $search_query,
      'stock_cond' => $stock_cond
    );
  }

  /**
   * Build SQL query for product central
   */
  private function build_sql_query($per_page, $offset) {
    global $wpdb;

    // Construct the SQL query - modified to include all product types
    $sql_query = $wpdb->prepare("
        SELECT DISTINCT
            posts.ID AS id,
            posts.post_title AS name,
            posts.post_content AS description,
            posts.post_excerpt AS short_description,
            posts.post_status AS status,
            pm_regular_price.meta_value AS regular_price,
            pm_sale_price.meta_value AS sale_price,
            pm_stock.meta_value AS stock_quantity,
            pm_thumbnail.meta_value AS thumbnail,
            pm_stock_status.meta_value AS stock_status,
            pm_sku.meta_value AS sku,
            pm_type.meta_value AS type,
            pm_manage_stock.meta_value AS manage_stock,
            pm_backorders.meta_value AS backorders,
            pm_weight.meta_value AS weight,
            pm_length.meta_value AS length,
            pm_width.meta_value AS width,
            pm_height.meta_value AS height
        FROM
            {$wpdb->prefix}posts AS posts
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_regular_price ON posts.ID = pm_regular_price.post_id AND pm_regular_price.meta_key = '_regular_price'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_sale_price ON posts.ID = pm_sale_price.post_id AND pm_sale_price.meta_key = '_sale_price'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_stock ON posts.ID = pm_stock.post_id AND pm_stock.meta_key = '_stock'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_thumbnail ON posts.ID = pm_thumbnail.post_id AND pm_thumbnail.meta_key = '_thumbnail_id'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_stock_status ON posts.ID = pm_stock_status.post_id AND pm_stock_status.meta_key = '_stock_status'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_sku ON posts.ID = pm_sku.post_id AND pm_sku.meta_key = '_sku'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_type ON posts.ID = pm_type.post_id AND pm_type.meta_key = '_product_type'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_manage_stock ON posts.ID = pm_manage_stock.post_id AND pm_manage_stock.meta_key = '_manage_stock'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_backorders ON posts.ID = pm_backorders.post_id AND pm_backorders.meta_key = '_backorders'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_weight ON posts.ID = pm_weight.post_id AND pm_weight.meta_key = '_weight'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_length ON posts.ID = pm_length.post_id AND pm_length.meta_key = '_length'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_width ON posts.ID = pm_width.post_id AND pm_width.meta_key = '_width'
        LEFT JOIN
            {$wpdb->prefix}postmeta AS pm_height ON posts.ID = pm_height.post_id AND pm_height.meta_key = '_height'
        LEFT JOIN
            {$wpdb->prefix}posts AS parent_posts ON posts.post_parent = parent_posts.ID
                AND parent_posts.post_status = 'publish'
                AND parent_posts.post_type = 'product'
        LEFT JOIN
            {$wpdb->prefix}term_relationships AS tr ON posts.ID = tr.object_id
        LEFT JOIN
            {$wpdb->prefix}term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
        LEFT JOIN
            {$wpdb->prefix}terms AS t ON tt.term_id = t.term_id
        WHERE
            posts.post_type IN ('product', 'product_variation')
            AND posts.post_status = 'publish'
            AND (
                posts.post_parent = 0 -- Parent products
                OR parent_posts.ID IS NOT NULL -- Valid child products with a published parent
            )
            {$tax_cond} -- Taxonomy conditions
            {$search_query} -- Search condition
            {$stock_cond} -- Stock status condition
        ORDER BY
            ID ASC
            
        LIMIT %d OFFSET %d",
        $per_page,
        $offset
    );

    return $sql_query;
  }

  /**
   * Execute the SQL query and prepare items
   */
  private function execute_sql_query($sql_query) {
    global $wpdb;

    // Execute the query
    $this->items = $wpdb->get_results($sql_query, ARRAY_A);    

    // $total_items = count($this->items ?? []);
  }

  function extra_tablenav($which)
  {
    if ($which !== "top") {
      return;
    }
    
    global $wpdb;
    ?>
    <div class="alignleft actions bulkactions">
      <?php
      $args = array(
        'taxonomy'   => "product_cat",
        'orderby'    => 'title',
        'order'      => 'ASC'
      );
      $product_categories = get_terms($args);

      if (!empty($product_categories)) {
        ?>
        <select name="cat-filter" id="cat-filter" class="ewc-filter-cat">
          <option value=""><?php esc_html_e('Filter by Category', 'stckup') ?></option>
          <?php
          $move_on_url = '&cat-filter=';
          foreach ($product_categories as $cat) {
            $cat_filter_value = !empty($_GET['cat-filter']) ? sanitize_text_field($_GET['cat-filter']) : '';
            // Extract the category ID if the value contains the prefix
            if (strpos($cat_filter_value, '&cat-filter=') === 0) {
                $cat_filter_value = substr($cat_filter_value, strlen('&cat-filter='));
            }
            $selected = (!empty($cat_filter_value) && $cat_filter_value == $cat->term_id) ? ' selected="selected"' : '';
            ?>
            <option value="<?php esc_attr_e($move_on_url . $cat->term_id, 'stckup'); ?>" <?php esc_attr_e($selected, 'stckup'); ?>><?php esc_attr_e($cat->name, 'stckup'); ?></option>
            <?php
          }
          ?>
        </select>
        <?php
      }
      ?>
    </div>
    
    <div class="alignleft actions bulkactions">
      <?php
      $type_filter_url = '&type-filter=';
      $product_types = wc_get_product_types();

      if (!empty($product_types)) {
        ?>
        <select name="type-filter" class="ewc-filter-type" id="ewc-filter-type">
          <option value=""><?php esc_html_e('Filter by Product Type', 'stckup') ?></option>
          <?php
          foreach ($product_types as $key => $product_type) {
            if ($key !== "simple" && $key !== "variable") {
              continue;
            }
            
            $type_filter_value = !empty($_GET['type-filter']) ? sanitize_text_field($_GET['type-filter']) : '';
            // Extract the type if the value contains the prefix
            if (strpos($type_filter_value, '&type-filter=') === 0) {
                $type_filter_value = substr($type_filter_value, strlen('&type-filter='));
            }
            $selected = (!empty($type_filter_value) && $type_filter_value == $key) ? ' selected="selected"' : '';
            ?>
            <option value="<?php esc_attr_e($type_filter_url . $key, 'stckup'); ?>" <?php esc_attr_e($selected, 'stckup'); ?>><?php esc_attr_e($product_type, 'stckup'); ?></option>
            <?php
          }
          ?>
        </select>
        <?php
      }
      ?>
    </div>
    
    <div class="alignleft actions bulkactions">
      <?php
      $searchval = isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '';
      ?>
      <input type="text" name="search" class="wcmlim_lst_search" id="wcmlim_lst_search" placeholder="Search" value="<?php echo $searchval; ?>">
    </div>
    
    <div class="alignleft actions bulkactions">
      <?php
      $stock_status_filter_url = '&stock-status-filter=';
      ?>
      <select name="stock-status-filter" id="ewc-filter-stock-status" class="ewc-filter-stock-status">
        <option value=""><?php esc_html_e('Filter by Stock Status', 'stckup') ?></option>
        <?php 
        $stock_filter_value = !empty($_GET['stock-status-filter']) ? sanitize_text_field($_GET['stock-status-filter']) : '';
        // Extract the stock status if the value contains the prefix
        if (strpos($stock_filter_value, '&stock-status-filter=') === 0) {
            $stock_filter_value = substr($stock_filter_value, strlen('&stock-status-filter='));
        }
        ?>
        <option value="<?php esc_attr_e($stock_status_filter_url . 'in_stock'); ?>" <?php if ($stock_filter_value == "in_stock") { echo "selected='selected'"; } ?>>In Stock</option>
        <option value="<?php esc_attr_e($stock_status_filter_url . 'out_of_stock'); ?>" <?php if ($stock_filter_value == "out_of_stock") { echo "selected='selected'"; } ?>>Out Of Stock</option>
      </select>
    </div>
    
    <div class="alignleft actions bulkactions">
      <a href="?page=wcmlim-product-central"><input type="button" class="button" id="wcmlim-rest" value="Reset"></a>
    </div>
    
    <?php
    echo '<input type="button" class="button action" id="bulk-edit-btn" value="' . esc_attr__('Bulk Edit', 'stckup') . '">';
    ?>
    
    <div id="bulk-edit-modal" class="bulk-edit-modal" style="display:none;">
      <div class="bulk-edit-modal-content">
        <span class="bulk-edit-modal-close">&times;</span>
        <h2><?php esc_html_e('Bulk Edit Products', 'stckup'); ?></h2>

        <!-- 🔴 Important Note -->
        <p style="color: red; font-weight: bold;">
          <?php esc_html_e('Please note this:', 'stckup'); ?>
        </p>
        <ul style="color: red; font-weight: bold; padding-left: 20px;">
          <li><?php esc_html_e('1 . Entering a quantity (including 0) will link the location to the product.', 'stckup'); ?></li>
          <li><?php esc_html_e('2 . Leaving the field blank will keep the stock as it is for that location.', 'stckup'); ?></li>
          
        </ul>

        <form id="bulk-edit-form" method="post">
          <?php
          $locations = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
          if (!empty($locations)) {
            foreach ($locations as $key => $value) {
              ?>
              <div class="bulk-setting">
                <label for="stock_location"><?php esc_html_e('Stock at ', 'stckup'); ?><?php echo $value->name; ?></label>
                <input type="text" name="stock_location" class="stock_location" data-locid="<?php echo $value->term_id; ?>" value="">
              </div>
              <?php
            }
          }
          ?>
          <input type="button" id="apply-changes" class="button button-primary" value="<?php esc_attr_e('Apply Changes', 'stckup'); ?>">
          <?php wp_nonce_field('bulk-edit-action', 'bulk-edit-nonce'); ?>
        </form>
      </div>
    </div>
    <?php
  }
}

add_action('wp_ajax_bulk_edit_products', 'handle_bulk_edit_ajax');

function handle_bulk_edit_ajax() {
  if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error([
            'message' => 'Unauthorized access',
        ], 403);
        return;
    }
 
    check_ajax_referer('wcmlim_locations_nonce', 'security');
    
    if(isset($_POST['security']) && !wp_verify_nonce($_POST['security'], 'wcmlim_locations_nonce')) {
        wp_send_json(array(
            'success' => false,
            'message' => 'Invalid nonce'
        ));
        return;
    }
  $product_ids = $_POST['products'];
  $bulk_update_loc = $_POST['bulk_update_loc'];
  
  if (!is_array($bulk_update_loc)) {
    $bulk_update_loc = json_decode(stripslashes($bulk_update_loc), true);
  }

  if (is_array($bulk_update_loc)) {
      // Iterate over each product ID
      foreach ($product_ids as $product_id) {

        // Skip if product ID is 'on'
        if ($product_id === 'on') {
          continue;
        }

          // Get product type (simple or variation)
          $product = wc_get_product($product_id);
          if(empty($product)){
            return;
          }
          $product_type = $product->get_type();
          $parent_id = false;          
          if ($product_type == 'variation') {
            $parent_id = wp_get_post_parent_id($product_id);
          } 

          // Get the current locations associated with the product
          $current_terms = wp_get_object_terms(($parent_id != false)? $parent_id : $product_id, 'locations', array('fields' => 'ids'));
          $current_term_ids = is_array($current_terms) ? $current_terms : [];
                                                  
          // Iterate over each location update data
          foreach ($bulk_update_loc as $update) {
                                    

              $stock_location = isset($update['value']) ? trim($update['value']) : '';
              $locid = isset($update['locid']) ? intval($update['locid']) : 0;

              // Ensure location ID is valid and the product ID is numeric
              if ($locid > 0 && is_numeric($product_id)) {

                  // Case 1: Stock is 0 or greater → Link the location (if not already linked)
                  if ($stock_location !== '' && is_numeric($stock_location) && intval($stock_location) >= 0) {                                                            
                      if (!in_array($locid, $current_term_ids)) {                        
                          $current_term_ids[] = $locid; // Add the new location
                          wp_set_object_terms(($parent_id != false) ? $parent_id : $product_id, $current_term_ids, 'locations', false); // Append, don't replace
                      }

                      // Update stock at this location
                      update_post_meta($product_id, "wcmlim_stock_at_{$locid}", intval($stock_location));
                  } 
     
              }
          }

          // Recalculate total stock quantity across all locations
          $updated_terms = wp_get_object_terms($product_id, 'locations', array('fields' => 'ids'));
          $arr_stock = array();
          foreach ($updated_terms as $term_id) {
              $loc_stock_val = intval(get_post_meta($product_id, "wcmlim_stock_at_{$term_id}", true));
              array_push($arr_stock, $loc_stock_val);
          }
          $total_stock_qty = array_sum($arr_stock);
          update_post_meta($product_id, "_stock", $total_stock_qty);
      }
  }

  wp_send_json_success('Stock at location updated, locations linked/unlinked successfully.');
}