<?php
/**
 * Plugin main class.
 *
 * @package Inspire_Labs\Alsendo_Connect
 */

namespace Inspire_Labs\Alsendo_Connect;

use Exception;
use Inspire_Labs\Alsendo_Connect\Plugin\Abstract_Ilabs_Plugin;
use WC_Order;
use Inspire_Labs\Alsendo_Connect\Shipping_Rates;

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

/**
 * Plugin
 */
class Plugin extends Abstract_Ilabs_Plugin {

	/**
	 * Text domain for plugin translations and localization.
	 */
	const TEXTDOMAIN = 'alsendo-connect';

	/**
	 * Application prefix used for option names, hooks, and identifiers.
	 */
	const APP_PREFIX = 'alsendo_connect';

	/**
	 * Static property to store the plugin directory path.
	 *
	 * @var string
	 */
	public static $plugin_dir;

	/**
	 * Array of available shipping methods for the plugin.
	 *
	 * @var array
	 */
	public $shipping_methods = array();

	/**
	 * Flag to track if WooCommerce order admin data has been displayed.
	 *
	 * @var bool
	 */
	public static $wc_order_admin_data_shown = false;


	/**
	 * Cached shipping zones \WC_Shipping_Zones::get_zones()
	 *
	 * @var $cached_zones
	 */
	public $cached_zones = array();

	/**
	 * Cached map config (per-request).
	 *
	 * @var array|null
	 */
	private $cached_map_config = null;

	/**
	 * Init
	 */
	public function init() {

		if ( is_admin() ) {
			$this->init_admin_features();
		}

		( new Integrations() );

		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_map_button_debug' ), 100 );
	}

	/**
	 * Register request filters
	 */
	protected function register_request_filters(): array {
		return array();
	}

	/**
	 * Before init
	 */
	protected function before_init() {
	}

	/**
	 * Plugins loaded hooks
	 */
	public function plugins_loaded_hooks() {

		$this->shipping_methods['alsendo_connect'] = new Shipping_Method_Alsendo_Connect();

		if ( is_admin() ) {
			( new Shipping_Rates() )->init();
			add_filter(
				'woocommerce_shipping_methods',
				array( $this, 'woocommerce_shipping_methods' ),
				20,
				1
			);
		}

		if ( ! is_plugin_active( 'apaczka-pl-mapa-punktow/apaczka-points-map.php' ) ) {
			add_action(
				'woocommerce_init',
				function () {
					$this->shipping_methods['alsendo_connect']->filtering_shipping_fields();
				}
			);
		}
	}


	/**
	 * Get option
	 *
	 * @param string $key $key.
	 *
	 * @return false|mixed|void
	 */
	public static function get_option( $key ) {
		return get_option( self::APP_PREFIX . '_settings_general_' . $key );
	}

	/**
	 * Registers the Alsendo Connect shipping method with WooCommerce.
	 *
	 * Adds the plugin's shipping method to WooCommerce's available shipping methods
	 * array using the method's ID and class name.
	 *
	 * @param array $methods Array of existing WooCommerce shipping methods.
	 *
	 * @return array Modified array with Alsendo Connect shipping method added
	 */
	public function woocommerce_shipping_methods( $methods ) {
		$methods[ $this->shipping_methods['alsendo_connect']->id ]
			= get_class( $this->shipping_methods['alsendo_connect'] );

		return $methods;
	}

	/**
	 * Init admin features
	 */
	private function init_admin_features() {
		add_filter(
			'woocommerce_get_settings_pages',
			function ( $woocommerce_settings ) {
				new Global_Settings_Integration();

				return $woocommerce_settings;
			}
		);

		( new Ajax() )->init();
		Shipment_Template_Manager::get_instance()->init();
		Sender_Template_Manager::get_instance()->init();
		( new Ecolet() );
		( new Order_Bulk_Actions() );

		if ( ! class_exists( 'Apaczka_Points_Map\Points_Map_Plugin' ) ) {

			if ( ! self::$wc_order_admin_data_shown ) {

				add_action(
					'woocommerce_admin_order_data_after_shipping_address',
					function ( WC_Order $order ) {
						$delivery_point = alsendo_connect()->get_delivery_point_meta_data( $order->get_id() );
						if ( ! empty( $delivery_point ) ) {
							$point_id          = ! empty( $delivery_point['apm_access_point_id'] ) ? $delivery_point['apm_access_point_id'] : '';
							$operator          = ! empty( $delivery_point['apm_supplier'] ) ? $delivery_point['apm_supplier'] : '';
							$point_description = ! empty( $delivery_point['apm_name'] ) ? $delivery_point['apm_name'] : '';
							echo '<div class="order_data_column alsendo_connect_order_info">
                                    <div class="alsendo_connect_order_info_title">'
								. esc_html__( 'Alsendo Connect Delivery point:', 'alsendo-connect' )
								. '</div>
                                        <p><b>'
								. esc_attr( $point_id )
								. ' (' . esc_attr( $operator ) . '. ' . esc_attr( $point_description ) . ')'
								. '</b>
                                        </p>
                                    </div>';
						}
					},
					100
				);

				self::$wc_order_admin_data_shown = true;
			}
		}
	}



	/**
	 * Get admin script id
	 *
	 * @return string
	 */
	private function get_admin_script_id(): string {
		return self::APP_PREFIX . '_admin-js';
	}

	/**
	 * Get admin css id
	 *
	 * @return string
	 */
	private function get_admin_css_id(): string {
		return self::APP_PREFIX . '_admin-css';
	}

	/**
	 * Get front blocks script id
	 *
	 * @return string
	 */
	public function get_front_blocks_script_id(): string {
		return self::APP_PREFIX . '_front_blocks-js';
	}

