<?php

trait Wcmlim_Backend_Shipping_Functions{

public function wcmlim_backend_mode_nearby_location_selection_shipping_address($posted_data)
{
  global $destination_prepare, $locations_data_lat_lng, $latlngarr, $shipping_latitude, $shipping_longitude, $distance, $woocommerce, $combine_item_arr;

  // Consolidate items in cart to avoid duplicate processing
  $combine_item_arr = array();
  $items = $woocommerce->cart->get_cart();
  foreach($items as $item => $values) { 
    $_product_cart_id = $values['data']->get_id(); 
    $_product_cart_quantity = $values['quantity'];
    if(isset($combine_item_arr[$_product_cart_id])) {
      $combine_item_arr[$_product_cart_id] += intval($_product_cart_quantity);
    } else {
      $combine_item_arr[$_product_cart_id] = intval($_product_cart_quantity);
    }
  } 
  
  // Clear cart and re-add consolidated items
  $cart = WC()->cart->get_cart();
  WC()->cart->empty_cart();
  
  foreach($combine_item_arr as $fetch_product_id => $fetch_product_value) {
    WC()->cart->add_to_cart($fetch_product_id, $fetch_product_value, '0', array());
  }
  
  // Get shipping address components
  $addressone = isset($_POST['s_address']) ? $_POST['s_address'] : '';
  $addresstwo = isset($_POST['s_address_2']) ? $_POST['s_address_2'] : '';
  $city = isset($_POST['s_city']) ? $_POST['s_city'] : '';
  $state = isset($_POST['s_state']) ? $_POST['s_state'] : '';
  $country = isset($_POST['s_country']) ? $_POST['s_country'] : '';
  $postcode = isset($_POST['s_postcode']) ? $_POST['s_postcode'] : '';

  $prepare_destination_address_string = $addressone.'+'.$addresstwo.'+'.$city.'+'.$state.'+'.$country.'+'.$postcode;
  $coordinates_calculator = get_option('wcmlim_distance_calculator_by_coordinates');
  $dis_unit = get_option("wcmlim_show_location_distance");
  $google_api_key = get_option("wcmlim_google_api_key");
  
  // Get shipping coordinates
  if(!empty($prepare_destination_address_string) && !empty($google_api_key)) {
    $shipping_coordinates = $this->get_coordinates_from_address($prepare_destination_address_string, $google_api_key);
    $shipping_latitude = $shipping_coordinates['latitude'];
    $shipping_longitude = $shipping_coordinates['longitude'];
    $latlngarr = $shipping_coordinates;
  } else {
    $shipping_latitude = 0;
    $shipping_longitude = 0;
    $latlngarr = array('latitude' => 0, 'longitude' => 0);
  }
  
  // Process items in cart after deduplication
  $tmp_cart_item_exist = array();
  foreach (WC()->cart->get_cart() as $item_id => $item) {
    $product_id = $item['variation_id'] ?: $item['product_id'];
    $item_quantity = $item['quantity'];
    
    // Check if this product was already processed
    if(!empty($tmp_cart_item_exist)) {
      $find_in_array = $this->find_product_in_array($product_id, $tmp_cart_item_exist);
      if($find_in_array != 0) {
        $found_item_quantity = $find_in_array['item_quantity'];
        $found_item_id = $find_in_array['item_id'];
        $found_new_qty = intval($found_item_quantity) + intval($item_quantity);
        
        // Remove duplicate and update quantity
        WC()->cart->remove_cart_item($found_item_id);
        WC()->cart->cart_contents[$item_id]['quantity'] = $found_new_qty;
        WC()->cart->set_session();
      }
    }
    
    // Track processed items
    $tmp_cart_item_exist[] = array(
      "product_id" => $product_id,
      "item_quantity" => $item_quantity,
      "item_id" => $item_id
    );
    
    // Get product name for notifications
    $cart_item_product_name = $item['data']->get_name();
    $stockmanagement = get_post_meta($product_id, '_manage_stock', true);
    
    // Get locations with stock for this product
    $match_dest = $this->get_locations_with_stock($product_id);
    $dest = array_column($match_dest, 'address');
    
    // Handle product availability
    if(empty($dest) && $stockmanagement == "yes") {
      wc_clear_notices();
      wc_add_notice(sprintf(__('The Item added to cart "%s" is not available at your shipping location, you need to remove it from your cart!', 'wcmlim'), $cart_item_product_name), 'error');
    } else {
      // Handle distance calculation and stock assignment
      if($coordinates_calculator == '') {
        $this->handle_api_distance_calculation($product_id, $match_dest, $dest, $dis_unit, $prepare_destination_address_string, $google_api_key, $item_id);
      } else {
        $this->handle_coordinate_distance_calculation($product_id, $match_dest, $shipping_latitude, $shipping_longitude, $cart_item_product_name, $item_id);
      }
    }
  }
  
  WC()->cart->set_session();
  return 0;
}

/**
 * Get coordinates from address using Google Maps API
 */
private function get_coordinates_from_address($address_string, $google_api_key) {
  $curl = curl_init();
  curl_setopt_array($curl, array(
    CURLOPT_URL => 'https://maps.googleapis.com/maps/api/geocode/json?address=' . urlencode($address_string) . '&sensor=false&key=' . $google_api_key,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_ENCODING => "",
    CURLOPT_MAXREDIRS => 10,
    CURLOPT_TIMEOUT => 0,
    CURLOPT_FOLLOWLOCATION => true,
    CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
    CURLOPT_CUSTOMREQUEST => "GET",
  ));
  $geocode = curl_exec($curl);
  $output = json_decode($geocode);
  curl_close($curl);
  
  if (isset($output->results[0]->geometry->location->lat)) {
    $latitude = $output->results[0]->geometry->location->lat;
    $longitude = $output->results[0]->geometry->location->lng;
  } else {
    $latitude = 0;
    $longitude = 0;
  }
  
  return array('latitude' => $latitude, 'longitude' => $longitude);
}

/**
 * Get locations with stock for a given product
 */
private function get_locations_with_stock($product_id) {
  $match_dest = array();
  $isExcLoc = get_option("wcmlim_exclude_locations_from_frontend");
  
  if (!empty($isExcLoc)) {
    $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0, 'exclude' => $isExcLoc));
  } else {
    $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
  }
  
  foreach ($terms as $in => $term) {
    $term_id = $term->term_id;
    $stock = get_post_meta($product_id, 'wcmlim_stock_at_' . $term_id, true);
    $backorders = get_post_meta($product_id, '_backorders', true);
    $loc_lat = get_term_meta($term_id, 'wcmlim_lat', true);
    $loc_lng = get_term_meta($term_id, 'wcmlim_lng', true);
    $term_address = $this->wcmlim_get_locations_address($term_id);
    
    // Only include locations with stock or that allow backorders
    if(($stock > 0) || ($backorders == "yes" && $stock < 1)) {
      $match_dest[] = array(
        "locationname" => $term->name,
        "address" => $term_address,
        "termid" => $term_id,
        "termkey" => $in,
        "loc_lat" => $loc_lat,
        "loc_lng" => $loc_lng,
        "stock" => $stock
      );
    }
  }
  
  return $match_dest;
}

