<?php

namespace Ilabs\Inpost_International\Frontend;

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


use Exception;
use Ilabs\Inpost_International\Helpers\Helper;
use Ilabs\Inpost_International\Settings\Product_Settings;
use WC_Order;
use WC_Session;
use WC_Shipping_Rate;

/**
 * Frontend
 */
class Frontend {

	/**
	 * Helper instance for utility functions.
	 *
	 * @since 1.0.0
	 * @var Helper An instance of the Helper class that provides utility methods.
	 */
	private $helper;

	/**
	 * Product_Settings instance.
	 *
	 * @since 1.0.0
	 * @var Product_Settings An instance of the Product_Settings class.
	 */
	private $product_settings;

	/**
	 * Constructor
	 */
	public function __construct() {
		$this->helper           = Helper::init();
		$this->product_settings = new Product_Settings();
		$this->hooks();
	}

	/**
	 * Registers all hooks related frontend functionality.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function hooks() {

		$plugin_checkout_settings = get_option( 'inpost_international_settings_geowidget' );
		// by default show map button here.
		if ( empty( $plugin_checkout_settings ) ) {
			$plugin_checkout_settings = 'woocommerce_review_order_after_shipping';
		}

		$map_button_js_mode = false;
		if ( ! empty( $plugin_checkout_settings['map_button_output_js'] ) && 'on' === $plugin_checkout_settings['map_button_output_js'] ) {
			$map_button_js_mode = true;
		}

		if ( ! $map_button_js_mode ) {

			$hook_name = 'woocommerce_review_order_after_shipping';
			if ( ! empty( $plugin_checkout_settings['map_button_output'] ) ) {
				$hook_name = $plugin_checkout_settings['map_button_output'];
			}

			add_action(
				$hook_name,
				array( $this, 'map_button_classic_checkout' )
			);
		}

		add_action( 'woocommerce_checkout_process', array( $this, 'checkout_point_locker_validation' ), 99999 );

		add_filter( 'woocommerce_shipping_packages', array( $this, 'filter_shipping_methods_by_product_config' ), 1000 );

		add_filter( 'woocommerce_get_order_item_totals', array( $this, 'show_locker_name_in_order_details' ), 2, 100 );

		add_action( 'woocommerce_after_shipping_rate', array( $this, 'show_shipping_method_logo' ), 10 );
	}


	/**
	 * Output template with Choose Parcel Locker button
	 */
	public function map_button_classic_checkout() {

		$current_shipping_method = '';
		$fs_method_name          = '';
		$map_button_is_required  = false;

		if ( is_object( WC()->session ) ) {
			$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );

			if ( ! empty( $chosen_shipping_methods[0] ) ) {
				$current_shipping_method = $chosen_shipping_methods[0];
			}

			if ( $this->helper->is_flexible_shipping_activated() ) {
				$fs_method_name = $this->helper->get_method_linked_to_fs( $chosen_shipping_methods );
			}
		}

		if ( 0 === strpos( $current_shipping_method, 'inpost_international_automated_locker_point' ) ) {
			$map_button_is_required = true;
		}

		if ( 0 === strpos( $fs_method_name, 'inpost_international_automated_locker_point' ) ) {
			$map_button_is_required = true;
		}

