<?php

/**
 * Backend Only Mode of the plugin (Order Fulfilment).
 *
 * 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.2.2
 * @package    Wcmlim
 * @subpackage Wcmlim/admin
 * @author     techspawn1 <contact@techspawn.com>
 */
class Wcmlim_Nearby_Instock_Location
{
  public function __construct()
  {
    $wcmlim_order_fulfil_edit = get_option('wcmlim_order_fulfil_edit');
    $fulfilment_rule = get_option("wcmlim_order_fulfilment_rules");

    // Fix logic inconsistency - only change once
    if ($fulfilment_rule == "nearby_instock") {    
      add_action('woocommerce_before_cart_contents', array($this, 'wcmlim_nearby_instock_location'), 10, 4);
      add_filter('woocommerce_cart_item_name', array($this, 'nearby_wcmlim_cart_item_name'), 10, 3); 
    }

    // Always add the price customization hook
    add_action('woocommerce_before_calculate_totals', array($this, 'add_custom_price_nearby'), 100);
  }

  /**
   * Sort helper function for distance comparison
   * 
   * @since 1.2.13
   * Updated 3.0.7
   */
  private static function sortByDis($a, $b){
    if ($a["value"] == $b["value"]) {
      return 0;
    }
    return ($a["value"] < $b["value"]) ? -1 : 1;
  }
   