/**
 * Calculate distances using Google Distance Matrix API
 */
private function handle_api_distance_calculation($product_id, $match_dest, $dest, $dis_unit, $origin, $google_api_key, $item_id) {
  if(empty($dest)) return;
  
  $destination = implode("|", $dest);
  $distance = $this->get_nearby_distance_by_api($dis_unit, $origin, $destination, $google_api_key);
  
  if(is_array($distance)) {
    // Sort locations by distance
    usort($distance, function ($a, $b) {
      return floatval($a['value']) <=> floatval($b['value']);
    });
    
    $this->wcmlim_nearby_stock_adjustment($product_id, $match_dest, $distance, $item_id);
  }
}

/**
 * Calculate distances using coordinates
 */
private function handle_coordinate_distance_calculation($product_id, $match_dest, $shipping_lat, $shipping_lng, $product_name, $item_id) {
  if(empty($match_dest)) {
    wc_clear_notices();
    wc_add_notice(sprintf(__('The Item "%s" is not available at your shipping location, you need to remove it from your cart!', 'wcmlim'), $product_name), 'error');
    return;
  }
  
  $coordinates_prepare_result = array();
  foreach($match_dest as $key => $value) {
    $each_loc_lat = $value['loc_lat'];
    $each_loc_lng = $value['loc_lng'];
    
    // Calculate distance between shipping address and store location
    $distance = $this->distance_between_coordinates($shipping_lat, $shipping_lng, $each_loc_lat, $each_loc_lng);
    
    $coordinates_prepare_result[] = array(
      "locationname" => $value['locationname'],
      "address" => $value['address'],
      "termid" => $value['termid'],
      "termkey" => $value['termkey'],
      "loc_lat" => $value['loc_lat'],
      "loc_lng" => $value['loc_lng'],
      "distance" => $distance
    ); 
  }
  
  if(is_array($coordinates_prepare_result)) {
    // Sort by distance
    usort($coordinates_prepare_result, function ($a, $b) {
      return floatval($a['distance']) <=> floatval($b['distance']);
    });
    
    $this->wcmlim_nearby_stock_adjustment($product_id, $match_dest, $coordinates_prepare_result, $item_id);
  }
}