	/**
	 * Enqueue frontend scripts
	 */
	public function enqueue_frontend_scripts() {

		$is_virtual_products = false;

		if ( is_checkout() || has_block( 'woocommerce/checkout' ) ) {
			if ( is_object( WC()->cart ) ) {
				if ( ! WC()->cart->needs_shipping() ) {
					$is_virtual_products = true;
				}
			}
		}

		if ( $is_virtual_products ) {
			return;
		}

		if ( class_exists( 'Apaczka_Points_Map\Points_Map_Plugin' ) ) {
			return;
		}

		global $wp;
		$thankyou_page          = ! empty( $wp->query_vars['order-received'] ) ? absint( $wp->query_vars['order-received'] ) : false;
		$current_plugin_version = alsendo_connect()->get_plugin_version();

		if ( is_checkout() || has_block( 'woocommerce/checkout' ) ) {

			$bp_css_ver = '8.7';
			wp_enqueue_style(
				self::APP_PREFIX . '_bliskapaczka',
				'https://map.alsendo.com/v8.7/main.css',
				array(),
				$bp_css_ver
			);

			$front_css_path = alsendo_connect()->get_plugin_dir() . 'assets/css/front.css';
			$front_css_ver  = file_exists( $front_css_path ) ? filemtime( $front_css_path ) : $current_plugin_version;
			wp_enqueue_style(
				$this->get_admin_css_id(),
				$this->get_plugin_css_url() . '/front.css',
				array(),
				$front_css_ver
			);
		}

		if ( ! $thankyou_page && ( is_checkout() || has_block( 'woocommerce/checkout' ) ) ) {

			$bp_js_ver = '8.7';
			wp_enqueue_script(
				self::APP_PREFIX . '_bliskapaczka-sdk',
				'https://map.alsendo.com/v8.7/main.js',
				array( 'jquery' ),
				$bp_js_ver,
				array( 'in_footer' => true )
			);

			$lang = $this->get_website_language();

			$front_js_path = alsendo_connect()->get_plugin_dir() . 'assets/js/front.js';
			$front_js_ver  = file_exists( $front_js_path ) ? filemtime( $front_js_path ) : $current_plugin_version;
			wp_enqueue_script(
				self::APP_PREFIX . '_front.js',
				$this->get_plugin_js_url() . '/front.js',
				array( 'jquery' ),
				$front_js_ver,
				array( 'in_footer' => true )
			);
			wp_localize_script(
				self::APP_PREFIX . '_front.js',
				'alsendo_checkout',
				array(
					'map_config'     => $this->get_map_config(),
					'lang'           => $lang,
					'api_type'       => alsendo_connect()->get_main_settings_api(),
					'checkout_nonce' => wp_create_nonce( 'alsendo_connect_nonce_param' ),
					'plugin_version' => $current_plugin_version,
				)
			);

		}
	}