  /**
   * Get Second Nearest Location if Nearest Location is Out Of Stock
   *  
   * @param array $addresses Location addresses with distances
   * @param string $dis_unit Distance unit (kms, miles, none)
   * @param int $product_id Product ID
   * @return array Second nearest store information
   */
  public function getSecondNearestLocation($addresses, $dis_unit, $product_id)
  {
    $ExcLoc = get_option("wcmlim_exclude_locations_from_frontend");
    if (!empty($ExcLoc)) {
      $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0, 'exclude' => $ExcLoc));
    } else {
      $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0));
    }
    
    $secNearStore = [];
    $secondNearLocKey = "";
    
    if (!empty($addresses)) {
      $dnumber = array_column($addresses, 'value');
      sort($dnumber, SORT_NUMERIC);
      $smallest_2nd = isset($dnumber[0]) ? $dnumber[0] : null;
      
      if ($smallest_2nd !== null) {
        foreach ($addresses as $e => $v) {
          if ($smallest_2nd == $v["value"]) {
            $secondNearLocKey = $e;
            break;
          }
        }
      }
    }
    
    if ($secondNearLocKey !== "") {
      foreach ($terms as $index => $term) {
        if ($index == $secondNearLocKey) {
          $secNearStore[] = $term->name;
          break;
        }
      }
      
      if (isset($addresses[$secondNearLocKey])) {
        $address = $addresses[$secondNearLocKey];
        if ($dis_unit == "kms") {
          $dis_in_un = $address["dis_in_un"];
        } elseif ($dis_unit == "miles") {
          $dis_in_un = round($address["value"] * 0.621, 1) . ' miles';
        } else {
          $dis_in_un = $address["dis_in_un"];
        }
        $secNearStore[] = $dis_in_un;
      }
      $secNearStore[] = $secondNearLocKey;
    }
    
    return $secNearStore;
  }

  /**
   * Displays the Selected Location below the Product name in Cart
   */
  public function nearby_wcmlim_cart_item_name($name1, $cart_item, $cart_item_key)
  {
    $from_address = get_option('from_address');

    // Find location name from from_address option
    $name = '';
    if (!empty($from_address) && is_array($from_address)) {
      foreach ($from_address as $value) {
        if ((isset($cart_item['variation_id']) && in_array($cart_item['variation_id'], $value)) || 
            (in_array($cart_item['product_id'], $value))) { 
          $name = isset($value['name']) ? $value['name'] : '';
          break;
        }
      }
    }

    // Add location information to product name
    if (isset($cart_item['select_location'])) {
      $locescstring = __("Location :", "wcmlim");
      $name1 .= sprintf('<p>%s</p>', __($locescstring . $cart_item['select_location']['location_name']));
    } else {
      // Get term information if select_location is not set
      $termExclude = get_option("wcmlim_exclude_locations_from_frontend");
      $terms = !empty($termExclude) 
        ? get_terms(['taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0, 'exclude' => $termExclude])
        : get_terms(['taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0]);
        
      foreach ($terms as $term) {
        $this->max_value_inpl = get_post_meta($cart_item['product_id'], "wcmlim_stock_at_{$term->term_id}", true);
      }
    }
    
    $this->max_in_value = isset($cart_item['select_location']) ? $cart_item['select_location'] : "";
    
    return $name1;
  }

  /**
   * Get location service radius
   */
  public function getLocationServiceRadius($distanceKey)
  {
    $ExcLoc = get_option("wcmlim_exclude_locations_from_frontend");
    $terms = !empty($ExcLoc) 
      ? get_terms(['taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0, 'exclude' => $ExcLoc])
      : get_terms(['taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0]);
    
    $_locRadius = '';
    foreach ($terms as $key => $value) {
      if ($distanceKey == $key) {
        $_locRadius = get_term_meta($value->term_id, 'wcmlim_service_radius_for_location', true);
        break;
      }
    }
    
    return $_locRadius;
  }

  /**
   * Find the nearest in-stock location for cart items
   */
  public function wcmlim_nearby_instock_location()
  {    
    global $woocommerce;
    
    // Get shipping information
    $country = WC()->customer->get_shipping_country();
    $state = WC()->customer->get_shipping_state();
    $city = WC()->customer->get_shipping_city();
    $postcode = WC()->customer->get_shipping_postcode();
    
    if (empty($city)) {
      return [];
    }
    
    // Format origin address
    $ladd = str_replace(",", "", $city);
    $city = str_replace(" ", "+", $ladd);
    $origins = $city . "+" . $state . "+" . $country;
    
    // Get configuration options
    $dis_unit = get_option("wcmlim_show_location_distance");
    $google_api_key = get_option('wcmlim_google_api_key');
    
    // Get available locations
    $isExcLoc = get_option("wcmlim_exclude_locations_from_frontend");
    $terms = !empty($isExcLoc) 
      ? get_terms(['taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0, 'exclude' => $isExcLoc])
      : get_terms(['taxonomy' => 'locations', 'hide_empty' => false, 'parent' => 0]);
    
    // Get all in-stock locations first to reduce API calls
    $location_terms = [];
    $dest = [];
    $in_stock_locations = [];
    
    // Build destination addresses and track in-stock terms
    foreach ($woocommerce->cart->get_cart() as $item => $values) {
      $product_id = ($values['variation_id'] > 0) ? $values['variation_id'] : $values['data']->get_id();
      
      foreach ($terms as $in => $term) {
        $postmeta_stock_at_term = get_post_meta($product_id, 'wcmlim_stock_at_' . $term->term_id, true);
        
        if (!empty($postmeta_stock_at_term) && ($postmeta_stock_at_term > 0)) {
          // Track in-stock locations
          $in_stock_locations[$product_id][] = [
            'term_id' => $term->term_id,
            'term_key' => $in,
            'name' => $term->name
          ];
          
          // Add location to destinations if not already added
          $term_meta = get_option("taxonomy_$term->term_id");
          $term_meta = array_map(function ($term) {
            if (!is_array($term)) {
              return $term;
            }
          }, $term_meta);
          
          $spacead = implode(" ", array_filter($term_meta));
          $formatted_dest = str_replace(" ", "+", $spacead);
          
          // Ensure we don't add duplicate destinations
          if (!in_array($formatted_dest, $dest)) {
            $dest[] = $formatted_dest;
          }
        }
      }
    }
    
    if (empty($dest)) {
      return [];
    }

    // Make a single API call for all destinations
    $destination = implode("|", $dest);
    $curl = curl_init();
    curl_setopt_array($curl, [
      CURLOPT_URL => "https://maps.googleapis.com/maps/api/distancematrix/json?units=metrics&origins=" . $origins . "&destinations=" . $destination . "&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",
    ]);
    
    $response = curl_exec($curl);
    $response_arr = json_decode($response);
    curl_close($curl);
    
    // Handle API error
    if (isset($response_arr->error_message)) {
      wc_add_notice($response_arr->error_message, 'error');
      return [];
    }
    
    // Process distance results
    $distance = [];
    if (!empty($response_arr->rows)) {
      foreach ($response_arr->rows as $r => $t) {
        foreach ($t as $key => $value) {
          foreach ($value as $a => $b) {
            if ($b->status == "OK") {
              $dis = explode(" ", $b->distance->text);
              $plaindis = str_replace(',', '', $dis[0]);
              
              if ($dis_unit == "kms") {
                $dis_in_un = $b->distance->text;
              } elseif ($dis_unit == "miles") {
                $dis_in_un = round($plaindis * 0.621, 1) . ' miles';
              } else {
                $dis_in_un = $b->distance->text;
              }
              
              $distance[] = ["value" => $plaindis, "key" => $a, "dis_in_un" => $dis_in_un];
            }
          }
        }
      }
    }
    
    // Sort distances and find nearest
    if (empty($distance)) {
      return [];
    }
    
    usort($distance, [__CLASS__, 'sortByDis']);
    $mindiskey = isset($distance[0]['key']) ? $distance[0]['key'] : 0;
    
    // Update cart items with nearest location
    $from_address = [];
    
    foreach ($woocommerce->cart->get_cart() as $item => $values) {
      $product_id = ($values['variation_id'] > 0) ? $values['variation_id'] : $values['data']->get_id();
      
      if (isset($in_stock_locations[$product_id])) {
        $loc_key = 0;
        foreach ($terms as $in => $term) {
          $postmeta_stock_at_term = get_post_meta($product_id, 'wcmlim_stock_at_' . $term->term_id, true);
          
          if (!empty($postmeta_stock_at_term) && ($postmeta_stock_at_term > 0)) {
            if ($mindiskey == $loc_key) {
              $values['select_location'] = [
                'location_name' => $term->name,
                'location_termId' => (int)$term->term_id
              ];
              
              $from_address[] = [
                'nearby_id_location' => $term->term_id,
                'product_id' => $product_id,
                'name' => $term->name
              ];
            }
            $loc_key++;
          }
        }
      }
    }
    
    update_option('from_address', $from_address);
    return $from_address;
  }
  
  /**
   * Apply custom location-based pricing
   */
  function add_custom_price_nearby($cart) {
    if (is_admin() && !defined('DOING_AJAX')) {
      return;
    }
    
    if (did_action('woocommerce_before_calculate_totals') >= 2) {
      return;
    }
    
    $from_address = get_option('from_address');
    if (empty($from_address) || !is_array($from_address)) {
      return;
    }
    
    // Create lookup array for faster access
    $location_product_map = [];
    foreach ($from_address as $addr) {
      if (isset($addr['product_id']) && isset($addr['nearby_id_location'])) {
        $location_product_map[$addr['product_id']] = $addr['nearby_id_location'];
      }
    }
    
    // Loop through cart items once
    foreach ($cart->get_cart() as $cart_item) {
      $product_id = $cart_item['data']->get_id();
      
      // Skip if we don't have location data for this product
      if (!isset($location_product_map[$product_id])) {
        continue;
      }
      
      $location_id = $location_product_map[$product_id];
      $location_regular_price = get_post_meta($product_id, "wcmlim_regular_price_at_{$location_id}", true);
      $location_sale_price = get_post_meta($product_id, "wcmlim_sale_price_at_{$location_id}", true);
      
      $product = $cart_item['data'];
      $default_price = $product->get_price();
      $default_sale_price = $product->get_sale_price();
      
      // Apply location-specific pricing
      if (!empty($location_sale_price)) {
        $cart_item['data']->set_price($location_sale_price);
      } elseif (!empty($location_regular_price)) {
        $cart_item['data']->set_price($location_regular_price);
      } elseif (!empty($default_sale_price)) {
        $cart_item['data']->set_price($default_sale_price);
      } else {
        $cart_item['data']->set_price($default_price);
      }
    }
  }
}

new Wcmlim_Nearby_Instock_Location();