public function wcmlim_shipping_error($fields, $errors)
{
  global $woocommerce;
  $cart = $woocommerce->cart->cart_contents;
  $shipping_packages = WC()->cart->get_shipping_packages();
  $shipping_zone = wc_get_shipping_zone(reset($shipping_packages));
  $zone_id = $shipping_zone->get_id(); 
  
  $isShippingMethods = get_option('wcmlim_enable_shipping_methods');
  if ($isShippingMethods !== "on") {
    return;
  }
  
  $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false));
  $error_products = array();
  
  foreach ($cart as $array_item) {
    $product = wc_get_product($array_item['product_id']);
    $product_name = $product->get_title();
    $product_id = $product->is_type('variable') ? $array_item['variation_id'] : $array_item['product_id'];
    
    // Skip if product doesn't manage stock
    if (!$product->get_manage_stock()) {
      continue;
    }
    
    // Check if product is available in the shipping zone
    $available_in_zone = false;
    foreach ($terms as $term) {
      $wcmlim_shipping_zone = get_term_meta($term->term_id, 'wcmlim_shipping_zone', true);
      $stock_at_loc = get_post_meta($product_id, "wcmlim_stock_at_{$term->term_id}", true);
      
      if (in_array($zone_id, $wcmlim_shipping_zone) && ($stock_at_loc > 0 && $stock_at_loc !== '')) {
        $available_in_zone = true;
        break;
      }
    }
    
    if (!$available_in_zone) {
      $error_products[] = $product_name;
    }
  }
  
  if (!empty($error_products)) {
    wc_clear_notices();
    $errors->add('validation', sprintf(
      __('The following products could not be delivered to your shipping zone: %s', 'wcmlim'),
      '<b>' . implode('</b>, <b>', $error_products) . '</b>'
    ));
  }
}

public function wcmlim_fulfil_order_shipping_zones($order_id)
{
  if (empty($order_id)) {
    return;
  }

  $order = wc_get_order($order_id);
  $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;
  }
  
  // Get shipping zone ID
  $shipping_items = $order->get_shipping_methods();
  if (empty($shipping_items)) {
    return;
  }
  
  $shipping_item = reset($shipping_items);
  $rate_id = $shipping_item->get_method_id() . ':' . $shipping_item->get_instance_id();
  $zone_id = $this->get_shipping_zone_from_method_rate_id($rate_id);
  
  // Get locations in shipping zone with stock
  $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false));
  $locations_with_stock = array();
  $processed_items = array();
  
  foreach ($terms as $term_index => $term) {
    $wcmlim_shipping_zone = get_term_meta($term->term_id, 'wcmlim_shipping_zone', true);
    if (!in_array($zone_id, $wcmlim_shipping_zone)) {
      continue;
    }
    
    // Process each order item
    foreach ($order->get_items() as $item_id => $item) {
      // Skip already processed items
      if (in_array($item_id, $processed_items)) {
        continue;
      }
      
      $product_id = $item->get_variation_id() ?: $item->get_product_id();
      $item_quantity = $item->get_quantity();
      $stock_at_term = get_post_meta($product_id, 'wcmlim_stock_at_' . $term->term_id, true);
      $loc_item_meta = wc_get_order_item_meta($item_id, 'Location');
      
      // Skip if no stock or location already set
      if (empty($stock_at_term) || $stock_at_term <= 0 || !empty($loc_item_meta)) {
        continue;
      }
      
      // Update item metadata
      wc_add_order_item_meta($item_id, "Location", $term->name);
      wc_add_order_item_meta($item_id, "_selectedLocationKey", $term_index);
      wc_add_order_item_meta($item_id, "_selectedLocTermId", $term->term_id);
      wc_add_order_item_meta($item_id, "_old_selectedLocTermId", $term->term_id); // stock-update-fix
      
      // Handle stock for child locations if present
      $this->handle_child_location_stock($term, $product_id, $item_quantity);
      
      // Update stock at this location
      $new_stock = $stock_at_term - $item_quantity;
      update_post_meta($product_id, 'wcmlim_stock_at_' . $term->term_id, $new_stock);
      
      // Add note about stock reduction
      $note = sprintf(
        "{ Stock levels reduced: %s from Location: %s %d &rarr; %d }",
        $item->get_name(),
        $term->name,
        $stock_at_term,
        $new_stock
      );
      $order->add_order_note($note);
      
      // Track processed items and locations used
      $processed_items[] = $item_id;
      $locations_with_stock[] = $term->term_id;
      
      // Send notifications to location manager
      $this->sendnotification_formanager($term->term_id, $order_id);
      $this->wcmlim_update_totaldata($product_id);
    }
  }
  
  // Update order meta with location data
  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 location name if available
  if (!empty($locations_with_stock)) {
    $primary_location = get_term($locations_with_stock[0]);
    if ($primary_location && !is_wp_error($primary_location)) {
      if (WC_HPOS_IS_ACTIVE) {
        $order->update_meta_data('_location', $primary_location->name);
      } else {
        update_post_meta($order_id, "_location", $primary_location->name);
      }
    }
  }
  
  // Reduce stock levels
  $this->wc_reduce_stock_levels($order);
  $order->save();
}