	/**
	 * Enqueue admin scripts
	 */
	public function enqueue_dashboard_scripts() {

		$current_plugin_version = alsendo_connect()->get_plugin_version();
		$api_type               = alsendo_connect()->get_main_settings_api();

		$all_templates_json         = ( new Sender_Settings_Templates_Helper() )->get_all_templates_json();
		$all_templates              = json_decode( $all_templates_json, true );
		$all_gateway_templates_json = ( new Gateway_Settings_Templates_Helper() )->get_all_templates_json();
		$all_gateway_templates      = json_decode( $all_gateway_templates_json, true );

		if ( $this->is_required_pages() ) {

			$ecolet_panel    = '';
			$ecolet          = new Ecolet();
			$ecolet_api_type = get_option( $ecolet::API_TYPE_FIELD );
			if ( 'prod' === $ecolet_api_type ) {
				$ecolet_panel = 'https://panel.ecolet.ro/';
			} else {
				$ecolet_panel = 'https://staging.ecolet.ro/';
			}

			$admin_css_path = alsendo_connect()->get_plugin_dir() . 'assets/css/admin.css';
			$admin_css_ver  = file_exists( $admin_css_path ) ? filemtime( $admin_css_path ) : $current_plugin_version;
			wp_enqueue_style(
				$this->get_admin_css_id(),
				$this->get_plugin_css_url() . '/admin.css',
				array(),
				$admin_css_ver
			);

			$current_screen = get_current_screen();
			$admin_js_path  = $this->get_plugin_dir() . 'assets/js/admin.js';
			$admin_js_ver   = file_exists( $admin_js_path ) ? filemtime( $admin_js_path ) : $current_plugin_version;

			$all_templates         = array();
			$all_gateway_templates = array();

			// enqueue scripts only on order details page.
			if ( ( isset( $_GET['page'] ) && 'wc-orders' === $_GET['page'] ) || ( isset( $_GET['post'] ) && isset( $_GET['action'] ) && 'edit' === $_GET['action'] ) ) {

				$sender_templates_json  = ( new Sender_Settings_Templates_Helper() )->get_all_templates_json();
				$sender_templates       = json_decode( $sender_templates_json, true );
				$package_templates_json = ( new Gateway_Settings_Templates_Helper() )->get_all_templates_json();
				$package_templates      = json_decode( $package_templates_json, true );

				$selected_sender_template  = get_option( 'alsendo_connect_settings_general_select_sender_template' );
				$selected_package_template = get_option( 'alsendo_connect_settings_general_select_package_template' );

				if ( 'zaslat' === $api_type ) {
					$zaslat                   = new Zaslat();
					$sender_templates         = $zaslat->get_sender_templates_for_zaslat();
					$selected_sender_template = get_option( 'alsendo_connect_settings_general_zaslat_address_id' );
				}

				$order_metabox_ecolet_js_path = $this->get_plugin_dir() . 'assets/js/order-metabox-ecolet.js';
				$order_metabox_ecolet_js_ver  = file_exists( $order_metabox_ecolet_js_path ) ? filemtime( $order_metabox_ecolet_js_path ) : $current_plugin_version;

				$order_metabox_apaczka_js_path = $this->get_plugin_dir() . 'assets/js/order-metabox-apaczka.js';
				$order_metabox_apaczka_js_ver  = file_exists( $order_metabox_apaczka_js_path ) ? filemtime( $order_metabox_apaczka_js_path ) : $current_plugin_version;

				$order_metabox_zaslat_js_path = $this->get_plugin_dir() . 'assets/js/order-metabox-zaslat.js';
				$order_metabox_zaslat_js_ver  = file_exists( $order_metabox_zaslat_js_path ) ? filemtime( $order_metabox_zaslat_js_path ) : $current_plugin_version;

				if ( 'apaczka' === $api_type ) {

					wp_enqueue_script(
						'alsendo_connect_order_metabox',
						$this->get_plugin_js_url() . '/order-metabox-apaczka.js',
						array( 'jquery' ),
						$order_metabox_apaczka_js_ver,
						array( 'in_footer' => true )
					);

				} elseif ( 'zaslat' === $api_type ) {
					wp_enqueue_script(
						'alsendo_connect_order_metabox',
						$this->get_plugin_js_url() . '/order-metabox-zaslat.js',
						array( 'jquery' ),
						$order_metabox_zaslat_js_ver,
						array( 'in_footer' => true )
					);
				} elseif ( 'ecolet' === $api_type ) {
					wp_enqueue_script(
						'alsendo_connect_order_metabox',
						$this->get_plugin_js_url() . '/order-metabox-ecolet.js',
						array( 'jquery' ),
						$order_metabox_ecolet_js_ver,
						array( 'in_footer' => true )
					);
				}

				wp_localize_script(
					'alsendo_connect_order_metabox',
					'alsendo_order_metabox',
					array(
						'ajaxurl'                       => admin_url( 'admin-ajax.php' ),
						'ecolet_panel'                  => $ecolet_panel,
						'preloader'                     => $this->get_plugin_img_url() . '/animation-round-small.gif',
						'selected_sender_template'      => $selected_sender_template,
						'selected_package_template'     => $selected_package_template,
						'sender_templates'              => $sender_templates,
						'package_properties_templates'  => $package_templates,
						'api_type'                      => alsendo_connect()->get_main_settings_api(),
						'shipping_method_alert'         => esc_html__( 'Shipping method cannot be empty.', 'alsendo-connect' ),
						'zaslat_reload_message'         => esc_html__( 'Order cancellation... After cancellation the page will reload.', 'alsendo-connect' ),
						'reload_message'                => esc_html__( 'Page will be re-loaded after 5 seconds', 'alsendo-connect' ),
						'text_here'                     => esc_html__( 'here', 'alsendo-connect' ),
						'text_max_parcels'              => esc_html__( 'Max 10 parcels can be added', 'alsendo-connect' ),
						'text_additional_parcel'        => esc_html__( 'Additional parcel', 'alsendo-connect' ),
						'recalc_notice'                 => esc_html__( 'Some fields have been changed. Please re-calculate parcel.', 'alsendo-connect' ),
						'text_no_order_id'              => esc_html__( 'Order created but has no order_id', 'alsendo-connect' ),
						'text_no_selected'              => esc_html__( 'Alsendo Connect: Please select service', 'alsendo-connect' ),
						'text_order_section'            => esc_html__( "Order was put to section 'Order to send'", 'alsendo-connect' ),
						'text_order_details'            => esc_html__( 'Check your Ecolet panel for details', 'alsendo-connect' ),
						'text_remove_parcel'            => esc_html__( 'Remove Parcel', 'alsendo-connect' ),
						'text_choose_shipment_template' => esc_html__( 'Choose shipment template', 'alsendo-connect' ),
						'text_posta_romana_code'        => esc_html__( 'Declared value must be greater than 20 RON for Post Romana', 'alsendo-connect' ),
						'text_contents_order_id'        => esc_html__( 'Order ID', 'alsendo-connect' ),
						'text_contents_product_id'      => esc_html__( 'Product ID', 'alsendo-connect' ),
						'text_contents_product_name'    => esc_html__( 'Product Name', 'alsendo-connect' ),
						'log_path'                      => $this->get_woocommerce_logs_section_url(),
						'declare_content_as_order'      => 'yes' === get_option( 'alsendo_connect_settings_general_declared_content_auto' ),
					)
				);
			}

			if ( is_a( $current_screen, 'WP_Screen' ) && 'woocommerce_page_wc-settings' === $current_screen->id ) {

				if ( isset( $_GET['tab'] ) && 'alsendo_connect_settings_general' === $_GET['tab'] ) {
					wp_enqueue_script(
						$this->get_admin_script_id(),
						$this->get_plugin_js_url() . '/admin.js',
						array( 'jquery' ),
						$admin_js_ver,
						array( 'in_footer' => true )
					);

					$current_section = isset( $_GET['section'] ) ? sanitize_text_field( wp_unslash( $_GET['section'] ) ) : '';
					if ( 'package_templates' === $current_section ) {
						$this->enqueue_package_templates_scripts();
					}
					if ( 'sender_templates' === $current_section ) {
						$this->enqueue_sender_templates_scripts();
					}
				}
			} else {
				// avoid JS errors in console on Order edit page.
				wp_enqueue_script(
					$this->get_admin_script_id(),
					$this->get_plugin_js_url() . '/admin.js',
					array( 'jquery', 'mediaelement', 'wc-admin-order-meta-boxes' ),
					$admin_js_ver,
					array( 'in_footer' => true )
				);
			}

			$lang = $this->get_website_language();

			$ecolet_services = $ecolet->get_service_structure_ecolet();

			wp_localize_script(
				$this->get_admin_script_id(),
				'alsendo_admin',
				array(
					'ajaxurl'            => admin_url( 'admin-ajax.php' ),
					'ecolet_panel'       => $ecolet_panel,
					'preloader'          => $this->get_plugin_img_url() . '/animation-round-small.gif',
					'nonce'              => wp_create_nonce( 'alsendo_connect_order_metabox' ),
					'settings_nonce'     => wp_create_nonce( 'alsendo_connect_nonce_param' ),
					'templates'          => $all_templates,
					'gateway_templates'  => $all_gateway_templates,
					'btn_text1'          => esc_html__( 'Check connection', 'alsendo-connect' ),
					'btn_text2'          => esc_html__( 'Connected', 'alsendo-connect' ),
					'btn_text3'          => esc_html__( 'Connected OK', 'alsendo-connect' ),
					'ecolet_status_text' => esc_html__( 'Not connected', 'alsendo-connect' ),
					'alert_text'         => esc_html__( 'Save settings to load correct list of available services', 'alsendo-connect' ),
					'lang'               => $lang,
					'api_type'           => alsendo_connect()->get_main_settings_api(),
					'logs_url'           => esc_url( alsendo_connect()->get_woocommerce_logs_section_url() ),
					'ecolet_connected'   => ! empty( $ecolet_services ) && is_array( $ecolet_services ) ? true : false,
				)
			);

			$bp_css_ver = '8.7';
			wp_enqueue_style(
				self::APP_PREFIX . '_bliskapaczka',
				'https://map.alsendo.com/v8.7/main.css',
				array(),
				$bp_css_ver
			);

			$bp_js_ver = '8.7';
			wp_enqueue_script(
				self::APP_PREFIX . '_bliskapaczka-sdk',
				'https://map.alsendo.com/v8.7/main.js',
				array( 'jquery' ),
				$bp_js_ver,
				array( 'in_footer' => true )
			);

		}

		if ( function_exists( 'get_current_screen' ) ) {
			$current_screen = get_current_screen();
			if ( is_a( $current_screen, 'WP_Screen' ) && 'woocommerce_page_wc-settings' === $current_screen->id ) {
				if ( isset( $_GET['tab'] ) && 'shipping' === $_GET['tab'] ) {

					wp_enqueue_script(
						'alsendo_shipping_method_settings',
						$this->get_plugin_js_url() . '/shipping-method-settings.js',
						array( 'jquery' ),
						$current_plugin_version,
						array( 'in_footer' => true )
					);

					wp_localize_script(
						'alsendo_shipping_method_settings',
						'alsendo_shipping_settings',
						array(
							'ajaxurl'           => admin_url( 'admin-ajax.php' ),
							'preloader'         => $this->get_plugin_img_url() . '/animation-round-small.gif',
							'nonce'             => wp_create_nonce( 'alsendo_connect_shipping_method_settings' ),
							'templates'         => $all_templates,
							'gateway_templates' => $all_gateway_templates,
							'api_type'          => alsendo_connect()->get_main_settings_api(),
							'logs_url'          => esc_url( alsendo_connect()->get_woocommerce_logs_section_url() ),
						)
					);

					//wp_enqueue_script( 'alsendo-shipping-method-settings' );
				}
			}
		}
	}


	/**
	 * Check is page require plugin scripts enqueue
	 */
	public function is_required_pages() {

		global $pagenow;

		if ( isset( $_GET['post'] ) && ! empty( $_GET['post'] ) && is_numeric( $_GET['post'] ) ) {
			if ( get_post_type() === 'product' ) {
				return false;
			}
		}

		$current_screen = get_current_screen();

		if ( 'post.php' === $pagenow || 'post-new.php' === $pagenow ) {
			return true;
		}

		if ( is_a( $current_screen, 'WP_Screen' ) && 'woocommerce_page_wc-settings' === $current_screen->id ) {
			if ( isset( $_GET['tab'] ) && 'alsendo_connect_settings_general' === $_GET['tab'] ) {
				return true;
			}
		}

		if ( is_a( $current_screen, 'WP_Screen' ) && 'woocommerce_page_wc-orders' === $current_screen->id ) {
			if ( isset( $_GET['id'] ) ) {
				return true;
			}
		}

		return false;
	}

