<?php

/**
 * Display Shipping base on zone.
 *
 * @link       http://www.techspawn.com
 * @since      1.2.5
 *
 * @package    Wcmlim
 * @subpackage Wcmlim/admin
 */

/**
 * Display Shipping base on zone.
 *
 * This class handles shipping zone display and provides compatibility
 * with third-party shipping plugins by dynamically overriding the
 * WooCommerce store address with location-specific addresses when
 * split packages are enabled.
 *
 * @package    Wcmlim
 * @subpackage Wcmlim/admin
 * @author     techspawn1 <contact@techspawn.com>
 */
class Wcmlim_Display_Shipping_zone
{
    private $current_location_id = null;
    private $package_location_map = array();
    private $is_calculating_rates = false;
    private static $current_package_location = null; // Static variable to track current package location
    private $original_store_address = null;
    private $original_store_address_2 = null;
    private $original_store_city = null;
    private $original_store_postcode = null;
    private $original_store_country = null;

    public function __construct()
    {
        $isSplitPackages = get_option('wcmlim_enable_split_packages');
        if($isSplitPackages == 'on')
        {
            add_filter( 'woocommerce_shipping_package_name', array($this, 'rename_wcmlim_package'), 10, 3);
            add_filter( 'woocommerce_package_rates', array( $this,'conditional_hide_shipping_methods'), 10, 2 );            
            add_filter( 'woocommerce_cart_shipping_packages', array( $this, 'wcmlim_woocommerce_cart_shipping_packages') ); 
            
            // Add filters to override store address for shipping plugins compatibility
            add_filter( 'pre_option_woocommerce_store_address', array($this, 'wcmlim_custom_store_address'), 10, 1 );
            add_filter( 'pre_option_woocommerce_store_address_2', array($this, 'wcmlim_custom_store_address_2'), 10, 1 );
            add_filter( 'pre_option_woocommerce_store_city', array($this, 'wcmlim_custom_store_city'), 10, 1 );
            add_filter( 'pre_option_woocommerce_store_postcode', array($this, 'wcmlim_custom_store_postcode'), 10, 1 );
            add_filter( 'pre_option_woocommerce_default_country', array($this, 'wcmlim_custom_store_country'), 10, 1 );
            
            // Add action to reset location context after shipping calculation is complete
            add_action( 'woocommerce_after_shipping_calculator', array($this, 'reset_location_context'), 10 );
            add_action( 'woocommerce_calculated_shipping', array($this, 'reset_location_context'), 10 );
            
            // Hook into package rate calculation to detect which package is being processed
            add_action( 'woocommerce_shipping_init', array($this, 'init_shipping_tracking'), 10 );
        }
        else
        {
           add_action('woocommerce_before_cart_contents', array($this, 'wcmlim_display_shipping_zones_locations_cartpage_load'));
            add_filter('woocommerce_package_rates', array($this, 'wcmlim_display_shipping_zones_locations'), 10, 2);
        }
    }
    public function wcmlim_woocommerce_cart_shipping_packages( $packages ) {
				// Reset the packages
				$packages = array();
				$location_items_map = array();

				foreach ( WC()->cart->get_cart() as $item ) {
                    $location_id = $item['select_location']['location_termId'];
                    $product_id = $item['product_id'];
                    if($location_id) {
                        $location_items_map[$location_id][] = $item;
                    }
				}
                
				foreach($location_items_map as $key => $location_items) {
                    $term_name = get_term( $key )->name;
					$packages[] = array(
                        'shipping_name' => $term_name,
                        'shipping_term_id' => $key,
						'contents' => $location_items,
						'contents_cost' => array_sum( wp_list_pluck( $location_items, 'line_total' ) ),
						'applied_coupons' => WC()->cart->applied_coupons,
						'destination' => array(
							'country' => WC()->customer->get_shipping_country(),
							'state' => WC()->customer->get_shipping_state(),
							'postcode' => WC()->customer->get_shipping_postcode(),
							'city' => WC()->customer->get_shipping_city(),
							'address' => WC()->customer->get_shipping_address(),
							'address_2' => WC()->customer->get_shipping_address_2()
						)
					);	
				}
				return $packages;
			}
    public function rename_wcmlim_package( $package_name, $i, $package ) {
     
        if ( ! empty( $package['shipping_name'] ) ) {
            $package_name = $package['shipping_name'];
        }
     
        return $package_name;
    }
    public function conditional_hide_shipping_methods($rates, $package) {
        global $woocommerce;
        $loc_term_id = $package["shipping_term_id"];
        
        // Set the static current package location for address override
        self::$current_package_location = $loc_term_id;
        $this->current_location_id = $loc_term_id;
        $this->is_calculating_rates = true;
    
        $isShippingMethods = get_option('wcmlim_enable_shipping_methods');
    
        // If the wcmlim_enable_shipping_methods option is not set, show all shipping methods
        if (empty($isShippingMethods)) {
            return $rates;
        }
    
        // Iterate through each package and ensure all methods are shown if the option is empty
        $updated_rates = array();
        foreach ($rates as $id => $data) {
            $updated_rates[$id] = $data;
        }
    
        if (!empty($package['shipping_name'])) {
            $tmp_package_items = array();
            if (isset($package['contents'])) {
                foreach ($package['contents'] as $key => $item) {
                    $product_id = $item['product_id'];
                    $variation_id = $item['variation_id'];
                    $product_id = (!empty($variation_id) || $variation_id != 0) ? $variation_id : $product_id;
                    $quantity = $item['quantity'];
                    $tmp_package_items[] = array(
                        'product_id' => $product_id,
                        'qty' => $quantity
                    );
                }
            }
            if (isset($data->meta_data)) {
                $data->meta = array('location' => $loc_term_id);
            }
    
            $wcmlim_shipping_method = get_term_meta($loc_term_id, 'wcmlim_shipping_method', true);
            if (is_array($wcmlim_shipping_method) && !empty($wcmlim_shipping_method)) {
                foreach ($rates as $id => $data) {
                    $rate_split_id = $data->instance_id;
                    if (!in_array($rate_split_id, $wcmlim_shipping_method)) {
                        unset($updated_rates[$id]);
                    }
                }
            }
        }
    
        return $updated_rates;
    }
    