/**
 * Handle stock for child locations
 */
private function handle_child_location_stock($parent_term, $product_id, $item_quantity) {
  $parent_terms = get_terms(array(
    'taxonomy' => 'locations',
    'hide_empty' => false,
    'parent' => $parent_term->term_id
  ));
  
  if (empty($parent_terms)) {
    return;
  }
  
  $stock_in_parent_location = array();
  foreach ($parent_terms as $parent_term) {
    $stock = get_post_meta($product_id, "wcmlim_stock_at_{$parent_term->term_id}", true);
    if ($stock && $stock > 0) {
      $stock_in_parent_location[$parent_term->term_id] = $stock;
    }
  }
  
  if (empty($stock_in_parent_location)) {
    return;
  }
  
  // Reduce stock from child location with maximum stock
  $parent_value = max($stock_in_parent_location);
  $parent_key = array_search($parent_value, $stock_in_parent_location);
  
  if ($parent_key) {
    $max_stock_at_sub = get_post_meta($product_id, "wcmlim_stock_at_{$parent_key}", true);
    update_post_meta($product_id, "wcmlim_stock_at_{$parent_key}", $max_stock_at_sub - $item_quantity);
  }
}

public function wcmlim_fulfil_order_nearby_shipping_address($item_id, $cart_item, $cart_item_key)
{
  // Convert cart_item if it's JSON
  if (!is_array($cart_item) && is_string($cart_item)) {
    $cart_item = json_decode($cart_item, true);
  }
  
  // Early return if cart_item is invalid
  if (!is_array($cart_item)) {
    return;
  }
  
  $product_id = ($cart_item['variation_id'] != 0) ? $cart_item['variation_id'] : $cart_item['product_id'];
  
  // Find matching cart item
  foreach (WC()->cart->get_cart() as $cart_item_id => $current_cart_item) {  
    $cart_product_id = $current_cart_item['variation_id'] ?: $current_cart_item['product_id'];
    
    if ($cart_product_id == $product_id) {
      // Check if location data exists
      if (isset(WC()->cart->cart_contents[$cart_item_id]['select_location'])) {
        $location_data = WC()->cart->cart_contents[$cart_item_id]['select_location'];
        
        // Add location meta to order item
        wc_add_order_item_meta($item_id, "Location", $location_data['location_name']);
        wc_add_order_item_meta($item_id, "_selectedLocationKey", $location_data['location_key']);
        wc_add_order_item_meta($item_id, "_selectedLocTermId", $location_data['location_termId']);
        wc_add_order_item_meta($item_id, "_old_selectedLocTermId", $location_data['location_termId']); // stock-update-fix
        
        break; // Found the item, no need to continue
      }
    }
  }   
}

public function get_shipping_zone_from_method_rate_id($method_rate_id)
{
  if (empty($method_rate_id)) {
    return 0;
  }

  global $wpdb;
  $data = explode(':', $method_rate_id);
  
  // Early return if format is invalid
  if (count($data) < 2) {
    return 0;
  }
  
  $method_id = $data[0];
  $instance_id = $data[1];

  // Query zone ID directly
  $zone_id = $wpdb->get_var($wpdb->prepare(
    "SELECT zone_id FROM {$wpdb->prefix}woocommerce_shipping_zone_methods 
     WHERE instance_id = %d AND method_id = %s",
    $instance_id,
    $method_id
  ));
  
  return $zone_id !== null ? $zone_id : 0;
}

public function wcmlim_show_address_checkout()
{
  $this->version = '3.2.1';
  
  // Register and enqueue scripts only once
  wp_enqueue_script('jquery');
  wp_register_script(
    'wcmlim_show_address', 
    WCMLIM_URL_PATH . 'public/js/wcmlim-show-address-min.js', 
    array('jquery'), 
    $this->version, 
    false
  );
  wp_enqueue_script('wcmlim_show_address');
  wp_localize_script('wcmlim_show_address', 'admin_url', array(
    'ajax_url' => admin_url('admin-ajax.php')
  ));
  
  // Enqueue styles
  wp_enqueue_style(
    'wcmlim_frontview_css', 
    WCMLIM_URL_PATH . '/public/css/wcmlim-public-min.css', 
    array(), 
    $this->version, 
    'all'
  );
  wp_enqueue_script('views', WCMLIM_URL_PATH . '/public/js/views.js', array('jquery'), $this->version . rand(), true);
}
}
?>