	/**
	 * Enqueue scripts and styles for the Package Templates settings page.
	 *
	 * @return void
	 */
	private function enqueue_package_templates_scripts() {
		$current_plugin_version = alsendo_connect()->get_plugin_version();

		wp_enqueue_script( 'jquery-ui-dialog' );
		wp_enqueue_style( 'wp-jquery-ui-dialog' );

		$pkg_tpl_js_path = $this->get_plugin_dir() . 'assets/js/package-templates.js';
		$pkg_tpl_js_ver  = file_exists( $pkg_tpl_js_path ) ? filemtime( $pkg_tpl_js_path ) : $current_plugin_version;

		wp_enqueue_script(
			self::APP_PREFIX . '_package-templates-js',
			$this->get_plugin_js_url() . '/package-templates.js',
			array( 'jquery', 'jquery-ui-dialog' ),
			$pkg_tpl_js_ver,
			array( 'in_footer' => true )
		);

		wp_localize_script(
			self::APP_PREFIX . '_package-templates-js',
			'alsendo_connect_templates',
			array(
				'ajax_url'                    => admin_url( 'admin-ajax.php' ),
				'set_default_nonce'           => wp_create_nonce( 'alsendo_connect_ajax_set_default_template' ),
				'default_slug'                => Shipment_Template_Manager::get_default_template_slug(),
				'i18n_add_template'           => esc_html__( 'Add template', 'alsendo-connect' ),
				'i18n_edit_template'          => esc_html__( 'Edit template', 'alsendo-connect' ),
				'i18n_save'                   => esc_html__( 'Save', 'alsendo-connect' ),
				'i18n_cancel'                 => esc_html__( 'Cancel', 'alsendo-connect' ),
				'i18n_saved'                  => esc_html__( 'Saved successfully', 'alsendo-connect' ),
				'i18n_set_as_default'         => esc_html__( 'Set as default template', 'alsendo-connect' ),
				'i18n_default_template'       => esc_html__( 'Default template', 'alsendo-connect' ),
				'i18n_default_set_success'    => esc_html__( 'Default template updated', 'alsendo-connect' ),
				'i18n_error_deleting'         => esc_html__( 'Error deleting template', 'alsendo-connect' ),
				'i18n_error_setting_default'  => esc_html__( 'Error setting default template', 'alsendo-connect' ),
				'i18n_fill_required'          => esc_html__( 'Please fill in the required fields:', 'alsendo-connect' ),
				'i18n_field_template_name'    => esc_html__( 'Template name', 'alsendo-connect' ),
				'i18n_field_length'           => esc_html__( 'Length', 'alsendo-connect' ),
				'i18n_field_width'            => esc_html__( 'Width', 'alsendo-connect' ),
				'i18n_field_height'           => esc_html__( 'Height', 'alsendo-connect' ),
				'i18n_field_weight'           => esc_html__( 'Weight', 'alsendo-connect' ),
				'i18n_field_package_contents' => esc_html__( 'My package contents', 'alsendo-connect' ),
				'i18n_field_shipping_method'  => esc_html__( 'Default way to send a parcel', 'alsendo-connect' ),
				'i18n_field_pickup_hour_from' => esc_html__( 'Pickup hour from', 'alsendo-connect' ),
				'i18n_field_pickup_hour_to'   => esc_html__( 'Pickup hour to', 'alsendo-connect' ),
				'i18n_additional_parcel'      => esc_html__( 'Additional parcel', 'alsendo-connect' ),
				'i18n_remove'                 => esc_html__( 'Remove', 'alsendo-connect' ),
				'i18n_parcel_type'            => esc_html__( 'Parcel type', 'alsendo-connect' ),
				'i18n_non_standard_package'   => esc_html__( 'Non standard package', 'alsendo-connect' ),
				'i18n_length_cm'              => esc_html__( 'Length [cm]', 'alsendo-connect' ),
				'i18n_width_cm'               => esc_html__( 'Width [cm]', 'alsendo-connect' ),
				'i18n_height_cm'              => esc_html__( 'Height [cm]', 'alsendo-connect' ),
				'i18n_weight_kg'              => esc_html__( 'Weight [kg]', 'alsendo-connect' ),
				'i18n_server_error'           => esc_html__( 'Server error', 'alsendo-connect' ),
				'i18n_ajax_not_found'         => esc_html__( 'AJAX handler not found. The AJAX action may not be registered on the server.', 'alsendo-connect' ),
			)
		);
	}

	/**
	 * Enqueue scripts and styles for the Sender Templates settings page.
	 *
	 * @return void
	 */
	private function enqueue_sender_templates_scripts() {
		$current_plugin_version = alsendo_connect()->get_plugin_version();

		wp_enqueue_script( 'jquery-ui-dialog' );
		wp_enqueue_style( 'wp-jquery-ui-dialog' );

		$sender_tpl_js_path = $this->get_plugin_dir() . 'assets/js/sender-templates.js';
		$sender_tpl_js_ver  = file_exists( $sender_tpl_js_path ) ? filemtime( $sender_tpl_js_path ) : $current_plugin_version;

		wp_enqueue_script(
			self::APP_PREFIX . '_sender-templates-js',
			$this->get_plugin_js_url() . '/sender-templates.js',
			array( 'jquery', 'jquery-ui-dialog' ),
			$sender_tpl_js_ver,
			array( 'in_footer' => true )
		);

		wp_localize_script(
			self::APP_PREFIX . '_sender-templates-js',
			'alsendo_connect_sender_templates',
			array(
				'ajax_url'                   => admin_url( 'admin-ajax.php' ),
				'set_default_nonce'          => wp_create_nonce( 'alsendo_connect_ajax_set_default_sender_template' ),
				'default_slug'               => Sender_Template_Manager::get_default_template_slug(),
				'i18n_add_template'          => esc_html__( 'Add template', 'alsendo-connect' ),
				'i18n_edit_template'         => esc_html__( 'Edit template', 'alsendo-connect' ),
				'i18n_save'                  => esc_html__( 'Save', 'alsendo-connect' ),
				'i18n_cancel'                => esc_html__( 'Cancel', 'alsendo-connect' ),
				'i18n_saved'                 => esc_html__( 'Saved successfully', 'alsendo-connect' ),
				'i18n_set_as_default'        => esc_html__( 'Set as default template', 'alsendo-connect' ),
				'i18n_default_template'      => esc_html__( 'Default template', 'alsendo-connect' ),
				'i18n_default_set_success'   => esc_html__( 'Default template updated', 'alsendo-connect' ),
				'i18n_error_deleting'        => esc_html__( 'Error deleting template', 'alsendo-connect' ),
				'i18n_error_setting_default' => esc_html__( 'Error setting default template', 'alsendo-connect' ),
				'i18n_fill_required'         => esc_html__( 'Please fill in the required fields:', 'alsendo-connect' ),
				'i18n_field_template_name'   => esc_html__( 'Template name', 'alsendo-connect' ),
				'i18n_server_error'          => esc_html__( 'Server error', 'alsendo-connect' ),
				'i18n_ajax_not_found'        => esc_html__( 'AJAX handler not found. The AJAX action may not be registered on the server.', 'alsendo-connect' ),
			)
		);
	}

