<?php

namespace Ilabs\Inpost_International\Backend;

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


use Automattic\WooCommerce\StoreApi\Exceptions\RouteException;
use Exception;
use Ilabs\Inpost_International\Helpers\Helper;
use Ilabs\Inpost_International\Settings\Settings_Helper;
use WC_Order;

/**
 * Backend
 */
class Backend {

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

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

	/**
	 * Registers all hooks related to InPost locker functionality.
	 *
	 * This method sets up action and filter hooks for integrating InPost locker
	 * functionality with WooCommerce, including saving locker selection data to order meta,
	 * handling block checkout integration, adding meta boxes to the order details screen,
	 * and customizing the display of shipping method information.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function hooks() {

		add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'save_locker_point_to_order_meta' ) );

		add_action( 'woocommerce_store_api_checkout_update_order_from_request', array( $this, 'save_locker_point_to_order_meta_block_checkout' ), 10, 2 );

		add_action( 'add_meta_boxes', array( $this, 'add_inpost_meta_box_in_order_details' ), 10, 2 );

		add_filter( 'woocommerce_order_item_get_formatted_meta_data', array( $this, 'wc_order_shipping_method_logo' ), 10, 2 );
	}

	/**
	 * Save locker point to order_meta
	 *
	 * @param mixed $order_id $order_id.
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function save_locker_point_to_order_meta( $order_id ) {

		$locker_point     = null;
		$fs_inpost_linked = false;
		$fs_method_name   = '';

		$order = wc_get_order( $order_id );
		if ( ! $order || is_wp_error( $order ) ) {
			return;
		}

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

		if ( ! empty( $_POST['inpost_international_locker_id'] ) ) {
			$locker_point = sanitize_text_field( wp_unslash( $_POST['inpost_international_locker_id'] ) );
		}

		if ( $this->helper->is_flexible_shipping_activated() ) {
			$fs_instance_id = '';
			foreach ( $order->get_shipping_methods() as $shipping_method ) {
				$fs_instance_id = $shipping_method->get_instance_id();
			}
			$fs_method_name = $this->helper->get_method_linked_to_fs_by_instance_id( $fs_instance_id );
			if ( ! empty( $fs_method_name ) ) {
				$fs_inpost_linked = true;
			}
		}

		if ( $locker_point ) {
			$order->update_meta_data( 'inpost_international_locker_id', $locker_point );
			if ( ! empty( $_POST['inpost_international_locker_desc'] ) ) {
				$locker_point_desc = sanitize_text_field( wp_unslash( $_POST['inpost_international_locker_desc'] ) );
				$order->update_meta_data( 'inpost_international_locker_desc', $locker_point_desc );
			}
			$order->save();
		}

		if ( $fs_inpost_linked ) {
			// save meta in metadata to show later required metabox in order details.
			$order->update_meta_data( 'inpost_international_fs_linked', $fs_method_name );
			$order->save();
		}

		if ( ! $locker_point ) {
			if ( 0 === strpos( $shipping_method_id, 'inpost_international_automated_locker_point' ) || 0 === strpos( $fs_method_name, 'inpost_international_automated_locker_point' ) ) {

				if ( is_object( WC() ) && property_exists( WC(), 'session' ) ) {
					$locker_point = WC()->session->get( 'inpost_intl_locker' );
					if ( $locker_point ) {

						if ( $this->helper->is_flexible_shipping_activated() ) {
							foreach ( $order->get_shipping_methods() as $shipping_method ) {
								$fs_instance_id = $shipping_method->get_instance_id();
							}

							$fs_method_name = $this->helper->get_method_linked_to_fs_by_instance_id( $fs_instance_id );
							if ( ! empty( $fs_method_name ) ) {
								$fs_inpost_linked = true;
							}
						}

						if ( $fs_inpost_linked ) {
							// save meta in metadata to show later required metabox in order details.
							$order->update_meta_data( 'inpost_international_fs_linked', $fs_method_name );
							$order->save();
						}

						$order->update_meta_data( 'inpost_international_locker_id', $locker_point );
						$order->save();
					}
					// Clear session data.
					WC()->session->__unset( 'inpost_intl_locker' );
				}
			}
		}
	}

	/**
	 * Save locker point to order_meta
	 *
	 * @param @param \WC_Order $order Order object.
	 * @param \WP_REST_Request $request Full details about the request.
	 *
	 * @return void
	 * @throws RouteException
	 * @since 1.0.0
	 */
	public function save_locker_point_to_order_meta_block_checkout( $order, $request ) {

		if ( ! $order ) {
			return;
		}

        $fs_inpost_linked = false;
        $fs_method_name   = '';
        static $alert_phone_shown;

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

        if ( $this->helper->is_flexible_shipping_activated() ) {
            foreach ( $order->get_shipping_methods() as $shipping_method ) {
                $fs_instance_id = $shipping_method->get_instance_id();
            }

            $fs_method_name = $this->helper->get_method_linked_to_fs_by_instance_id( $fs_instance_id );
            if ( ! empty( $fs_method_name ) ) {
                $fs_inpost_linked = true;
            }
        }

        if ( $fs_inpost_linked ) {
            // save meta in metadata to show later required metabox in order details.
            $order->update_meta_data( 'inpost_international_fs_linked', $fs_method_name );
            $order->save();
        }

		$request_body = json_decode( $request->get_body(), true );

		if ( ! empty( $request_body['extensions']['inpost_intl']['inpost-international-locker-id'] ) ) {

			$phone_number        = ! empty( $request_body['shipping_address']['phone'] ) ? sanitize_text_field( wp_unslash( $request_body['shipping_address']['phone'] ) ) : null;
			$country_of_delivery = ! empty( $request_body['shipping_address']['country'] ) ? sanitize_text_field( wp_unslash( $request_body['shipping_address']['country'] ) ) : null;

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

				$error_message = $this->helper->get_locale_error_for_phone_number( $country_of_delivery );
				throw new \Automattic\WooCommerce\StoreApi\Exceptions\RouteException(
					'inpost_intl_phone_validation',
					wp_kses_post( $error_message ),
					400
				);
			}

			$locker_point = sanitize_text_field( $request_body['extensions']['inpost_intl']['inpost-international-locker-id'] );

			$order->update_meta_data( 'inpost_international_locker_id', $locker_point );
			if ( ! empty( $request_body['extensions']['inpost_intl']['inpost-international-locker-description'] ) ) {
				$locker_point_desc = sanitize_text_field( $request_body['extensions']['inpost_intl']['inpost-international-locker-description'] );
				$order->update_meta_data( 'inpost_international_locker_desc', $locker_point_desc );
			}
			$order->save();


		} elseif ( 0 === strpos( $shipping_method_id, 'inpost_international_automated_locker_point' ) || 0 === strpos( $fs_method_name, 'inpost_international_automated_locker_point' ) ) {

			if ( is_object( WC() ) && property_exists( WC(), 'session' ) ) {
				$locker_point = WC()->session->get( 'inpost_intl_locker' );
				if ( $locker_point ) {

					if ( $this->helper->is_flexible_shipping_activated() ) {
						foreach ( $order->get_shipping_methods() as $shipping_method ) {
							$fs_instance_id = $shipping_method->get_instance_id();
						}

						$fs_method_name = $this->helper->get_method_linked_to_fs_by_instance_id( $fs_instance_id );
						if ( ! empty( $fs_method_name ) ) {
							$fs_inpost_linked = true;
						}
					}

					if ( $fs_inpost_linked ) {
						// save meta in metadata to show later required metabox in order details.
						$order->update_meta_data( 'inpost_international_fs_linked', $fs_method_name );
						$order->save();
					}

					$order->update_meta_data( 'inpost_international_locker_id', $locker_point );
					$order->save();
				}
				// Clear session data.
				WC()->session->__unset( 'inpost_intl_locker' );
			}
		}
	}
	

	/**
	 * Adds the InPost meta box to the order details screen when applicable.
	 *
	 * This function checks if the current post is a WooCommerce order and whether it has
	 * InPost locker information associated with it. If so, it adds a meta box displaying
	 * the InPost shipping details and enqueues necessary scripts for status tracking functionality.
	 * Works with both traditional post meta storage and HPOS (High-Performance Order Storage).
	 *
	 * @since 1.0.0
	 *
	 * @param string            $post_type The post type of the current screen.
	 * @param \WP_Post|WC_Order $post      The post or order object.
	 *
	 * @return void
	 */
	public function add_inpost_meta_box_in_order_details( $post_type, $post ) {

		$order_id                    = null;
		$inpost_intl_shipping_method = null;

		if ( 'yes' === get_option( 'woocommerce_custom_orders_table_enabled' ) ) {
			// HPOS usage is enabled.
			if ( is_a( $post, 'WC_Order' ) ) {
				$order_id = $post->get_id();
			}
		} else {
			// Legacy orders DB tables are in use.
			if ( is_object( $post ) && 'shop_order' === $post->post_type ) {
				$order_id = $post->ID;
			}
		}

		if ( $order_id ) {

			$order = wc_get_order( $order_id );

			if ( ! $order || is_wp_error( $order ) || ! $order instanceof WC_Order ) {
				return;
			}

			foreach ( $order->get_shipping_methods() as $shipping_method ) {
				if ( 0 === strpos( $shipping_method->get_method_id(), 'inpost_international_' ) ) {
					$inpost_intl_shipping_method = $shipping_method->get_method_id();
				}
			}

			$fs_method_name = $order->get_meta( 'inpost_international_fs_linked' );
			if ( ! empty( $fs_method_name ) ) {
				$inpost_intl_shipping_method = $fs_method_name;
			}

			if ( ! empty( $inpost_intl_shipping_method ) ) {

				add_action( 'admin_footer', array( $this->helper, 'package_status_modal' ), 100 );

				add_action(
					'admin_enqueue_scripts',
					function () use ( $order_id ) {
						$this->enqueue_order_metabox_script( $order_id );
					},
					999
				);

				$logo      = inpost_intl_core()->get_plugin_images_url() . '/white.png';
				$logo_html = '<img style="height:40px; float:right;" src="' . esc_url( $logo ) . '"/>';

				add_meta_box(
					'inpost_international_order_metabox',
					esc_html__( 'InPost International', 'inpost-international' )
					. $logo_html,
					function () use ( $order_id, $inpost_intl_shipping_method ) {
						$this->order_metabox_content( $order_id, $inpost_intl_shipping_method );
					},
					null,
					'side',
					'high'
				);
			}
		}
	}

	/**
	 * Renders the content of the InPost order meta box.
	 *
	 * This function loads and displays the template for the InPost International
	 * order meta box on the WooCommerce order details screen. It passes the order ID
	 * and any API response data to the template for rendering shipping and tracking
	 * information.
	 *
	 * @param int   $order_id The WooCommerce order ID.
	 * @param array $api_response Optional. API response data containing shipping details.
	 *                           Default empty array.
	 *
	 * @return void Outputs the HTML content for the meta box.
	 * @throws Exception Exception.
	 * @since 1.0.0
	 */
	public function order_metabox_content(
		$order_id,
		$inpost_intl_shipping_method,
		$api_response = array()
	) {

		ob_start();

		inpost_intl_core()->locate_template(
			'order-metabox.php',
			array(
				'order_id'        => $order_id,
				'shipping_method' => $inpost_intl_shipping_method,
				'api_response'    => $api_response,
			)
		);
		$ouput = ob_get_clean();

		$allowed_html = array(
			'div'      => array(
				'class' => array(),
			),
			'p'        => array(
				'class'         => array(),
				'id'            => array(),
				'data-priority' => array(),
			),
			'label'    => array(
				'for'      => array(),
				'style'    => array(),
				'class'    => array(),
				'disabled' => array(),
			),
			'input'    => array(
				'value'       => array(),
				'type'        => array(),
				'class'       => array(),
				'id'          => array(),
				'name'        => array(),
				'disabled'    => array(),
				'placeholder' => array(),
				'step'        => array(),
				'min'         => array(),
				'max'         => array(),
			),
			'span'     => array(
				'style' => array(),
				'class' => array(),
				'title' => array(),
				'id'    => array(),
			),
			'a'        => array(
				'id'      => array(),
				'data-id' => array(),
				'href'    => array(),
			),
			'img'      => array(
				'class' => array(),
				'src'   => array(),
				'alt'   => array(),
			),
			'select'   => array(
				'name'             => array(),
				'id'               => array(),
				'class'            => array(),
				'style'            => array(),
				'data-placeholder' => array(),
				'disabled'         => array(),
			),
			'option'   => array(
				'value'    => array(),
				'selected' => array(),
			),
			'textarea' => array(
				'disabled' => array(),
				'class'    => array(),
				'rows'     => array(),
				'cols'     => array(),
				'style'    => array(),
				'id'       => array(),
				'name'     => array(),
			),
			'button'   => array(
				'id'    => array(),
				'class' => array(),
			),
		);
		echo wp_kses( $ouput, $allowed_html );
	}

	/**
	 * Enqueues scripts and styles needed for the InPost order meta box functionality.
	 *
	 * This function loads the necessary CSS and JavaScript files for the InPost International
	 * order meta box display and functionality. It also prepares and localizes data for JavaScript,
	 * including package dimensions, saved parcel templates, API tokens, and shipping information.
	 * The function handles different scenarios based on whether package data already exists.
	 *
	 * @param int $order_id The WooCommerce order ID.
	 *
	 * @return void
	 * @throws Exception Exception.
	 * @since 1.0.0
	 */
	public function enqueue_order_metabox_script( $order_id ) {
		$order = wc_get_order( $order_id );
		if ( ! $order || is_wp_error( $order ) ) {
			return;
		}

		$package_meta = $order->get_meta( 'inpost_international_package' );
		if ( ! empty( $package_meta ) ) {
			try {
				$package_data = json_decode( $package_meta, true );
				$package_data = ! empty( $package_data['api_response'] ) ? $package_data : array();
			} catch ( Exception $e ) {
				$package_data = array();
			}
		}

		if ( empty( $package_data ) ) {
			inpost_intl_core()->enqueue_geowidget_assets();
		}

		$helper = new Helper();

		$current_plugin_version = inpost_intl_core()->get_plugin_version();

		$geowidget_token = inpost_intl_core()->get_geowidget_token();

		$instance_id     = '';
		$shipping_method = '';

		foreach ( $order->get_shipping_methods() as $shipping_method ) {
			$instance_id     = $shipping_method->get_instance_id();
			$shipping_method = $shipping_method->get_method_id();
		}

		$order_metabox_css_path = inpost_intl_core()->get_plugin_dir() . 'assets/css/order-metabox.css';
		$order_metabox_css_ver  = file_exists( $order_metabox_css_path ) ? filemtime( $order_metabox_css_path ) : $current_plugin_version;
		wp_enqueue_style(
			inpost_intl_core()->get_plugin_prefix() . '_order_metabox_css',
			inpost_intl_core()->get_plugin_css_url() . '/order-metabox.css',
			array(),
			$order_metabox_css_ver
		);

		$order_dimensions = $helper->get_order_dimensions_based_on_order( $order_id );

		$sending_options        = get_option( 'inpost_international_settings_sending' );
		$saved_parcel_templates = array();
		if ( ! empty( $sending_options['templates'] ) ) {
			$saved_parcel_templates = $sending_options['templates'];
		}

		$saved_parcel_templates['default'] = $order_dimensions;

		$order_metabox_js_path = inpost_intl_core()->get_plugin_dir() . 'assets/js/order-metabox.js';
		$order_metabox_js_ver  = file_exists( $order_metabox_js_path ) ? filemtime( $order_metabox_js_path ) : $current_plugin_version;
		wp_enqueue_script(
			inpost_intl_core()->get_plugin_prefix() . '_order_metabox_js',
			inpost_intl_core()->get_plugin_js_url() . '/order-metabox.js',
			array( 'jquery' ),
			$order_metabox_js_ver,
			array( 'in_footer' => true )
		);

		wp_set_script_translations( inpost_intl_core()->get_plugin_prefix() . '_order_metabox_js', 'inpost-international', inpost_intl_core()->get_plugin_dir() . 'lang' );

		wp_localize_script(
			inpost_intl_core()->get_plugin_prefix() . '_order_metabox_js',
			'inpost_intl_order_metabox',
			array(
				'ajaxurl'          => admin_url( 'admin-ajax.php' ),
				'logo_src'         => inpost_intl_core()->get_plugin_images_url() . '/white.png',
				'templates'        => $saved_parcel_templates,
				'geowidget_token'  => $geowidget_token,
				'instance_id'      => $instance_id,
				'method'           => $shipping_method,
				// 'current_lang'     => get_locale(),
				'shipping_country' => $order->get_shipping_country(),
				'log_path'         => $helper->get_woocommerce_logs_section_url(),
				'settings_path'    => admin_url( 'admin.php?page=inpost-international-api' ),
				'nonce'            => wp_create_nonce( 'inpost_international_ajax' ),
			)
		);
	}




	/**
	 * Prepares shipment data for the InPost API request.
	 *
	 * This function builds a complete shipment data structure required by the InPost API
	 * for creating a new shipment. It gathers information from various sources including
	 * sender details, recipient information, origin and destination data, parcel dimensions,
	 * and any value-added services or references associated with the order.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID for which to prepare the shipment data.
	 *
	 * @return array A structured array containing all the necessary shipment data for the API request,
	 *               including label format, sender, recipient, origin, destination, priority,
	 *               value-added services, references, and parcel information.
	 */
	public function prepare_shipment_for_api( $order_id ) {
		$data = array();

		$data['labelFormat'] = 'PDF_URL';
		$data['shipment']    = array();

		$sender    = $this->get_sender_data();
		$recipient = $this->get_receiver_data( $order_id );

		$origin = $this->get_origin( $order_id );

		$destination = $this->get_destination_data( $order_id );

		$priority = 'STANDARD';

		$value_added_services = $this->get_added_services_data( $order_id );
		$references           = $this->get_references_data( $order_id );
		$parcel               = $this->get_parcel_data( $order_id );

		$data['shipment']['sender']             = $sender;
		$data['shipment']['recipient']          = $recipient;
		$data['shipment']['origin']             = $origin;
		$data['shipment']['destination']        = $destination;
		$data['shipment']['priority']           = $priority;
		$data['shipment']['valueAddedServices'] = $value_added_services;
		$data['shipment']['references']         = $references;
		$data['shipment']['parcel']             = $parcel;

		return $data;
	}

	/**
	 * Retrieves and formats sender data for API requests.
	 *
	 * This function collects the merchant/sender information from the plugin settings and formats
	 * it according to the requirements of the InPost API. It handles company name, personal details,
	 * contact information, and language preferences. The phone number is specially formatted to
	 * meet the API's requirements.
	 *
	 * @since 1.0.0
	 *
	 * @return array An array containing the formatted sender data including:
	 *               - companyName: Merchant's company name
	 *               - firstName: Sender's first name
	 *               - lastName: Sender's last name
	 *               - email: Sender's email address
	 *               - phone: Array with 'prefix' and 'number' elements
	 *               - languageCode: The sender's preferred language code
	 */
	public function get_sender_data() {

		$data = array();

		$sender_options = get_option( 'inpost_international_settings_merchant' );

		$data['companyName'] = ! empty( $sender_options['company'] ) ? $sender_options['company'] : '';
		$data['firstName']   = ! empty( $sender_options['name'] ) ? $sender_options['name'] : '';
		$data['lastName']    = ! empty( $sender_options['surname'] ) ? $sender_options['surname'] : '';
		$data['email']       = ! empty( $sender_options['email'] ) ? $sender_options['email'] : '';

		$shop_country = ! empty( $sender_options['country'] ) ? $sender_options['country'] : 'PL';

		// $language_code = $this->helper->get_language_code( $shop_country );
		$language_code = 'pl_PL';
		$phone_prefix  = '+48';
		if ( 'IT' === $shop_country ) {
			$language_code = 'it_IT';
			$phone_prefix  = '+39';
		}

		$sender_phone = '';
		if ( ! empty( $sender_options['phone'] ) ) {
			$phone = preg_replace( '/[-]/', '', $sender_options['phone'] );
			$phone = preg_replace( '/[ ]/', '', $phone );
			$phone = trim( $phone );
			if ( 'PL' === $shop_country ) {
				$sender_phone = preg_replace( '/^\+48|\D/', '', $phone );
			}
			if ( 'IT' === $shop_country ) {
				$sender_phone = preg_replace( '/^\+39|\D/', '', $phone );
			}
		}

		$phone           = array();
		$phone['prefix'] = $phone_prefix;
		$phone['number'] = $sender_phone;

		$data['phone']        = $phone;
		$data['languageCode'] = $language_code;

		return $data;
	}


	/**
	 * Retrieves and formats receiver data from a WooCommerce order.
	 *
	 * This function extracts customer information from a WooCommerce order and formats it
	 * according to the InPost API requirements. It processes shipping details, contact information,
	 * and applies proper formatting to the phone number based on the destination country.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID from which to extract receiver data.
	 *
	 * @return array An array containing the formatted receiver data including:
	 *               - firstName: Receiver's first name
	 *               - lastName: Receiver's last name
	 *               - companyName: Receiver's company name (if applicable)
	 *               - email: Receiver's email address
	 *               - phone: Array with 'prefix' and 'number' elements
	 *               - languageCode: The receiver's language code based on country
	 *
	 *               Returns an empty array if the order cannot be retrieved.
	 */
	public function get_receiver_data( $order_id ) {

		$order = wc_get_order( $order_id );

		$receiver_data = array();

		if ( ! $order || is_wp_error( $order ) ) {
			return $receiver_data;
		}

		$shipping_first_name = $order->get_shipping_first_name();
		$shipping_last_name  = $order->get_shipping_last_name();
		$shipping_company    = $order->get_shipping_company();
		$shipping_country    = $order->get_shipping_country();

		$billing_email  = $order->get_billing_email();
		$receiver_phone = ! empty( $order->get_shipping_phone() ) ? $order->get_shipping_phone() : null;
		if ( ! $receiver_phone ) {
			$receiver_phone = $order->get_billing_phone();
		}

		$language_code  = $this->helper->get_language_code( $shipping_country );
		$receiver_phone = $this->helper->get_phone_prefix_from_phone_number( $receiver_phone );

		$phone_prefix = ! empty( $receiver_phone['prefix'] ) ? $receiver_phone['prefix'] : '';
		$phone        = ! empty( $receiver_phone['phone'] ) ? $receiver_phone['phone'] : '';

		$receiver_data = array(
			'firstName'    => $shipping_first_name,
			'lastName'     => $shipping_last_name,
			'companyName'  => $shipping_company,
			'email'        => $billing_email,
			'phone'        => array(
				'prefix' => '+' . $phone_prefix,
				'number' => $phone,
			),
			'languageCode' => $language_code,
		);

		return $receiver_data;
	}



	/**
	 * Gets destination data for InPost International shipping based on order and method.
	 *
	 * Extracts delivery destination information including point names for locker delivery
	 * or address details for courier delivery, handling both single mode creation and
	 * automatic order processing with proper fallbacks to billing data.
	 *
	 * @param int $order_id The WooCommerce order ID.
	 * @return array Destination data array with point name or address information.
	 */
	public function get_destination_data( $order_id ) {
		$destination_data = array();

		$order = wc_get_order( $order_id );

		if ( ! $order || is_wp_error( $order ) ) {
			return $destination_data;
		}

		$helper = new Helper();
		if ( $helper->is_creating_parcel_in_single_mode() ) {

			$send_method = ! empty( $_POST['send_method'] ) ? sanitize_text_field( wp_unslash( $_POST['send_method'] ) ) : '';

			if ( 'point-to-point' === $send_method || 'address-to-point' === $send_method ) {

				$destination_data['countryCode'] = ! empty( $order->get_shipping_country() ) ? $order->get_shipping_country() : $order->get_billing_country();

				$destination_data['pointName'] = '';
				if ( ! empty( $_POST['locker_id'] ) ) {
					$destination_point = sanitize_text_field( wp_unslash( $_POST['locker_id'] ) );
					if ( preg_match( '/^[A-Za-z]{2}_/', $destination_point ) ) {
						// Remove the prefix (first two letters and "_").
						$destination_point = preg_replace( '/^[A-Za-z]{2}_/', '', $destination_point );
					}

					$destination_data['pointName'] = $destination_point;
				}
			}

			if ( 'point-to-address' === $send_method || 'address-to-address' === $send_method ) {
				$destination_data['address']                = array();
				$destination_data['address']['street']      = ! empty( $order->get_shipping_address_1() ) ? $order->get_shipping_address_1() : $order->get_billing_address_1();
				$destination_data['address']['houseNumber'] = ! empty( $order->get_shipping_address_2() ) ? $order->get_shipping_address_2() : $order->get_billing_address_2();
				$destination_data['address']['flatNumber']  = '';
				$destination_data['address']['city']        = ! empty( $order->get_shipping_city() ) ? $order->get_shipping_city() : $order->get_billing_city();
				$destination_data['address']['postalCode']  = ! empty( $order->get_shipping_city() ) ? $order->get_shipping_city() : $order->get_billing_city();
				$destination_data['address']['countryCode'] = ! empty( $order->get_shipping_country() ) ? $order->get_shipping_country() : $order->get_billing_country();
			}
		} else {

			$is_courier_method = false;

			foreach ( $order->get_items( 'shipping' ) as $item_id => $item ) {
				$shipping_method_id = $item->get_method_id();
				if ( 'inpost_international_courier' === $shipping_method_id ) {
					$is_courier_method = true;
				}
			}

			$fs_method_name = $order->get_meta( 'inpost_international_fs_linked' );
			if ( ! empty( $fs_method_name ) && 'inpost_international_courier' === $fs_method_name ) {
				$is_courier_method = true;
			}

			if ( $is_courier_method ) {

				$destination_data['address']                = array();
				$destination_data['address']['street']      = ! empty( $order->get_shipping_address_1() ) ? $order->get_shipping_address_1() : $order->get_billing_address_1();
				$destination_data['address']['houseNumber'] = ! empty( $order->get_shipping_address_2() ) ? $order->get_shipping_address_2() : $order->get_billing_address_2();
				$destination_data['address']['flatNumber']  = '';
				$destination_data['address']['city']        = ! empty( $order->get_shipping_city() ) ? $order->get_shipping_city() : $order->get_billing_city();
				$destination_data['address']['postalCode']  = ! empty( $order->get_shipping_postcode() ) ? $order->get_shipping_postcode() : $order->get_billing_postcode();
				$destination_data['address']['countryCode'] = ! empty( $order->get_shipping_country() ) ? $order->get_shipping_country() : $order->get_billing_country();

			} else {

				$destination_data['countryCode'] = ! empty( $order->get_shipping_country() ) ? $order->get_shipping_country() : $order->get_billing_country();
				$destination_point               = trim( $order->get_meta( 'inpost_international_locker_id' ) );
				if ( preg_match( '/^[A-Za-z]{2}_/', $destination_point ) ) {
					$destination_point = preg_replace( '/^[A-Za-z]{2}_/', '', $destination_point );
				}
				$destination_data['pointName'] = $destination_point;
			}
		}

		return $destination_data;
	}


	/**
	 * Retrieves and formats destination data for a shipment.
	 *
	 * This function extracts the destination information from a WooCommerce order,
	 * particularly focusing on the destination country and InPost locker point name.
	 * It handles different scenarios based on whether the parcel is being created
	 * in single mode (via admin form) or from stored order meta data.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID from which to extract destination data.
	 *
	 * @return array An array containing the formatted destination data including:
	 *               - countryCode: Two-letter ISO country code
	 *               - pointName: The InPost locker point ID (with country prefix removed if present)
	 *
	 *               Returns an empty array if the order cannot be retrieved.
	 */
	public function get_added_services_data( $order_id ) {
		$services_data                          = array();
		$services_data['insurance']['currency'] = 'EUR';

		$helper = new Helper();
		if ( $helper->is_creating_parcel_in_single_mode() ) {
			$services_data['insurance']['value'] = 0;
			if ( ! empty( $_POST['insurance_amounts'] ) ) {
				$services_data['insurance']['value'] = sanitize_text_field( wp_unslash( $_POST['insurance_amounts'] ) );
			}
		} else {
			$order = wc_get_order( $order_id );

			if ( ! $order || is_wp_error( $order ) ) {
				return $services_data;
			}

			$insurance_amount     = 0;
			$shipping_method_name = '';
			$method_instance_id   = '';

			foreach ( $order->get_shipping_methods() as $shipping_method ) {
				$method_instance_id   = $shipping_method->get_instance_id();
				$shipping_method_name = $shipping_method->get_method_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['insurance_inpost_intl'] ) ) {
				if ( 'yes' === $shipping_method_settings['insurance_inpost_intl'] ) {
					$insurance_amount = $order->get_total();
				} else {
					$insurance_amount = floatval( $shipping_method_settings['insurance_value_inpost_intl'] );
				}
			}

			$services_data['insurance']['value'] = $insurance_amount;

		}

		return $services_data;
	}


	/**
	 * Retrieves and formats reference data for a shipment.
	 *
	 * This function prepares reference information to be included with the InPost shipment,
	 * such as merchant notes and buyer notes. It handles different scenarios based on whether
	 * the parcel is being created in single mode (via admin form) or from stored order data.
	 * It can also include the customer's order note based on plugin settings.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID from which to extract reference data.
	 *
	 * @return array An array containing the formatted reference data including:
	 *               - custom: Array containing reference information such as:
	 *                 - merchant_note: Order ID or custom reference from admin form
	 *                 - buyer_note: Customer's order note (if enabled in settings)
	 *
	 *               Returns a basic structure with empty values if the order cannot be retrieved.
	 */
	public function get_references_data( $order_id ) {

		$references_data           = array();
		$references_data['custom'] = array();

		$order = wc_get_order( $order_id );
		if ( ! $order || is_wp_error( $order ) ) {
			return $references_data;
		}

		$helper = new Helper();
		if ( $helper->is_creating_parcel_in_single_mode() ) {
			$references_data['custom']['merchant_note'] = '';
			if ( ! empty( $_POST['label_reference'] ) ) {
				$references_data['custom']['merchant_note'] = sanitize_text_field( wp_unslash( $_POST['label_reference'] ) );
			}
		} else {
			$references_data['custom']['merchant_note'] = $order_id;
		}

		$plugin_order_settings = get_option( 'inpost_international_settings_sending' );
		if ( ! empty( $plugin_order_settings['copy_order_note'] ) ) {
			$order_note = $order->get_customer_note();
			if ( ! empty( $order_note ) ) {
				$references_data['custom']['buyer_note'] = $order_note;
			}
		}

		return $references_data;
	}


	/**
	 * Retrieves and formats parcel data for a shipment.
	 *
	 * This function prepares the parcel information required by the InPost API,
	 * including the parcel type, dimensions, weight, and label data. It aggregates
	 * data from several helper methods to create a complete parcel specification
	 * based on the order contents.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID from which to extract parcel data.
	 *
	 * @return array An array containing the formatted parcel data including:
	 *               - type: The parcel type (default: 'STANDARD')
	 *               - dimensions: Array containing length, width, and height values
	 *               - weight: The total weight of the parcel
	 *               - label: Label information for the parcel
	 *
	 *               Returns an empty array if the order cannot be retrieved.
	 */
	public function get_parcel_data( $order_id ) {
		$parcel_data = array();

		$order = wc_get_order( $order_id );

		if ( ! $order || is_wp_error( $order ) ) {
			return $parcel_data;
		}

		$parcel_data['type']       = 'STANDARD';
		$parcel_data['dimensions'] = $this->get_dimensions( $order_id );

		$parcel_data['weight'] = $this->get_order_weight( $order_id );
		$parcel_data['label']  = $this->get_order_label_data( $order_id );

		return $parcel_data;
	}


	/**
	 * Calculates and formats the weight data for an order's parcel.
	 *
	 * This function determines the total weight of an order by summing the weights of
	 * all non-virtual products, multiplied by their quantities. It handles different scenarios
	 * based on whether the parcel is being created in single mode (via admin form) or
	 * calculated automatically from the order items.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID for which to calculate weight.
	 *
	 * @return array An array containing the formatted weight data including:
	 *               - unit: The weight unit (always 'KG')
	 *               - amount: The total weight value (empty string if not available)
	 *
	 *               Returns a basic structure with default values if the order cannot be retrieved
	 *               or if no valid weight can be calculated.
	 */
	public function get_order_weight( $order_id ) {
		$weight_data         = array();
		$weight              = 0;
		$weight_data['unit'] = 'KG';

		$helper = new Helper();
		if ( $helper->is_creating_parcel_in_single_mode() ) {
			$weight_data['amount'] = '';
			if ( ! empty( $_POST['parcel']['weight'] ) ) {
				$weight_data['amount'] = sanitize_text_field( wp_unslash( $_POST['parcel']['weight'] ) );
			}
		} else {
			$order = wc_get_order( $order_id );

			if ( ! $order || is_wp_error( $order ) ) {
				return $weight_data;
			}

			if ( count( $order->get_items() ) > 0 ) {
				foreach ( $order->get_items() as $item ) {
					if ( isset( $item['product_id'] ) && $item['product_id'] > 0 ) {
						if ( is_object( $item ) ) {
							$_product = $item->get_product();
							if ( ! $_product->is_virtual() ) {
								$weight += (float) $_product->get_weight() * (int) $item['qty'];
							}
						}
					}
				}
			}

			$weight_data['amount'] = $weight;
		}

		return $weight_data;
	}


	/**
	 * Retrieves and formats the dimensions data for an order's parcel.
	 *
	 * This function determines the dimensions (length, width, height) of a parcel
	 * either from form input in admin single mode or by calculating based on the
	 * order's products. All dimensions are standardized to centimeters.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID for which to determine dimensions.
	 *
	 * @return array An array containing the formatted dimensions data including:
	 *               - length: The parcel length in centimeters
	 *               - width: The parcel width in centimeters
	 *               - height: The parcel height in centimeters
	 *               - unit: The dimension unit (always 'CM')
	 *
	 *               Returns a basic structure with empty values if the order cannot be retrieved
	 *               or if no valid dimensions can be determined.
	 */
	public function get_dimensions( $order_id ) {

		$dimensions = array();

		$helper = new Helper();
		if ( $helper->is_creating_parcel_in_single_mode() ) {
            // create shipment from Order edit page.
			$dimensions['length'] = ! empty( $_POST['parcel']['length'] ) ? sanitize_text_field( wp_unslash( $_POST['parcel']['length'] ) ) : '';
			$dimensions['width']  = ! empty( $_POST['parcel']['width'] ) ? sanitize_text_field( wp_unslash( $_POST['parcel']['width'] ) ) : '';
			$dimensions['height'] = ! empty( $_POST['parcel']['height'] ) ? sanitize_text_field( wp_unslash( $_POST['parcel']['height'] ) ) : '';
		} else {

            // Bulk shipment creating mode.

			$order = wc_get_order( $order_id );

			if ( ! $order || is_wp_error( $order ) ) {
				return $dimensions;
			}

			$order_dimensions     = $helper->get_order_dimensions_based_on_order( $order_id );

			$dimensions['length'] = $order_dimensions['length'];
			$dimensions['width']  = $order_dimensions['width'];
			$dimensions['height'] = $order_dimensions['height'];
		}

		$dimensions['unit'] = 'CM';

		return $dimensions;
	}


	/**
	 * Retrieves and formats the label data for an order's parcel.
	 *
	 * This function prepares the label information for the InPost shipment label,
	 * including any comments or references to be printed on the label. It handles
	 * different scenarios based on whether the parcel is being created in single mode
	 * (via admin form) or from stored order data.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID for which to prepare label data.
	 *
	 * @return array An array containing the formatted label data including:
	 *               - comment: Text to be printed on the label (order reference or custom text)
	 *
	 *               Returns a basic structure with empty values if the order cannot be retrieved
	 *               or if no valid label data can be determined.
	 */
	public function get_order_label_data( $order_id ) {

		$data = array();
		// $data['barcode'] = $order_id;.
		// $data['barcode'] = '';.
		$data['comment'] = '';

		$helper = new Helper();
		if ( $helper->is_creating_parcel_in_single_mode() ) {
			if ( ! empty( $_POST['label_reference'] ) ) {
				$data['comment'] = sanitize_text_field( wp_unslash( $_POST['label_reference'] ) );
			}
		} else {
			$order = wc_get_order( $order_id );
			if ( ! $order || is_wp_error( $order ) ) {
				return $data;
			}
			$data['comment'] = 'Order number in merchant store is # ' . $order_id;

		}

		return $data;
	}



	/**
	 * Determines and formats the origin data for a shipment.
	 *
	 * This function prepares the origin information for an InPost shipment, which includes
	 * the country code and available shipping methods. It handles different scenarios based on
	 * whether the parcel is being created in single mode (via admin form) or using default
	 * settings from the plugin configuration. For address-to-point shipments, it retrieves
	 * the selected dispatch point details.
	 *
	 * @since 1.0.0
	 *
	 * @param int $order_id The WooCommerce order ID.
	 *
	 * @return array An array containing the formatted origin data including:
	 *               - countryCode: The origin country code (typically 'PL' for Poland)
	 *               - shippingMethods: Array of available shipping methods (APM, PUDO, HUB)
	 *
	 *               For address-to-point shipments, returns the selected dispatch point details.
	 *               Returns an empty array if no valid origin data can be determined.
	 */
	public function get_origin( $order_id ) {

		$origin = array();

		$country_code   = 'PL';
		$sender_options = get_option( 'inpost_international_settings_merchant' );
		if ( ! empty( $sender_options['country'] ) ) {
			$country_code = $sender_options['country'];
		}

		$shipping_methods = array(
			'APM',
			'PUDO',
			'HUB',
		);

		if ( 'IT' === $country_code ) {
			$shipping_methods = array(
				'APM',
				'PUDO',
			);
		}

		$helper = new Helper();

		if ( $helper->is_creating_parcel_in_single_mode() ) {

			if ( ! empty( $_POST['send_method'] ) ) {
				$sending_method = sanitize_text_field( wp_unslash( $_POST['send_method'] ) );
				if ( 'address-to-point' === $sending_method || 'address-to-address' === $sending_method ) {
					$origin = $this->get_selected_dispatch_point();

				} else {
					$origin = array(
						'countryCode'     => $country_code,
						'shippingMethods' => $shipping_methods,
					);
				}
			}
		} else {

			$order = wc_get_order( $order_id );

			if ( ! $order || is_wp_error( $order ) ) {
				return $origin;
			}

			$inpost_ship_method = '';

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

			$fs_method_name = $order->get_meta( 'inpost_international_fs_linked' );
			if ( ! empty( $fs_method_name ) ) {
				$inpost_ship_method = $fs_method_name;
			}

			$plugin_order_settings = get_option( 'inpost_international_settings_sending' );
			if ( ! empty( $plugin_order_settings['default_send_method'] ) ) {
				$sending_method = $helper->validate_send_method_option( $inpost_ship_method, $plugin_order_settings['default_send_method'] );

				if ( 'address-to-point' === $sending_method || 'address-to-address' === $sending_method ) {
					$origin = $this->get_selected_dispatch_point();
				} else {
					$origin = array(
						'countryCode'     => $country_code,
						'shippingMethods' => $shipping_methods,
					);

				}
			}
		}

		return $origin;
	}


	/**
	 * Determines and formats the origin data for a shipment.
	 *
	 * This function prepares the origin information for an InPost shipment, which includes
	 * the country code and available shipping methods. It handles different scenarios based on
	 * whether the parcel is being created in single mode (via admin form) or using default
	 * settings from the plugin configuration. For address-to-point shipments, it retrieves
	 * the selected dispatch point details.
	 *
	 * @since 1.0.0
	 *
	 * @return array An array containing the formatted origin data including:
	 *               - countryCode: The origin country code (typically 'PL' for Poland)
	 *               - shippingMethods: Array of available shipping methods (APM, PUDO, HUB)
	 *
	 *               For address-to-point shipments, returns the selected dispatch point details.
	 *               Returns an empty array if no valid origin data can be determined.
	 */
	public function get_selected_dispatch_point() {

		$origin = array();

		$country_code   = 'PL';
		$sender_options = get_option( 'inpost_international_settings_merchant' );
		if ( ! empty( $sender_options['country'] ) ) {
			$country_code = $sender_options['country'];
		}

		$dispatch_options = get_option( 'inpost_international_settings_dispatch_points' );
		if ( ! empty( $dispatch_options['points'] ) && is_array( $dispatch_options['points'] ) ) {
			$house_number = '';
			$flat_number  = '';
			$street       = '';
			$city         = '';
			$postal_code  = '';

			if ( 1 === count( $dispatch_options['points'] ) ) {
				$single_dispatch_point = reset( $dispatch_options['points'] );
				$house_number          = ! empty( $single_dispatch_point['building_number'] ) ? $single_dispatch_point['building_number'] : '';
				$flat_number           = ! empty( $single_dispatch_point['flat_number'] ) ? $single_dispatch_point['flat_number'] : '';
				$street                = ! empty( $single_dispatch_point['street'] ) ? $single_dispatch_point['street'] : '';
				$city                  = ! empty( $single_dispatch_point['city'] ) ? $single_dispatch_point['city'] : '';
				$postal_code           = ! empty( $single_dispatch_point['postal_code'] ) ? $single_dispatch_point['postal_code'] : '';
			} else {

				foreach ( $dispatch_options['points'] as $point ) {
					if ( isset( $point['selected'] ) ) {
						$house_number = ! empty( $point['building_number'] ) ? $point['building_number'] : '';
						$flat_number  = ! empty( $point['flat_number'] ) ? $point['flat_number'] : '';
						$street       = ! empty( $point['street'] ) ? $point['street'] : '';
						$city         = ! empty( $point['city'] ) ? $point['city'] : '';
						$postal_code  = ! empty( $point['postal_code'] ) ? $point['postal_code'] : '';
						break;
					}
				}
			}

			$origin = array(
				'address' => array(
					'houseNumber' => $house_number,
					'flatNumber'  => $flat_number,
					'street'      => $street,
					'city'        => $city,
					'postalCode'  => $postal_code,
					'countryCode' => $country_code,
				),
			);
		}

		return $origin;
	}



	/**
	 * Customizes the display of InPost shipping method logos in order details.
	 *
	 * This function modifies the formatted meta data for shipping line items to display
	 * InPost logos properly. It handles both default logos (white, yellow, black) and
	 * custom logos configured in the shipping method settings. The function replaces
	 * the text representation with an appropriate image.
	 *
	 * @since 1.0.0
	 *
	 * @param array                   $formatted_meta          The array of formatted meta data for the order item.
	 * @param \WC_Order_Item_Shipping $wc_order_item_shipping_obj The shipping line item object.
	 *
	 * @return array The modified array of formatted meta data with proper logo display.
	 */
	public function wc_order_shipping_method_logo( $formatted_meta, $wc_order_item_shipping_obj ) {

		$default_logos = array( 'white', 'yellow', 'black', 'mondial' );
		$display_value = '';
		$custom_logo   = false;

		if ( is_array( $formatted_meta ) ) {
			foreach ( $formatted_meta as $key => $obj ) {
				if ( 'inpost_order_sm_logo' === $obj->key || 'logo_inpost' === $obj->key || 'logo' === $obj->key || 'by_inpost' === $obj->key ) {

					if ( in_array( $obj->value, $default_logos, true ) ) {
						$logo_src           = inpost_intl_core()->get_plugin_images_url() . '/' . $obj->value . '.png';
						$display_value      = '<p><img style="width: 60px;height:auto;" src="' . esc_url( $logo_src ) . '"></p>';
						$obj->display_key   = 'By';
						$obj->display_value = $display_value;
					} elseif ( 'custom' === $obj->value ) {
						$custom_logo = true;
					}
				}
			}
		}

		if ( $custom_logo ) {
			$sm_name        = $wc_order_item_shipping_obj->get_method_id();
			$sm_instance_id = $wc_order_item_shipping_obj->get_instance_id();

			$shipping_method_settings_name = 'woocommerce_' . $sm_name . '_' . $sm_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'];

				if ( ! empty( $img_src ) ) {
					foreach ( $formatted_meta as $key => $obj ) {
						if ( 'custom' === $obj->value ) {
							$display_value      = '<p><img style="width: 60px;height:auto;" src="' . esc_url( $img_src ) . '"></p>';
							$obj->display_key   = 'By';
							$obj->display_value = $display_value;
						}
					}
				}
			}
		}
		return $formatted_meta;
	}
}