    public function wcmlim_display_shipping_zones_locations($available_methods)
    {
        global $woocommerce;
        $packages = $woocommerce->cart->get_shipping_packages();

      if(isset($packages[0])){

        $packages[0]['destination']['country']  = WC()->customer->get_shipping_country();
        $packages[0]['destination']['state']    = WC()->customer->get_shipping_state();
        $packages[0]['destination']['postcode'] =  WC()->customer->get_shipping_postcode();
        $packages[0]['destination']['city']     = WC()->customer->get_shipping_city();
        $packages[0]['destination']['address']  = WC()->customer->get_shipping_address();
        $packages[0]['destination']['address_2']= WC()->customer->get_shipping_address_2();
        
        $shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $packages[0] );
      } else{
        $shipping_zone = WC_Shipping_Zones::get_zone_matching_package( $packages );
      }
        
       
       
        $zone=$shipping_zone->get_zone_name();
            $isShippingMethods = get_option('wcmlim_enable_shipping_methods');
            
            if ($isShippingMethods == "on") {
                // load the contents of the cart into an array.
                global $woocommerce;

                $cart = $woocommerce->cart->cart_contents;

                $found = 'no';
                // loop through the array looking for the tag you set. Switch to true if the tag is     found.
                foreach ($cart as $array_item) {
                    
                    if (isset($array_item['select_location']['location_name'])) {
                        $product_name = $array_item['data']->get_name();
                        $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false));
                        foreach ($terms as $term) {
                            if ($term->name == $array_item['select_location']['location_name']) {
                                $wcmlim_shipping_method = get_term_meta($term->term_id, 'wcmlim_shipping_method', true);
                            $method_found =  0;
                                foreach ($available_methods as $shipping_method => $value) {
                                     $instance_id = $value->instance_id;
                                     if(is_array($wcmlim_shipping_method)){ 
                                        if (!in_array($instance_id, $wcmlim_shipping_method)) {
                                            unset($available_methods[$shipping_method]);  
                                      }else {
                                          $method_found = $method_found +1;
                                      }
                                     }
                                     

                                }
                                if ($method_found == 0) {
                                     wc_clear_notices();
                                     wc_add_notice("Cart item <b> $product_name </b> could not be delivered in shipping zone", "error");
                                }
                            }
                        }
                    }
                }
            }
        return $available_methods;
    }
    public function wcmlim_check_cart_zone()
    {
        // load the contents of the cart into an array.
        global $woocommerce;
        $packages = $woocommerce->cart->get_shipping_packages();

        $cart = $woocommerce->cart->cart_contents;

        $found = 'no';
        // loop through the array looking for the tag you set. Switch to true if the tag is     found.
        foreach ($cart as $array_item) {
            if (isset($array_item['select_location']['location_name'])) {
                $terms = get_terms(array('taxonomy' => 'locations', 'hide_empty' => false));
                foreach ($terms as $term) {
                    if ($term->name == $array_item['select_location']['location_name']) {
                        $wcmlim_shipping_zone = get_term_meta($term->term_id, 'wcmlim_shipping_zone', true);
                        $shipping_packages =  WC()->cart->get_shipping_packages();
                        $shipping_zone = wc_get_shipping_zone(reset($shipping_packages));
                        $zone_id   = $shipping_zone->get_id();

                    }
                }
            }
        }
        return $found;
    }

    function wcmlim_display_shipping_zones_locations_cartpage_load(){
        $packages = WC()->shipping->get_packages();
    
        if (isset($packages[0])) {
            $methods = $packages[0]['rates'];
            $this->wcmlim_display_shipping_zones_locations($methods);
        }
    }
    
    /**
     * Initialize shipping tracking
     */
    public function init_shipping_tracking() {
        // Hook into shipping method calculation to track which package is being processed
        add_filter( 'woocommerce_shipping_methods', array($this, 'track_shipping_method_init'), 1 );
    }
    
    /**
     * Track shipping method initialization to detect current package context
     */
    public function track_shipping_method_init($methods) {
        // This helps us know when shipping methods are being initialized for package calculations
        return $methods;
    }
    
    /**
     * Reset location context after shipping calculation is complete
     */
    public function reset_location_context() {
        $this->current_location_id = null;
        $this->is_calculating_rates = false;
        $this->package_location_map = array();
        self::$current_package_location = null; // Reset static variable
    }
    
    /**
     * Override WooCommerce store address with location address for shipping plugins compatibility
     */
    public function wcmlim_custom_store_address($value) {
        $location_id = self::$current_package_location ?: $this->get_active_location_context();
        if ($location_id) {
            $location_address = $this->get_location_street_address($location_id);
            if (!empty($location_address)) {
                return $location_address;
            }
        }
        return $value;
    }

    /**
     * Override WooCommerce store address line 2 with location address for shipping plugins compatibility
     */
    public function wcmlim_custom_store_address_2($value) {
        // Return empty for address line 2 unless you add this field to location meta
        return '';
    }

    /**
     * Override WooCommerce store city with location city for shipping plugins compatibility
     */
    public function wcmlim_custom_store_city($value) {
        $location_id = self::$current_package_location ?: $this->get_active_location_context();
        if ($location_id) {
            $location_city = $this->get_location_city($location_id);
            if (!empty($location_city)) {
                return $location_city;
            }
        }
        return $value;
    }

    /**
     * Override WooCommerce store postcode with location postcode for shipping plugins compatibility
     */
    public function wcmlim_custom_store_postcode($value) {
        $location_id = self::$current_package_location ?: $this->get_active_location_context();
        if ($location_id) {
            $location_postcode = $this->get_location_postcode($location_id);
            if (!empty($location_postcode)) {
                return $location_postcode;
            }
        }
        return $value;
    }

    /**
     * Override WooCommerce store country with location country for shipping plugins compatibility
     */
    public function wcmlim_custom_store_country($value) {
        $location_id = self::$current_package_location ?: $this->get_active_location_context();
        if ($location_id) {
            $location_country_state = $this->get_location_country_state($location_id);
            if (!empty($location_country_state)) {
                return $location_country_state;
            }
        }
        return $value;
    }    /**
     * Get the active location context for the current shipping calculation
     */
    private function get_active_location_context() {
        // First priority: static current package location
        if (self::$current_package_location) {
            return self::$current_package_location;
        }
        
        // Second priority: current location being processed
        if ($this->current_location_id) {
            return $this->current_location_id;
        }
        
        // Fallback: get from cart only if there's a single location to avoid conflicts
        return $this->get_single_location_from_cart();
    }
    
    /**
     * Get location from cart only if there's a single location (to avoid conflicts)
     */
    private function get_single_location_from_cart() {
        if (WC()->cart && !WC()->cart->is_empty()) {
            $locations = array();
            foreach (WC()->cart->get_cart() as $cart_item) {
                if (isset($cart_item['select_location']['location_termId'])) {
                    $locations[] = $cart_item['select_location']['location_termId'];
                }
            }
            
            // Only return a location if there's exactly one unique location in cart
            $unique_locations = array_unique($locations);
            if (count($unique_locations) === 1) {
                return $unique_locations[0];
            }
        }
        
        return null;
    }
    
    /**
     * Get location street address with fallback to detailed components
     */
    private function get_location_street_address($location_id) {
        // Try simple address field first
        $street_address = get_term_meta($location_id, 'wcmlim_street_address', true);
        if (!empty($street_address)) {
            return $street_address;
        }
        
        // Fallback to detailed components
        $street_number = get_term_meta($location_id, 'wcmlim_street_number', true);
        $route = get_term_meta($location_id, 'wcmlim_route', true);
        
        $address_parts = array_filter([$street_number, $route]);
        if (!empty($address_parts)) {
            return implode(' ', $address_parts);
        }
        
        return '';
    }
    
    /**
     * Get location city with fallback to detailed components
     */
    private function get_location_city($location_id) {
        // Try simple city field first
        $city = get_term_meta($location_id, 'wcmlim_city', true);
        if (!empty($city)) {
            return $city;
        }
        
        // Fallback to locality
        $locality = get_term_meta($location_id, 'wcmlim_locality', true);
        if (!empty($locality)) {
            return $locality;
        }
        
        return '';
    }
    
    /**
     * Get location postcode with fallback to detailed components
     */
    private function get_location_postcode($location_id) {
        // Try simple postcode field first
        $postcode = get_term_meta($location_id, 'wcmlim_postcode', true);
        if (!empty($postcode)) {
            return $postcode;
        }
        
        // Fallback to postal_code
        $postal_code = get_term_meta($location_id, 'wcmlim_postal_code', true);
        if (!empty($postal_code)) {
            return $postal_code;
        }
        
        return '';
    }
    
    /**
     * Get location country/state with fallback to detailed components
     */
    private function get_location_country_state($location_id) {
        // Try simple country_state field first
        $country_state = get_term_meta($location_id, 'wcmlim_country_state', true);
        if (!empty($country_state)) {
            return $country_state;
        }
        
        // Fallback to separate country and state fields
        $country = get_term_meta($location_id, 'wcmlim_country', true);
        $state = get_term_meta($location_id, 'wcmlim_administrative_area_level_1', true);
        
        if (!empty($country)) {
            if (!empty($state)) {
                return $country . ':' . $state;
            }
            return $country;
        }
        
        return '';
    }

}
new Wcmlim_Display_Shipping_zone();