	/**
	 * 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 ) {

		static $details_shown = false;

		$locker_data = alsendo_connect()->get_delivery_point_meta_data( $order->get_id() );
		if ( empty( $locker_data ) ) {
			return $items;
		}

		if ( ! $details_shown ) {
			$locker_id       = ! empty( $locker_data['apm_access_point_id'] ) ? $locker_data['apm_access_point_id'] : '';
			$locker_operator = ! empty( $locker_data['apm_supplier'] ) ? $locker_data['apm_supplier'] : '';
			if ( ! empty( $locker_operator ) ) {
				$locker_id = esc_html( $locker_operator ) . ': ' . esc_attr( $locker_id );
			}

			$locker_desc        = '';
			$locker_name        = ! empty( $locker_data['apm_name'] ) ? $locker_data['apm_name'] : '';
			$locker_street      = ! empty( $locker_data['apm_street'] ) ? $locker_data['apm_street'] : '';
			$locker_postal_code = ! empty( $locker_data['apm_postal_code'] ) ? $locker_data['apm_postal_code'] : '';
			$locker_city        = ! empty( $locker_data['apm_city'] ) ? $locker_data['apm_city'] : '';

			$locker_desc .= $locker_name . '<br>' . $locker_street . '<br>' . $locker_postal_code . ' ' . $locker_city;

			$shipping_method_id          = '';
			$shipping_method_instance_id = '';

			foreach ( $order->get_items( 'shipping' ) as $item_id => $item ) {
				$shipping_method_id          = $item->get_method_id();
				$shipping_method_instance_id = $item->get_instance_id();
			}

			$items['shipping']['value']
				.= sprintf(
					'<br>%1s:<br><span class="alsendo-shipments-chosen-locker-point point">%1s</span><br><span class="alsendo-shipments-chosen-locker-point description">%3s</span>',
					esc_html__( 'Selected point', 'alsendo-connect' ),
					esc_attr( $locker_id ),
					$locker_desc
				);

			$details_shown = true;
		}

		return $items;
	}


	/**
	 * Get logo for Apaczka services
	 *
	 * @param int|string $service_id $service_id.
	 *
	 * @return string|null
	 */
	public function get_logo_apaczka( $service_id ) {
		switch ( (int) $service_id ) {
			case 1:
			case 2:
			case 3:
			case 4:
			case 5:
			case 6:
			case 8:
			case 13:
			case 14:
			case 15:
			case 16:
				return 'ups';

			case 20:
			case 21:
			case 22:
			case 23:
			case 24:
			case 25:
			case 26:
			case 28:
			case 29:
			case 30:
				return 'dpd';

			case 41:
			case 40:
			case 42:
			case 43:
			case 45:
			case 46:
			case 47:
				return 'inpost';

			case 162:
			case 163:
			case 60:
			case 64:
			case 65:
			case 66:
			case 67:
			case 68:
			case 69:
				return 'pocztex';

			case 86:
			case 81:
			case 82:
			case 83:
			case 84:
			case 87:
			case 91:
			case 92:
				return 'dhl';

			case 50:
			case 53:
				return 'orlen';

			case 110:
				return 'ipaczka';

			case 150:
				return 'geis';

			case 151:
			case 153:
				return 'fedex';

			case 191:
				return 'apaczka-niemcy';

			case 201:
			case 200:
			case 202:
			case 203:
			case 204:
			case 205:
			case 206:
			case 207:
			case 208:
				return 'gls';

			case 211:
				return 'wawa';

			case 220:
				return 'pallex';

			case 230:
				return 'hellmann';

			case 240:
				return 'rhenus';

			case 260:
			case 261:
				return 'ambro';

			case 250:
			case 251:
				return 'geodis';

			case 90:
			case 310:
			case 311:
			case 312:
			case 315:
				return 'alsendo-international';

			case 313:
			case 314:
			case 316:
			case 317:
				return 'red-packeta';

			default:
				return null;

		}
	}


	/**
	 * Get logo for Ecolet services
	 *
	 * @param int|string $service_id $service_id.
	 *
	 * @return string|null
	 */
	public function get_logo_ecolet( $service_id ) {
		switch ( (int) $service_id ) {
			case 55:
				return 'bookurier_metropolitan';
			case 8:
				return 'sameday_nextday';
			case 63:
			case 41:
				return 'sameday_locker';
			case 53:
				return 'bookurier_bucuresti_24';
			case 61:
			case 60:
			case 59:
				return 'fan_courier_fanbox';
			case 70:
				return 'fan_courier_marfa';
			case 73:
			case 72:
			case 71:
			case 69:
			case 57:
			case 56:
			case 48:
			case 47:
			case 46:
			case 45:
			case 44:
			case 43:
			case 42:
			case 19:
			case 17:
			case 16:
			case 14:
			case 13:
			case 12:
				return 'dpd';
			case 49:
			case 81:
			case 82:
			case 83:
			case 84:
				return 'cargus_easy_collect';
			case 4:
			case 85:
				return 'urgent_cargus_standard';
			case 1:
				return 'fan_courier_standard';
			case 5:
			case 64:
			case 65:
			case 66:
			case 67:
			case 68:
			case 74:
			case 75:
			case 76:
				return 'gls';
			case 86:
			case 87:
			case 88:
			case 89:
			case 91:
			case 92:
			case 93:
			case 94:
			case 95:
			case 96:
			case 97:
			case 98:
			case 99:
			case 104:
				return 'ups';
			case 78:
			case 79:
			case 80:
			case 111:
			case 112:
			case 148:
			case 151:
				return 'dhl';
			case 90:
				return 'posta-romana';
			case 116:
			case 117:
			case 123:
			case 127:
			case 128:
			case 133:
			case 138:
			case 142:
			case 145:
			case 146:
				return 'fedex';
			default:
				return null;

		}
	}