		if ( $map_button_is_required ) {
			// add template with button on classic Checkout page.
			inpost_intl_core()->locate_template( 'classic-checkout-map-button.php' );
		}
	}


	/**
	 * Validates the selection of an InPost International locker during checkout.
	 *
	 * This function checks if a physical product is in the cart and if an InPost International
	 * shipping method is selected. If both conditions are met, it ensures that a locker has been chosen.
	 * If no locker is selected, it displays an error message and throws an exception.
	 *
	 * @since 1.0.0
	 * @throws Exception If no InPost International locker is selected when required.
	 *
	 * @global WC_Session $WC_Session Allows access to the WooCommerce session data.
	 *
	 * @uses WC()->session To access the current WooCommerce session.
	 * @uses wc_add_notice() To display error messages to the user.
	 * @uses get_bloginfo() To get the site's language setting.
	 *
	 * @return void
	 */
	public function checkout_point_locker_validation() {
		$current_shipping_method        = '';
		$is_physical_product_in_cart    = false;
		$fs_method_name                 = '';
		$is_inpost_international_method = false;
		static $alert_locker_shown;
		static $alert_phone_shown;

		if ( is_object( WC()->session ) ) {
			$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
			if ( ! empty( $chosen_shipping_methods[0] ) ) {
				$current_shipping_method = $chosen_shipping_methods[0];
			}
			if ( $this->helper->is_flexible_shipping_activated() ) {
				$fs_method_name = $this->helper->get_method_linked_to_fs( $chosen_shipping_methods );
			}
			$cart_contents = WC()->session->get( 'cart' );

			$is_physical_product_in_cart = $this->helper->check_physical_goods_in_cart( $cart_contents );
		}

		$is_inpost_international_method = $this->validate_is_inpost_method( $current_shipping_method );
		if ( ! empty( $fs_method_name ) ) {
			$is_inpost_international_method = $this->validate_is_inpost_method( $fs_method_name );
		}

		if ( $is_physical_product_in_cart && $is_inpost_international_method ) {

			if ( empty( $_POST['inpost_international_locker_id'] ) ) {
				if ( 0 === strpos( $current_shipping_method, 'inpost_international_automated_locker_point' ) ) {
					if ( ! $alert_locker_shown ) {
						$alert_locker_shown = true;
						if ( 'pl-PL' === get_bloginfo( 'language' ) ) {
							wc_add_notice(
								esc_html__(
									'Musisz wybrać paczkomat Inpost International',
									'inpost-international'
								),
								'error'
							);
							throw new Exception( 'Inpost International' );

						} else {
							wc_add_notice(
								esc_html__(
									'Parcel locker Inpost International must be choosen',
									'inpost-international'
								),
								'error'
							);
							throw new Exception( 'Inpost International' );
						}
					}
				}
			}

			$phone_number = null;
			if ( ! empty( $_POST['shipping_phone'] ) ) {
				$phone_number_raw = sanitize_text_field( wp_unslash( $_POST['shipping_phone'] ) );
				if ( preg_match_all( '/\d/', $phone_number_raw ) >= 7 ) {
					$phone_number = $phone_number_raw;
				}
			}
			if ( ! $phone_number ) {
				$phone_number = ! empty( $_POST['billing_phone'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_phone'] ) ) : null;
			}

			$country_of_delivery = ! empty( $_POST['shipping_country'] ) ? sanitize_text_field( wp_unslash( $_POST['shipping_country'] ) ) : null;
			if ( ! $country_of_delivery ) {
				$country_of_delivery = ! empty( $_POST['billing_country'] ) ? sanitize_text_field( wp_unslash( $_POST['billing_country'] ) ) : null;
			}

			if ( ! $phone_number || ! $this->helper->is_phone_number_valid( $phone_number ) || empty( $this->helper->get_phone_prefix_from_phone_number( $phone_number ) ) ) {

				if ( ! $alert_phone_shown ) {

					$alert_phone_shown = true;

					if ( 'PL' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Proszę wpisać numer telefonu w formacie kod kraju i numer telefonu.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Obsługiwane numery telefonów dla następujących krajów: Polska, Włochy, Hiszpania, Portugalia, Francja, Holandia, Luksemburg, Belgia.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} elseif ( 'BE' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Veuillez saisir le numéro de téléphone au format indicatif pays et numéro de téléphone.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Numéros de téléphone mobile pris en charge: Pologne, Italie, Espagne, Portugal, France, Pays-Bas, Luxembourg et Belgique.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} elseif ( 'ES' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Ingrese el número de teléfono con el formato de código de país y número de teléfono.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Números de teléfono móvil compatibles: Polonia, Italia, España, Portugal, Francia, Países Bajos, Luxemburgo y Bélgica.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} elseif ( 'FR' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Veuillez saisir le numéro de téléphone au format indicatif pays et numéro de téléphone.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Numéros de téléphone mobile pris en charge: Pologne, Italie, Espagne, Portugal, France, Pays-Bas, Luxembourg et Belgique.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} elseif ( 'IT' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Inserisci il numero di telefono nel formato prefisso internazionale e numero di telefono.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Numeri di cellulare supportati per Polonia, Italia, Spagna, Portogallo, Francia, Paesi Bassi, Lussemburgo e Belgio.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} elseif ( 'LU' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Bitte geben Sie die Telefonnummer im Format „Landesvorwahl und Telefonnummer“ ein.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Unterstützte Mobilfunknummern für die Länder Polen, Italien, Spanien, Portugal, Frankreich, Niederlande, Luxemburg und Belgien.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} elseif ( 'NL' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Voer het telefoonnummer in de notatie landcode en telefoonnummer in.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Ondersteunde mobiele telefoonnummers voor landen als Polen, Italië, Spanje, Portugal, Frankrijk, Nederland, Luxemburg en België.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} elseif ( 'PT' === $country_of_delivery ) {
						wc_add_notice( esc_html__( 'Introduza o número de telefone no formato indicativo do país e número de telefone.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Números de telemóvel suportados para os países: Polónia, Itália, Espanha, Portugal, França, Países Baixos, Luxemburgo e Bélgica.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					} else {
						wc_add_notice( esc_html__( 'Please enter the phone number in the format country code and phone number.', 'inpost-international' ), 'error' );
						wc_add_notice( esc_html__( 'Supported mobile phone numbers for countries Poland, Italy, Spain, Portugal, France, Netherlands, Luxembourg, Belgium.', 'inpost-international' ), 'error' );
						throw new Exception( 'InPost International' );
					}
				}
			}
		}
	}


	/**
	 * Filters shipping methods based on product configuration and cart contents.
	 *
	 * This function examines the cart contents and filters the available shipping methods
	 * based on product settings and compatibility with Flexible Shipping (if activated).
	 * It ensures that only allowed shipping methods for the products in the cart are presented.
	 *
	 * @since 1.0.0
	 *
	 * @param array $packages An array of shipping packages.
	 *
	 * @uses WC()->session To access the current WooCommerce session.
	 * @uses WC()->cart To access the current cart contents.
	 * @uses $this->product_settings->get_methods_allowed_by_cart() To get allowed methods based on cart contents.
	 * @uses $this->helper->is_flexible_shipping_activated() To check if Flexible Shipping is active.
	 * @uses $this->helper->get_method_linked_to_fs_by_instance_id() To get methods linked to Flexible Shipping.
	 *
	 * @return array Modified array of shipping packages with filtered shipping rates.
	 */
	public function filter_shipping_methods_by_product_config( $packages ) {
		$methods_allowed_by_cart = array();

		if ( is_object( WC()->session ) ) {
			$cart = WC()->cart->cart_contents;

			if ( ! empty( $cart ) && is_array( $cart ) ) {
				$methods_allowed_by_cart = $this->product_settings->get_methods_allowed_by_cart( $cart );
			}
		}

		$rates_allowed = array();
		$rates         = array();

		if ( isset( $packages[0]['rates'] ) ) {
			$rates = $packages[0]['rates'];
		}

		if ( is_array( $rates ) && ! empty( $rates ) ) {
			foreach ( $rates as $key => $rate_object ) {
				// if Flexible shipping is active we need check if inpost inter. method is linked to FS.
				if ( $this->helper->is_flexible_shipping_activated() ) {
					$linked_method = '';
					$instance_id   = '';

					if ( stripos( $key, ':' ) ) {
						$instance_id = trim( explode( ':', $key )[1] );
					}
					// check if some easypack method linked to Flexible Shipping.
					if ( ! empty( $instance_id ) ) {
						$linked_method = $this->helper->get_method_linked_to_fs_by_instance_id( $instance_id );
					}

					if ( 0 === strpos( $key, 'flexible_shipping' ) ) {
						// check if linked FS methods are allowed for all products in cart.
						if ( 0 === strpos( $linked_method, 'inpost_international_' ) ) {
							if ( in_array( $key, $methods_allowed_by_cart, true ) ) {
								$rates_allowed[ $key ] = $rate_object;
							}
						}
					}
				}
				// if FS is not active or for not integrated methods.
				if ( 0 === strpos( $key, 'inpost_international_' ) ) {
					if ( in_array( $key, $methods_allowed_by_cart, true ) ) {
						$rates_allowed[ $key ] = $rate_object;
					}
				} else {
					$rates_allowed[ $key ] = $rate_object;
				}
			}
		}

		if ( ! empty( $rates_allowed ) ) {
			$packages[0]['rates'] = $rates_allowed;
		}

		return $packages;
	}




	/**
	 * Show parcel machine in order details
	 *
	 * @param array    $items $items.
	 *
	 * @param WC_Order $order $order.
	 *
	 * @return array
	 */
	public function show_locker_name_in_order_details( $items, $order ) {

		$is_inpost_method  = false;
		$inpost_method_obj = null;

		$locker_desc = html_entity_decode( $order->get_meta( 'inpost_international_locker_desc' ) );
		$locker_id   = html_entity_decode( $order->get_meta( 'inpost_international_locker_id' ) );

		$inpost_methods = array(
			'inpost_international_automated_locker_point',
			'inpost_international_courier',
		);

		$fs_method_name = $order->get_meta( 'inpost_international_fs_linked' );

		$shipping_method_id = '';

		foreach ( $order->get_items( 'shipping' ) as $item_id => $item ) {
			$shipping_method_id = $item->get_method_id(); // The method ID.
			if ( in_array( $shipping_method_id, $inpost_methods, true )
				|| ( isset( $fs_method_name ) && in_array( $fs_method_name, $inpost_methods, true ) )
			) {
				$is_inpost_method  = true;
				$inpost_method_obj = $item;
			}
		}

		if ( $is_inpost_method ) {
			if ( isset( $items['shipping'] ) ) {
				if ( ! empty( $locker_id ) ) {
					$items['shipping']['value']
						.= sprintf(
							'<br>%1s:<br><span class="inpost-intl-chosen-locker-point point">%1s</span><br><span class="inpost-intl-chosen-locker-point description">%3s</span>',
							esc_html__( 'Selected parcel machine', 'inpost-international' ),
							esc_attr( $locker_id ),
							esc_html( $locker_desc )
						);

				} elseif ( is_object( $inpost_method_obj ) ) {

						$method_name = $inpost_method_obj->get_name();
						$meta_data   = $inpost_method_obj->get_meta_data();

						$inpost_order_sm_logo = null;

					foreach ( $meta_data as $meta ) {
						if ( 'inpost_order_sm_logo' === $meta->key ) {
							$inpost_order_sm_logo = $meta->value;
							break;
						}
					}

					if ( ! empty( $inpost_order_sm_logo ) ) {
						$img = $this->get_shipping_logo_html( $inpost_order_sm_logo, $inpost_method_obj );
						if ( ! empty( $img ) ) {
							$items['shipping']['label']
								.= PHP_EOL . esc_html( $method_name );

							$items['shipping']['value']
								.= sprintf(
									'%1s',
									wp_kses_post( $img )
								);
						}
					}
				}
			}
		}

		return $items;
	}


	/**
	 * Displays the shipping method logo for InPost International methods.
	 *
	 * This function checks if the given shipping method is an InPost International method
	 * (either directly or through Flexible Shipping integration) and displays the appropriate logo.
	 * The logo can be white, yellow, black, or a custom image based on the method's settings.
	 *
	 * @since 1.0.0
	 *
	 * @param WC_Shipping_Rate $method The shipping method object.
	 *
	 * @uses $this->helper->is_flexible_shipping_activated() To check if Flexible Shipping is active.
	 * @uses $this->helper->get_method_linked_to_fs_by_instance_id() To get methods linked to Flexible Shipping.
	 * @uses inpost_intl_core()->get_plugin_images_url() To get the plugin's images URL.
	 * @uses get_option() To retrieve shipping method settings.
	 *
	 * @return void Echoes the HTML for the shipping method logo.
	 */
	public function show_shipping_method_logo( $method ) {
		$fs_method_name = null;

		if ( $this->helper->is_flexible_shipping_activated() ) {

			if ( strpos( $method->get_method_id(), 'flexible_shipping_single' ) !== false ) {
				$fs_method_name = $this->helper->get_method_linked_to_fs_by_instance_id( $method->get_instance_id() );
			}
		}

		if ( 0 === strpos( $method->get_method_id(), 'inpost_international_' )
			|| ( isset( $fs_method_name ) && 0 === strpos( $fs_method_name, 'inpost_international_' ) ) ) {

			$img = '';

			$meta = $method->get_meta_data();

			if ( ! empty( $meta['inpost_order_sm_logo'] ) || ! empty( $meta['inpost_delivery_terms'] ) ) {

                $img .= '<span class="inpost_intl-shipping-method-meta-wrap">';

                if ( ! empty( $meta['inpost_order_sm_logo'] ) ) {
                    $chosen_logo = $meta['inpost_order_sm_logo'];
                    $img         .= $this->get_shipping_logo_html( $chosen_logo, $method );
                }

                if ( ! empty( $meta['inpost_delivery_terms'] ) ) {
                    $delivery_terms = '<span class="inpost-intl-shipping-meta inpost-intl-shipping-terms">';
                    $delivery_terms .= esc_html( trim( $meta['inpost_delivery_terms'] ) );
                    $delivery_terms .= '</span>';
                    $img .= $delivery_terms;
                }

                $img .= '</span>';
			}

			echo wp_kses_post( $img );
		}
	}


	/**
	 * Filters shipping methods based on the customer's shipping country.
	 *
	 * This function removes InPost International automated locker point shipping methods
	 * if the customer's shipping country is not in the list of allowed countries.
	 * The allowed countries are: Belgium, Spain, France, Italy, Luxembourg, and Netherlands.
	 *
	 * @since 1.0.0
	 *
	 * @global WooCommerce $woocommerce WooCommerce instance.
	 *
	 * @param array $rates An array of WC_Shipping_Rate objects.
	 *
	 * @uses WC()->customer To get the customer's shipping country.
	 *
	 * @return array Modified array of WC_Shipping_Rate objects with filtered shipping methods.
	 */
	public function filter_shipping_methods_by_country( $rates ) {

		// API doesn't accept COD amount > 5000.
		$methods_to_disable = array(
			'inpost_international_automated_locker_point',
		);

		$allowed_countries = array( 'BE', 'ES', 'FR', 'IT', 'LU', 'NL' );

		// Get the customer's shipping country.
		$customer_country = WC()->customer->get_shipping_country();

		$disable_inpost_int = false;

		if ( ! in_array( $customer_country, $allowed_countries, true ) ) {
			$disable_inpost_int = true;
		}

		if ( $disable_inpost_int ) {
			foreach ( $rates as $rate_key => $rate ) {
				if ( in_array( $rate->method_id, $methods_to_disable, true ) ) {
					unset( $rates[ $rate_key ] );
				}
			}
		}

		return $rates;
	}



	/**
	 * Validates if a shipping method is an InPost method.
	 *
	 * Checks if the method identifier starts with InPost international
	 * automated locker point or InPost international courier prefixes.
	 *
	 * @param string $method The shipping method identifier to validate.
	 * @return bool True if it's an InPost method, false otherwise.
	 */
	private function validate_is_inpost_method( $method ) {
		if ( 0 === strpos( $method, 'inpost_international_automated_locker_point' ) ) {
			return true;
		}

		if ( 0 === strpos( $method, 'inpost_international_courier' ) ) {
			return true;
		}

		return false;
	}


	/**
	 * Generates HTML for shipping method logo based on chosen logo type.
	 *
	 * Returns appropriate logo image HTML for white, yellow, black, mondial,
	 * or custom logo options with proper styling and alt attributes.
	 *
	 * @param string $chosen_logo The selected logo type (white, yellow, black, mondial, custom).
	 * @param mixed  $method The shipping method instance.
	 * @return string HTML string containing the logo image or empty string.
	 */
	private function get_shipping_logo_html( $chosen_logo, $method ) {

		$img = '';

		if ( 'white' === $chosen_logo ) {
			$img_white = inpost_intl_core()->get_plugin_images_url() . '/white.png';
			$img       = '<span class="inpost-intl-shipping-meta inpost-intl-shipping-method-logo">
 						    <img style="width:60px;height:auto;" src="' . esc_url( $img_white ) . '" alt="Inpost International" />
 						</span>';
		} elseif ( 'yellow' === $chosen_logo ) {
			$img_yellow = inpost_intl_core()->get_plugin_images_url() . '/yellow.png';
			$img        = '<span class="inpost-intl-shipping-meta inpost-intl-shipping-method-logo">
 						    <img style="width:60px;height:auto;" src="' . esc_url( $img_yellow ) . '" alt="Inpost International" />
 						</span>';

		} elseif ( 'black' === $chosen_logo ) {
			$img_black = inpost_intl_core()->get_plugin_images_url() . '/black.png';
			$img       = '<span class="inpost-intl-shipping-meta inpost-intl-shipping-method-logo">
 						    <img style="width:60px;height:auto;" src="' . esc_url( $img_black ) . '" alt="Inpost International" />
 						</span>';
		} elseif ( 'mondial' === $chosen_logo ) {
			$img_mondial = inpost_intl_core()->get_plugin_images_url() . '/mondial.png';
			$img         = '<span class="inpost-intl-shipping-meta inpost-intl-shipping-method-logo">
 						    <img style="width:60px;height:auto;" src="' . esc_url( $img_mondial ) . '" alt="Inpost International" />
 						</span>';
		} elseif ( 'custom' === $chosen_logo ) {
			$shipping_method_name = '';
			$method_instance_id   = '';
			if ( is_object( $method ) ) {
				$shipping_method_name = $method->get_method_id();
				$method_instance_id   = $method->get_instance_id();
			}

			$shipping_method_settings_name = 'woocommerce_' . $shipping_method_name . '_' . $method_instance_id . '_settings';
			$shipping_method_settings      = get_option( $shipping_method_settings_name );
			if ( ! empty( $shipping_method_settings['logo_custom'] ) ) {
				$img_src = $shipping_method_settings['logo_custom'];
				$img     = '<span class="inpost-intl-shipping-meta inpost-intl-shipping-method-logo">
 						    <img style="width:60px;height:auto;" src="' . esc_url( $img_src ) . '" alt="Inpost International" />
 						</span>';
			}
		}

		return $img;
	}
}