	/**
	 * Get logo for Zaslat services
	 *
	 * @param int|string $service_id $service_id.
	 *
	 * @return string|null
	 */
	public function get_logo_zaslat( $service_id ) {
		switch ( (int) $service_id ) {
			case 4:
			case 52:
			case 66:
			case 1080:
				return 'dpd';

			case 7:
			case 83:
			case 1470:
				return 'gls';

			case 86:
			case 87:
			case 88:
			case 89:
			case 91:
			case 92:
			case 93:
			case 94:
			case 95:
			case 96:
			case 97:
			case 98:
				return 'ups';

			case 99:
			case 1503:
				return 'fedex';

			case 1554:
				return 'sps';

			case 11:
			case 79:
			case 80:
				return 'ppl';

			case 131:
				return 'wedo';

			case 13:
				return 'toptrans';

			case 1091:
				return 'balikovna';

			case 1298:
				return 'liftago';
			case 1352:
			case 1546:
			case 1548:
			case 1551:
				return 'zasilkovna';

			default:
				return null;

		}
	}


	/**
	 * Retrieves the API type used for a shipping order from metadata.
	 *
	 * Extracts and returns the 'used_api' value from the provided metadata array,
	 * or returns an empty string if not found.
	 *
	 * @param array $meta_data Order metadata containing API information.
	 *
	 * @return string The API type used (e.g., 'apaczka', 'ecolet', 'zaslat') or empty string
	 */
	public function get_api_used( $meta_data ) {
		$used_api = '';
		if ( ! empty( $meta_data['used_api'] ) ) {
			$used_api = $meta_data['used_api'];
		}

		return $used_api;
	}

	/**
	 * Retrieves and caches shipping zones.
	 *
	 * @uses WC_Shipping_Zones::get_zones() To fetch shipping zones if not already cached.
	 *
	 * @return array An array of WooCommerce shipping zones, or an empty array if WC_Shipping_Zones class doesn't exist.
	 */
	public function get_cached_zones() {
		$cached_zones = ! empty( $this->cached_zones ) ? $this->cached_zones : null;
		if ( empty( $cached_zones ) ) {
			if ( class_exists( 'WC_Shipping_Zones' ) ) {
				$cached_zones       = \WC_Shipping_Zones::get_zones();
				$this->cached_zones = $cached_zones;
			}
		}

		if ( empty( $this->cached_zones ) ) {
			if ( class_exists( 'WC_Shipping_Zones' ) ) {
				$worldwide_zone = \WC_Shipping_Zones::get_zone( 0 );
				if ( ! empty( $worldwide_zone ) ) {
					// Add the worldwide zone to our cached zones.
					$this->cached_zones[0] = array(
						'zone_id'                 => 0,
						'zone_name'               => $worldwide_zone->get_zone_name(),
						'zone_order'              => 0,
						'zone_locations'          => $worldwide_zone->get_zone_locations(),
						'zone_location_code'      => array(),
						'formatted_zone_location' => $worldwide_zone->get_formatted_location(),
						'shipping_methods'        => $worldwide_zone->get_shipping_methods(),
					);
				}
			}
		}

		return $cached_zones;
	}



	/**
	 * Create shipping methods config for use in JS logic showing map on checkout
	 */
	public function get_map_config() {

		$is_cached = null !== $this->cached_map_config;
		if ( $is_cached ) {
			return is_array( $this->cached_map_config ) ? $this->cached_map_config : array();
		}

		$start                  = microtime( true );
		$zones_count            = 0;
		$shipping_instances_cnt = 0;

		$api = $this->get_main_settings_api();

		$config = array();
		// Get all your existing shipping zones IDS.
		$delivery_zones = $this->get_cached_zones();

		$zone_ids    = array_keys( array( '' ) + $delivery_zones );
		$zones_count = is_array( $zone_ids ) ? count( $zone_ids ) : 0;

		foreach ( $zone_ids as $zone_id ) {

			$shipping_zone    = new \WC_Shipping_Zone( $zone_id );
			$shipping_methods = $shipping_zone->get_shipping_methods( true, 'values' );

			if ( is_array( $shipping_methods ) ) {
				foreach ( $shipping_methods as $instance_id => $shipping_method ) {
					++$shipping_instances_cnt;
					if ( isset( $shipping_method->instance_settings['display_apaczka_map'] ) && 'yes' === $shipping_method->instance_settings['display_apaczka_map'] ) {
						$supplier_defined_in_shipping_method = strtoupper( $shipping_method->instance_settings['supplier_apaczka_map'] );

						if ( 'ALL_APACZKA' === $supplier_defined_in_shipping_method
							|| 'ALL_ECOLET' === $supplier_defined_in_shipping_method
							|| 'ALL_ZASLAT' === $supplier_defined_in_shipping_method
							|| 'ALL' === $supplier_defined_in_shipping_method
						) {

							if ( 'ALL_APACZKA' === $supplier_defined_in_shipping_method ) {
								$config[ $instance_id ]['geowidget_supplier'] = array(
									'RUCH',
									'INPOST',
									'INPOST_INTERNATIONAL',
									'POCZTA',
									'DPD',
									'UPS',
									'DHL',
									'GLS',
									'PACKETA',
								);
							}

							if ( 'ALL_ECOLET' === $supplier_defined_in_shipping_method ) {
								$config[ $instance_id ]['geowidget_supplier'] = array(
									'DPD',
									'SAMEDAY',
									'CARGUS',
									'FAN_COURIER',
									'GLS',
								);
							}

							if ( 'ALL_ZASLAT' === $supplier_defined_in_shipping_method ) {
								$config[ $instance_id ]['geowidget_supplier'] = array(
									'DPD',
									'GLS',
									'ONE_DELIVERY',
									'PACKETA',
									'PPL',
									'BALIKOVNA',
								);
							}

							if ( 'ALL' === $supplier_defined_in_shipping_method ) {
								if ( 'apaczka' === $api ) {
									$config[ $instance_id ]['geowidget_supplier'] = array(
										'RUCH',
										'INPOST',
										'INPOST_INTERNATIONAL',
										'POCZTA',
										'DPD',
										'UPS',
										'DHL',
										'GLS',
										'PACKETA',
									);
								}

								if ( 'ecolet' === $api ) {
									$config[ $instance_id ]['geowidget_supplier'] = array(
										'DPD',
										'SAMEDAY',
										'CARGUS',
										'FAN_COURIER',
										'GLS',
									);
								}

								if ( 'zaslat' === $api ) {
									$config[ $instance_id ]['geowidget_supplier'] = array(
										'DPD',
										'GLS',
										'ONE_DELIVERY',
										'PACKETA',
										'PPL',
										'BALIKOVNA',
									);
								}
							}
						} else {
							if ( 'DHL_PARCEL' === $supplier_defined_in_shipping_method ) {
								$supplier_defined_in_shipping_method = 'DHL';
							} elseif ( 'PWR' === $supplier_defined_in_shipping_method ) {
								$supplier_defined_in_shipping_method = 'RUCH';
							} elseif ( 'ECOLET_DPD' === $supplier_defined_in_shipping_method ) {
								$supplier_defined_in_shipping_method = 'DPD';
							} elseif ( 'ZASLAT_DPD' === $supplier_defined_in_shipping_method ) {
								$supplier_defined_in_shipping_method = 'DPD';
							} elseif ( 'ZASLAT_GLS' === $supplier_defined_in_shipping_method ) {
								$supplier_defined_in_shipping_method = 'GLS';
							} elseif ( 'ONE' === $supplier_defined_in_shipping_method ) {
								$supplier_defined_in_shipping_method = 'ONE_DELIVERY';
							}

							$config[ $instance_id ]['geowidget_supplier'] = array( $supplier_defined_in_shipping_method );
						}

						$config[ $instance_id ]['geowidget_only_cod'] = $shipping_method->instance_settings['only_cod_apaczka_map'];
						$config[ $instance_id ]['method_name']        = $shipping_method->title;
					}
				}
			}
		}

		$this->cached_map_config = $config;
		return $config;
	}


	/**
	 * Retrieves the current website language code.
	 *
	 * Detects and returns the active language code by checking for multilingual plugins
	 * (WPML, Polylang) or falls back to WordPress locale. Returns a 2-character language code.
	 *
	 * @return string Two-character language code (e.g., 'en', 'pl', 'ro')
	 */
	public function get_website_language() {
		$lang = '';

		// Check for WPML.
		if ( class_exists( 'SitePress' ) ) {
			$lang = apply_filters( 'wpml_current_language', null );
		}

		// Check for Polylang.
		if ( empty( $lang ) && function_exists( 'pll_current_language' ) ) {
			$lang = pll_current_language();
		}

		// Standard WordPress (no multilingual plugin).
		if ( empty( $lang ) ) {
			$locale = get_locale();
			$lang   = substr( $locale, 0, 2 );
		}

		// Normalize to lowercase and extract first 2 characters.
		$lang = strtolower( substr( $lang, 0, 2 ) );

		// Special case: Czech language - return 'cz' instead of 'cs'.
		if ( 'cs' === $lang ) {
			return 'cz';
		}

		// Validate language code (should be 2 lowercase letters).
		/*if ( preg_match( '/^[a-z]{2}$/', $lang ) ) {
			return $lang;
		}*/

		$translations_exits = array( 'en', 'pl', 'ro', 'cz', 'sk' );

		if ( ! in_array( $lang, $translations_exits, true ) ) {
			return 'en';
		}

		// Fallback to English if validation fails.
		return $lang;
	}


	/**
	 * Generates the URL for the WooCommerce logs section in the admin area.
	 *
	 * This function constructs the URL to the logs tab in the WooCommerce status page.
	 * It checks if WooCommerce is active before attempting to generate the URL.
	 *
	 * @uses admin_url() To get the base admin URL.
	 * @uses add_query_arg() To append query parameters to the URL.
	 *
	 * @return string|false The URL to the WooCommerce logs section if WooCommerce is active,
	 *                      or false if WooCommerce is not active.
	 */
	public function get_woocommerce_logs_section_url() {
		if ( ! function_exists( 'wc_get_page_permalink' ) ) {
			return false; // WooCommerce is not active.
		}

		$base_url   = admin_url( 'admin.php' );
		$query_args = array(
			'page' => 'wc-status',
			'tab'  => 'logs',
		);

		return add_query_arg( $query_args, $base_url );
	}



	/**
	 * Retrieves shipping metadata for a WooCommerce order.
	 *
	 * Fetches order metadata from the 'alsendo_connect_wc_order' meta key, with fallback
	 * to legacy '_apaczka' meta key if the primary key is empty. Returns an empty array
	 * if no valid metadata is found.
	 *
	 * @param int $order_id The WooCommerce order ID.
	 *
	 * @return array Order shipping metadata or empty array if not found
	 */
	public function get_order_meta_data( $order_id ) {
		$meta_data = array();
		$wc_order  = wc_get_order( $order_id );
		if ( $wc_order && ! is_wp_error( $wc_order ) ) {
			$meta_data = $wc_order->get_meta( 'alsendo_connect_wc_order' );
			if ( empty( $meta_data ) ) {
				$meta_data = $wc_order->get_meta( '_apaczka' );
			}
		}

		return is_array( $meta_data ) ? $meta_data : array();
	}


	/**
	 * Retrieves the Alsendo order ID from WooCommerce order metadata.
	 *
	 * Extracts the Alsendo order ID from order meta, checking both current and legacy
	 * meta key formats. Returns the ID if found in the 'alsendo_order.id' path.
	 *
	 * @param int $order_id The WooCommerce order ID.
	 *
	 * @return string The Alsendo order ID or empty string if not found
	 */
	public function get_alsendo_order_id_from_order_meta( $order_id ) {
		$alsendo_order_id = '';
		$meta_data        = array();

		$wc_order = wc_get_order( $order_id );

		if ( $wc_order && ! is_wp_error( $wc_order ) ) {
			$meta_data = $wc_order->get_meta( 'alsendo_connect_wc_order' );
			if ( empty( $meta_data ) ) {
				$meta_data = $wc_order->get_meta( '_apaczka' );
			}
			if ( ! empty( $meta_data['alsendo_order']['id'] ) ) {
				$alsendo_order_id = $meta_data['alsendo_order']['id'];
			}
		}

		return $alsendo_order_id;
	}



	/**
	 * Retrieves delivery point metadata for a given order.
	 *
	 * Attempts to fetch delivery point information from order meta data,
	 * checking both 'alsendo_connect_delivery_point' and 'apaczka_delivery_point' meta keys.
	 *
	 * @param int $order_id The WooCommerce order ID.
	 *
	 * @return array Array containing delivery point metadata with keys:
	 *               - apm_access_point_id: Access point ID
	 *               - apm_supplier: Supplier name (e.g., "POCZTA")
	 *               - apm_name: Delivery point name
	 *               - apm_foreign_access_point_id: External access point ID
	 *               - apm_street: Street address
	 *               - apm_city: City name
	 *               - apm_postal_code: Postal code
	 *               - apm_country_code: Country code (ISO 2-letter)
	 *               Returns empty array if no valid data found or order doesn't exist.
	 */
	public function get_delivery_point_meta_data( $order_id ) {

		/**
		 * array(8) {
		 * ["apm_access_point_id"]=>
		 * string(5) "20424"
		 * ["apm_supplier"]=>
		 * string(6) "POCZTA"
		 * ["apm_name"]=>
		 * string(12) "Sklep Żabka"
		 * ["apm_foreign_access_point_id"]=>
		 * string(6) "932337"
		 * ["apm_street"]=>
		 * string(40) "ul. Bitwy Warszawskiej 1920 R. 23 lok. 1"
		 * ["apm_city"]=>
		 * string(8) "Warszawa"
		 * ["apm_postal_code"]=>
		 * string(6) "02-366"
		 * ["apm_country_code"]=>
		 * string(2) "PL"
		 * }
		 */

		$meta_data = array();
		$wc_order  = wc_get_order( $order_id );
		if ( $wc_order && ! is_wp_error( $wc_order ) ) {
			$meta_data = $wc_order->get_meta( 'alsendo_connect_delivery_point' );
			if ( empty( $meta_data ) ) {
				$meta_data = $wc_order->get_meta( 'apaczka_delivery_point' );
			}
			if ( ! empty( $meta_data ) && is_array( $meta_data ) ) {
				return $meta_data;
			}
		}

		return $meta_data;
	}


	/**
	 * Parse API error response into structured chunks for better display
	 *
	 * @param string $response The full API error response.
	 * @return array Structured array with parsed components
	 */
	public function parse_api_response( $response ) {
		$result = array(
			'status'      => null,
			'url'         => null,
			'method'      => null,
			'status_code' => null,
			'status_text' => null,
			'message'     => null,
			'errors'      => array(),
			'raw_json'    => null,
			'chunks'      => array(),
		);

		// Extract basic request info using regex.
		if ( preg_match( '/Request failed: (.+?) error: `(\w+) ([^`]+)` resulted in a `(\d+) ([^`]+)` response:/', $response, $matches ) ) {
			$result['status']      = trim( $matches[1] );
			$result['method']      = $matches[2];
			$result['url']         = $matches[3];
			$result['status_code'] = (int) $matches[4];
			$result['status_text'] = $matches[5];
		}

		// Extract JSON part from the response.
		$json_start = strpos( $response, '{' );
		if ( false !== $json_start ) {
			$json_part = substr( $response, $json_start );

			// Handle truncated JSON by trying to complete it.
			if ( strpos( $json_part, '(truncated...)' ) !== false ) {
				$json_part = str_replace( '(truncated...)', '', $json_part );
				// Try to close unclosed braces/brackets.
				$json_part = rtrim( $json_part );
				if ( substr( $json_part, -1 ) === ',' ) {
					$json_part = rtrim( $json_part, ',' );
				}
			}

			$result['raw_json'] = $json_part;

			// Try to decode JSON.
			$decoded = json_decode( $json_part, true );
			if ( null !== $decoded ) {
				if ( isset( $decoded['message'] ) ) {
					$result['message'] = $decoded['message'];
				}
				if ( isset( $decoded['errors'] ) ) {
					$result['errors'] = $decoded['errors'];
				}
			}
		}

		// Create chunks for display.
		$result['chunks'] = $this->create_display_chunks( $result );

		return $result;
	}



	/**
	 * Create display-friendly chunks from parsed response
	 *
	 * @param array $parsed_response $parsedResponse.
	 * @return array
	 */
	public function create_display_chunks( $parsed_response ) {
		$chunks = array();

		if ( $parsed_response['method'] && $parsed_response['url'] ) {
			$chunks[] = array(
				'type'  => 'request',
				'label' => 'Request',
				'value' => $parsed_response['method'] . ' ' . $parsed_response['url'],
			);
		}

		if ( $parsed_response['status_code'] && $parsed_response['status_text'] ) {
			$chunks[] = array(
				'type'  => 'status',
				'label' => 'Status',
				'value' => $parsed_response['status_code'] . ' ' . $parsed_response['status_text'],
			);
		}

		if ( $parsed_response['message'] ) {
			$chunks[] = array(
				'type'  => 'message',
				'label' => 'Message',
				'value' => $parsed_response['message'],
			);
		}

		if ( ! empty( $parsed_response['errors'] ) ) {
			foreach ( $parsed_response['errors'] as $field => $error ) {
				$chunks[] = array(
					'type'  => 'error',
					'label' => 'Error: ' . $field,
					'value' => is_array( $error ) ? implode( ', ', $error ) : $error,
				);
			}
		}

		return $chunks;
	}


	/**
	 * Retrieves the main API settings type from WordPress options.
	 *
	 * @return mixed The global API type setting value, or false if option doesn't exist.
	 */
	public function get_main_settings_api() {
		return get_option( 'alsendo_connect_settings_general_global_api_type' );
	}

	/**
	 * Checks if an order has been calculated/processed.
	 *
	 * Determines if an order has calculation data by checking for 'updated' field
	 * in order meta data from either 'alsendo_connect_wc_order' or '_apaczka' meta keys.
	 *
	 * @param int $order_id The WooCommerce order ID to check.
	 *
	 * @return bool|int Returns 1 if order is calculated, false otherwise.
	 */
	public function get_is_order_calculated( $order_id ) {
		$order_calculated = false;
		$meta_data        = array();

		$wc_order = wc_get_order( $order_id );
		if ( $wc_order && ! is_wp_error( $wc_order ) ) {
			$meta_data = $wc_order->get_meta( 'alsendo_connect_wc_order' );
			if ( empty( $meta_data ) ) {
				$meta_data = $wc_order->get_meta( '_apaczka' );
			}
			if ( ! empty( $meta_data['updated'] ) ) {
				$order_calculated = 1;
			}
		}

		return $order_calculated;
	}


	/**
	 * Integration with plugin "Flexible shipping" (get shipping method linked in FS settings)
	 *
	 * @param string $instance_id $instance_id.
	 *
	 * @return string
	 */
	public function get_carrier_id_linked_to_flexible_shipping( $instance_id ) {
		$carrier_id               = '';
		$shipping_method_settings = get_option( 'woocommerce_flexible_shipping_single_' . $instance_id . '_settings' );

		if ( ! empty( $shipping_method_settings['alsendo_connect_linked_api_shipping_method'] ) ) {
			$carrier_id = $shipping_method_settings['alsendo_connect_linked_api_shipping_method'];
		}

		return $carrier_id;
	}



	/**
	 * Displays a map selection button for debugging purposes.
	 *
	 * Shows a "Select point" button when debug mode is enabled and the current
	 * shipping method has map configuration. Only displays when the shipping method
	 * is selected by the customer.
	 *
	 * @param object $shipping The shipping method object.
	 */
	public function show_map_button_debug( $shipping ) {

		if ( 'yes' !== get_option( 'alsendo_connect_settings_general_map_debug_mode' ) ) {
			return;
		}

		$selected_method             = null;
		$method_has_config           = false;
		$selected_method_instance_id = null;

		if ( function_exists( 'WC' ) && property_exists( WC(), 'session' ) ) {
			$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
			if ( is_array( $chosen_shipping_methods ) && 1 === count( $chosen_shipping_methods ) ) {
				$selected_method = reset( $chosen_shipping_methods );
			}
		}

		static $map_config = null;
		if ( null === $map_config ) {
			$map_config = $this->get_map_config();
		}

		$data = explode( ':', $selected_method );
		if ( ! empty( $data[1] ) ) {
			$selected_method_instance_id = (int) $data[1];
		}

		if ( is_array( $map_config ) && ! empty( $map_config[ $shipping->instance_id ] ) ) {
			$method_has_config = true;
		}

		if ( $method_has_config && ( $selected_method_instance_id === $shipping->instance_id ) ) {

			$allowed_html = array(
				'div'    => array(),
				'button' => array(
					'type'  => array(),
					'class' => array(),
					'id'    => array(),
				),
			);

			echo wp_kses( '<div><button id="alsendo_geowidget_show_map_classic_checkout" type="button" class="button alt alsendo_after_rate_btn">' . esc_html__( 'Select point', 'alsendo-connect' ) . '</button></div>', $allowed_html );
		}
	}
}
