<?php

namespace Inspire_Labs\Alsendo_Connect;

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

use Automattic\WooCommerce\Blocks\Package as NewPackage;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields as NewCheckoutFields;

/**
 * Integrations
 */
class Integrations {


	/**
	 * @var Helper
	 */
	private $helper;

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

	/**
	 * Registers hooks for the plugin functionality.
	 *
	 * @return void
	 *
	 * @since 1.0.2
	 * @access public
	 */
	public function hooks() {

		add_filter( 'wc_subscriptions_object_data', array( $this, 'woo_subscriptions_integration' ), 10, 3 );
		add_action( 'wps_sfw_renewal_order_creation', array( $this, 'sfw_subscriptions_integration' ), 10, 2 );
		add_filter( 'woocommerce_checkout_fields', array( $this, 'ecolet_customize_checkout_fields' ) );
		add_action( 'woocommerce_checkout_create_order', array( $this, 'ecolet_store_checkout_address_details' ), 10, 2 );
		add_action( 'woocommerce_store_api_checkout_update_order_meta', array( $this, 'ecolet_glue_address_lines_for_store_api_order' ), 20 );
		add_action( 'woocommerce_after_checkout_validation', array( $this, 'ecolet_checkout_additional_required_fields_notice' ), 10, 2 );
		add_action( 'woocommerce_blocks_validate_location_address_fields', array( $this, 'ecolet_blocks_address_fields_validation_notice' ), 10, 3 );

		add_action( 'init', array( $this, 'register_additional_checkout_fields' ), 20 );
		add_action( 'woocommerce_blocks_loaded', array( $this, 'register_additional_checkout_fields' ), 20 );
		add_action( 'woocommerce_blocks_checkout_enqueue_data', array( $this, 'override_blocks_address_fields_locations' ), 1 );

		add_filter( 'woocommerce_get_country_locale', array( $this, 'ecolet_hide_address_2_in_blocks_locale' ), 20 );
		add_filter( 'woocommerce_blocks_get_country_locale', array( $this, 'ecolet_hide_address_2_in_blocks_locale' ), 20 );

	}

	/**
	 * Adds an additional user-facing notice when Ecolet required address fields are missing (classic checkout).
	 *
	 * @param array     $data   Posted checkout data.
	 * @param \WP_Error $errors Validation errors.
	 *
	 * @return void
	 */
	public function ecolet_checkout_additional_required_fields_notice( $data, $errors ) {
		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}
		if ( 'ecolet' !== alsendo_connect()->get_main_settings_api() ) {
			return;
		}
		if ( ! $errors || ! is_wp_error( $errors ) || 0 === count( $errors->get_error_codes() ) ) {
			return;
		}
		if ( empty( $data ) || ! is_array( $data ) ) {
			return;
		}

		$field_keys = array(
			'alsendo_connect_ecolet_street_number',
			'alsendo_connect_ecolet_house_block',
			'alsendo_connect_ecolet_house_entrance',
			'alsendo_connect_ecolet_floor',
			'alsendo_connect_ecolet_flat',
		);

		$sections = array( 'billing' );
		if ( ! empty( $data['ship_to_different_address'] ) ) {
			$sections[] = 'shipping';
		}

		$missing = false;
		foreach ( $sections as $section ) {
			foreach ( $field_keys as $key ) {
				$post_key = $section . '_' . $key;
				if ( ! isset( $data[ $post_key ] ) || '' === trim( (string) $data[ $post_key ] ) ) {
					$missing = true;
					break 2;
				}
			}
		}

		if ( ! $missing ) {
			return;
		}

		wc_add_notice(
			wp_kses_post(
				esc_html__( 'All address fields are mandatory and must be completed.', 'alsendo-connect' ) .
				'<br>' .
				esc_html__( 'If certain details such as building, entrance, floor, or apartment are not applicable, please enter “-” (dash) or “.” (dot) instead of leaving the fields empty or using 0.', 'alsendo-connect' )
			),
			'error'
		);
	}

	

	/**
	 * Adds an additional user-facing validation message for Blocks checkout when Ecolet required address fields are missing.
	 *
	 * Hook: woocommerce_blocks_validate_location_address_fields
	 *
	 * @param \WP_Error $errors  Validation errors to append to.
	 * @param mixed    $fields  Field values for the address location.
	 * @param string   $group   Group being validated (billing|shipping).
	 *
	 * @return void
	 */
	public function ecolet_blocks_address_fields_validation_notice( $errors, $fields, $group ) {
		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}
		if ( 'ecolet' !== alsendo_connect()->get_main_settings_api() ) {
			return;
		}
		if ( ! $errors || ! is_wp_error( $errors ) ) {
			return;
		}
		if ( empty( $fields ) || ! is_array( $fields ) ) {
			return;
		}

		$field_ids = array(
			'alsendo-connect/ecolet-street-number',
			'alsendo-connect/ecolet-house-block',
			'alsendo-connect/ecolet-house-entrance',
			'alsendo-connect/ecolet-floor',
			'alsendo-connect/ecolet-flat',
		);

		$missing = false;
		foreach ( $field_ids as $field_id ) {
			$value = isset( $fields[ $field_id ] ) ? (string) $fields[ $field_id ] : '';
			$value = trim( $value );
			// Treat "0" as missing too (user guidance expects "-" when not applicable).
			if ( '' === $value || '0' === $value ) {
				$missing = true;
				break;
			}
		}

		if ( ! $missing ) {
			return;
		}

		$errors->add(
			'alsendo_connect_ecolet_required_fields_notice',
			wp_kses_post(
				esc_html__( 'All address fields are mandatory and must be completed.', 'alsendo-connect' ) .
				'<br><br>' .
				esc_html__( 'If certain details such as building, entrance, floor, or apartment are not applicable, please enter “-” (dash) or “.” (dot) instead of leaving the fields empty or using 0.', 'alsendo-connect' )
			),
			array(
				'location' => 'address',
				'group'    => $group,
			)
		);
	}

	/**
	 * Override Blocks addressFieldsLocations to control additional field ordering.
	 *
	 * WooCommerce Blocks stores field ordering in wcSettings.addressFieldsLocations.
	 * The underlying registry ignores duplicate keys, so adding this early allows us
	 * to control order before core data is registered later in the hook chain.
	 *
	 * @return void
	 */
	public function override_blocks_address_fields_locations() {
		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}

		if ( 'ecolet' !== alsendo_connect()->get_main_settings_api() ) {
			return;
		}

		if ( ! class_exists( '\Automattic\WooCommerce\Blocks\Package' ) ) {
			return;
		}

		try {
			$container = \Automattic\WooCommerce\Blocks\Package::container();

			if ( ! $container || ! class_exists( '\Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields' ) ) {
				return;
			}

			if ( ! class_exists( '\Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry' ) ) {
				return;
			}

			$checkout_fields = $container->get( \Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields::class );
			if ( ! $checkout_fields || ! method_exists( $checkout_fields, 'get_address_fields_keys' ) ) {
				return;
			}

			$address_keys = $checkout_fields->get_address_fields_keys();
			if ( ! is_array( $address_keys ) || empty( $address_keys ) ) {
				return;
			}

			$field_ids = array(
				'alsendo-connect/ecolet-street-number',
				'alsendo-connect/ecolet-house-block',
				'alsendo-connect/ecolet-house-entrance',
				'alsendo-connect/ecolet-floor',
				'alsendo-connect/ecolet-flat',
			);

			foreach ( $field_ids as $field_id ) {
				$pos = array_search( $field_id, $address_keys, true );
				if ( false !== $pos ) {
					unset( $address_keys[ $pos ] );
				}
			}
			$address_keys = array_values( $address_keys );

			$insert_after = 'address_1';
			$after_pos    = array_search( $insert_after, $address_keys, true );
			if ( false === $after_pos ) {
				$address_keys = array_merge( $address_keys, $field_ids );
			} else {
				array_splice( $address_keys, $after_pos + 1, 0, $field_ids );
			}

			$locations = array(
				'address' => $address_keys,
				'contact' => method_exists( $checkout_fields, 'get_contact_fields_keys' ) ? $checkout_fields->get_contact_fields_keys() : array(),
				'order'   => method_exists( $checkout_fields, 'get_order_fields_keys' ) ? $checkout_fields->get_order_fields_keys() : array(),
			);

			$registry = $container->get( \Automattic\WooCommerce\Blocks\Assets\AssetDataRegistry::class );
			if ( $registry && method_exists( $registry, 'add' ) ) {
				$registry->add( 'addressFieldsLocations', $locations );
			}
		} catch ( \Throwable $e ) {
			// Fail silently - checkout should remain functional even if Blocks internals change.
			error_log( $e->getMessage() );
		}
	}


	public function register_additional_checkout_fields() {
		static $already_registered = false;
		if ( $already_registered ) {
			return;
		}

		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}

		// Register only for Ecolet integration.
		if ( 'ecolet' !== alsendo_connect()->get_main_settings_api() ) {
			return;
		}

		// If called too early (e.g. on init), defer to the Blocks lifecycle hook.
		if ( 0 === did_action( 'woocommerce_blocks_loaded' ) ) {
			add_action( 'woocommerce_blocks_loaded', array( $this, __FUNCTION__ ), 20 );
			return;
		}

		try {
			$this->ecolet_register_additional_checkout_fields_for_blocks();
			$already_registered = true;
		} catch ( \Throwable $e ) {
			error_log( $e->getMessage() );
		}
	}

	/**
	 * Register additional checkout fields for Block-based checkout.
	 *
	 * Uses WooCommerce Blocks CheckoutFields service when available to support ordering via priority.
	 *
	 * @return void
	 */
	public function ecolet_register_additional_checkout_fields_for_blocks() {
		static $already_registered = false;
		if ( $already_registered ) {
			return;
		}

		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}

		// Register only for Ecolet integration.
		if ( 'ecolet' !== alsendo_connect()->get_main_settings_api() ) {
			return;
		}

		// Ensure Blocks package is fully loaded before trying to use its DI container.
		if ( 0 === did_action( 'woocommerce_blocks_loaded' ) ) {
			return;
		}

		$dash_placeholder = esc_html__( 'Put a dash if not applicable', 'alsendo-connect' );

		$fields = array(
			array(
				'id'         => 'alsendo-connect/ecolet-street-number',
				'label'      => esc_html__( 'Street number', 'alsendo-connect' ),
				'location'   => 'address',
				'type'       => 'text',
				'required'   => true,
				'priority'   => 55,
			),
			array(
				'id'         => 'alsendo-connect/ecolet-house-block',
				'label'      => esc_html__( 'House block', 'alsendo-connect' ),
				'location'   => 'address',
				'type'       => 'text',
				'required'   => true,
				'priority'   => 56,
				'attributes' => array(
					'title'      => $dash_placeholder,
					'aria-label' => esc_html__( 'House block', 'alsendo-connect' ) . '. ' . $dash_placeholder,
				),
			),
			array(
				'id'         => 'alsendo-connect/ecolet-house-entrance',
				'label'      => esc_html__( 'House entrance', 'alsendo-connect' ),
				'location'   => 'address',
				'type'       => 'text',
				'required'   => true,
				'priority'   => 57,
				'attributes' => array(
					'title'      => $dash_placeholder,
					'aria-label' => esc_html__( 'House entrance', 'alsendo-connect' ) . '. ' . $dash_placeholder,
				),
			),
			array(
				'id'         => 'alsendo-connect/ecolet-floor',
				'label'      => esc_html__( 'Floor', 'alsendo-connect' ),
				'location'   => 'address',
				'type'       => 'text',
				'required'   => true,
				'priority'   => 58,
				'attributes' => array(
					'title'      => $dash_placeholder,
					'aria-label' => esc_html__( 'Floor', 'alsendo-connect' ) . '. ' . $dash_placeholder,
				),
			),
			array(
				'id'         => 'alsendo-connect/ecolet-flat',
				'label'      => esc_html__( 'Flat', 'alsendo-connect' ),
				'location'   => 'address',
				'type'       => 'text',
				'required'   => true,
				'priority'   => 59,
				'attributes' => array(
					'title'      => $dash_placeholder,
					'aria-label' => esc_html__( 'Flat', 'alsendo-connect' ) . '. ' . $dash_placeholder,
				),
			),
		);

		// Prefer Blocks CheckoutFields service if available (supports priority ordering).
		if ( class_exists( '\Automattic\WooCommerce\Blocks\Package' ) && class_exists( '\Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields' ) ) {
			$container = \Automattic\WooCommerce\Blocks\Package::container();
			$service   = $container->get( \Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields::class );
			if ( $service && method_exists( $service, 'register_checkout_field' ) ) {
				foreach ( $fields as $field ) {
					$service->register_checkout_field( $field );
				}
				$already_registered = true;
				return;
			}
		}

		// Fallback to public function if available (may not support priority on older versions).
		if ( function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
			foreach ( $fields as $field ) {
				woocommerce_register_additional_checkout_field( $field );
			}
			$already_registered = true;
		}
	}

	/**
	 * Hide address_2 field in Blocks address form via locale config.
	 *
	 * @param array $locale Country locale data.
	 * @return array
	 */
	public function ecolet_hide_address_2_in_blocks_locale( $locale ) {
		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return $locale;
		}

		if ( 'ecolet' !== alsendo_connect()->get_main_settings_api() ) {
			return $locale;
		}

		if ( ! is_array( $locale ) ) {
			return $locale;
		}

		foreach ( $locale as $country_code => $country_locale ) {
			if ( ! isset( $locale[ $country_code ] ) || ! is_array( $locale[ $country_code ] ) ) {
				continue;
			}
			if ( ! isset( $locale[ $country_code ]['address_2'] ) || ! is_array( $locale[ $country_code ]['address_2'] ) ) {
				$locale[ $country_code ]['address_2'] = array();
			}
			$locale[ $country_code ]['address_2']['hidden'] = true;
		}

		return $locale;
	}

	/**
	 * Adds Ecolet-specific checkout fields and removes default address line 2 fields.
	 *
	 * @param array $fields Checkout fields.
	 * @return array
	 */
	public function ecolet_customize_checkout_fields( $fields ) {
		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return $fields;
		}

		$extra_fields = array(
			'alsendo_connect_ecolet_street_number' => array(
				'label'       => esc_html__( 'Street number', 'alsendo-connect' ),
				'placeholder' => '',
			),
			'alsendo_connect_ecolet_house_block'   => array(
				'label'       => esc_html__( 'House block', 'alsendo-connect' ),
				'placeholder' => esc_html__( 'Put a dash if not applicable', 'alsendo-connect' ),
			),
			'alsendo_connect_ecolet_house_entrance' => array(
				'label'       => esc_html__( 'House entrance', 'alsendo-connect' ),
				'placeholder' => esc_html__( 'Put a dash if not applicable', 'alsendo-connect' ),
			),
			'alsendo_connect_ecolet_floor'          => array(
				'label'       => esc_html__( 'Floor', 'alsendo-connect' ),
				'placeholder' => esc_html__( 'Put a dash if not applicable', 'alsendo-connect' ),
			),
			'alsendo_connect_ecolet_flat'           => array(
				'label'       => esc_html__( 'Flat', 'alsendo-connect' ),
				'placeholder' => '',
			),
		);

		$sections = array( 'billing', 'shipping' );
		foreach ( $sections as $section ) {
			if ( empty( $fields[ $section ] ) || ! is_array( $fields[ $section ] ) ) {
				continue;
			}

			unset( $fields[ $section ][ $section . '_address_2' ] );

			$priority = 56;
			foreach ( $extra_fields as $field_key => $config ) {
				$fields[ $section ][ $section . '_' . $field_key ] = array(
					'label'       => $config['label'],
					'required'    => true,
					'class'       => array( 'form-row-wide' ),
					'clear'       => true,
					'type'        => 'text',
					'priority'    => $priority,
					'placeholder' => $config['placeholder'],
				);
				$priority++;
			}
		}

		return $fields;
	}

	/**
	 * Saves Ecolet checkout additional fields as separate meta and address_2.
	 *
	 * @param WC_Order $order Order object.
	 * @param array    $data Posted checkout data.
	 * @return void
	 */
	public function ecolet_store_checkout_address_details( $order, $data ) {
		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}

		$street_number_key = 'alsendo_connect_ecolet_street_number';
		$field_keys = array(
			$street_number_key,
			'alsendo_connect_ecolet_house_block',
			'alsendo_connect_ecolet_house_entrance',
			'alsendo_connect_ecolet_floor',
			'alsendo_connect_ecolet_flat',
		);

		$address_data = array(
			'billing'  => array(),
			'shipping' => array(),
		);

		foreach ( $address_data as $section => $_values ) {
			foreach ( $field_keys as $field_key ) {
				$posted_key = $section . '_' . $field_key;
				$value      = '';
				if ( isset( $data[ $posted_key ] ) ) {
					$value = sanitize_text_field( wp_unslash( $data[ $posted_key ] ) );
				}
				$address_data[ $section ][ $field_key ] = $value;
				$order->update_meta_data( $posted_key, $value );
			}
		}

		foreach ( $field_keys as $field_key ) {
			$common_value = $address_data['billing'][ $field_key ];
			if ( '' === $common_value && '' !== $address_data['shipping'][ $field_key ] ) {
				$common_value = $address_data['shipping'][ $field_key ];
			}
			$order->update_meta_data( $field_key, $common_value );
		}

		$billing_line_1 = implode(
			', ',
			array_filter(
				array(
					$order->get_billing_address_1(),
					$address_data['billing'][ $street_number_key ] ?? '',
				)
			)
		);

		$line_2_field_labels = array(
			'alsendo_connect_ecolet_house_block'    => esc_html__( 'block', 'alsendo-connect' ),
			'alsendo_connect_ecolet_house_entrance' => esc_html__( 'entrance', 'alsendo-connect' ),
			'alsendo_connect_ecolet_floor'          => esc_html__( 'floor', 'alsendo-connect' ),
			'alsendo_connect_ecolet_flat'           => esc_html__( 'flat', 'alsendo-connect' ),
		);

		$billing_line_2_parts = array();
		foreach ( $line_2_field_labels as $field_key => $label ) {
			$value = $address_data['billing'][ $field_key ] ?? '';
			if ( '' !== trim( (string) $value ) ) {
				$billing_line_2_parts[] = trim( $label . ' ' . $value );
			}
		}
		$billing_line_2 = implode( ', ', $billing_line_2_parts );

		$shipping_data  = $address_data['shipping'];
		if ( empty( array_filter( $shipping_data ) ) ) {
			$shipping_data = $address_data['billing'];
		}
		$base_shipping_line_1 = $order->get_shipping_address_1();
		if ( '' === trim( (string) $base_shipping_line_1 ) ) {
			$base_shipping_line_1 = $order->get_billing_address_1();
		}
		$shipping_line_1 = implode(
			', ',
			array_filter(
				array(
					$base_shipping_line_1,
					$shipping_data[ $street_number_key ] ?? '',
				)
			)
		);
		$shipping_line_2_parts = array();
		foreach ( $line_2_field_labels as $field_key => $label ) {
			$value = $shipping_data[ $field_key ] ?? '';
			if ( '' !== trim( (string) $value ) ) {
				$shipping_line_2_parts[] = trim( $label . ' ' . $value );
			}
		}
		$shipping_line_2 = implode( ', ', $shipping_line_2_parts );

		$order->set_billing_address_1( $billing_line_1 );
		$order->set_billing_address_2( $billing_line_2 );
		$order->set_shipping_address_1( $shipping_line_1 );
		$order->set_shipping_address_2( $shipping_line_2 );
	}

	/**
	 * Saves Ecolet checkout additional fields from Blocks Checkout (Store API request).
	 *
	 * @param WC_Order|null   $order   Order object.
	 * @param WP_REST_Request $request Store API request.
	 * @return void
	 */
	public function ecolet_store_api_checkout_address_details( $order, $request ) {
		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}

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

		$request_body = json_decode( $request->get_body(), true );
		$raw_payload  = $request_body['extensions']['alsendo_connect']['ecolet-checkout-fields'] ?? '';
		if ( empty( $raw_payload ) || ! is_string( $raw_payload ) ) {
			return;
		}

		$payload = json_decode( $raw_payload, true );
		if ( empty( $payload ) || ! is_array( $payload ) ) {
			return;
		}

		$street_number_key = 'alsendo_connect_ecolet_street_number';
		$field_keys        = array(
			$street_number_key,
			'alsendo_connect_ecolet_house_block',
			'alsendo_connect_ecolet_house_entrance',
			'alsendo_connect_ecolet_floor',
			'alsendo_connect_ecolet_flat',
		);

		$address_data = array(
			'billing'  => array(),
			'shipping' => array(),
		);

		foreach ( $address_data as $section => $_values ) {
			$section_payload = $payload[ $section ] ?? array();
			foreach ( $field_keys as $field_key ) {
				$value = '';
				if ( is_array( $section_payload ) && isset( $section_payload[ $field_key ] ) ) {
					$value = sanitize_text_field( (string) $section_payload[ $field_key ] );
				}

				$address_data[ $section ][ $field_key ] = $value;

				$posted_key = $section . '_' . $field_key;
				$order->update_meta_data( $posted_key, $value );
			}
		}

		foreach ( $field_keys as $field_key ) {
			$common_value = $address_data['billing'][ $field_key ];
			if ( '' === $common_value && '' !== $address_data['shipping'][ $field_key ] ) {
				$common_value = $address_data['shipping'][ $field_key ];
			}
			$order->update_meta_data( $field_key, $common_value );
		}

		$billing_line_1 = implode(
			', ',
			array_filter(
				array(
					$order->get_billing_address_1(),
					$address_data['billing'][ $street_number_key ] ?? '',
				)
			)
		);

		$line_2_field_labels = array(
			'alsendo_connect_ecolet_house_block'    => esc_html__( 'block', 'alsendo-connect' ),
			'alsendo_connect_ecolet_house_entrance' => esc_html__( 'entrance', 'alsendo-connect' ),
			'alsendo_connect_ecolet_floor'          => esc_html__( 'floor', 'alsendo-connect' ),
			'alsendo_connect_ecolet_flat'           => esc_html__( 'flat', 'alsendo-connect' ),
		);

		$billing_line_2_parts = array();
		foreach ( $line_2_field_labels as $field_key => $label ) {
			$value = $address_data['billing'][ $field_key ] ?? '';
			if ( '' !== trim( (string) $value ) ) {
				$billing_line_2_parts[] = trim( $label . ' ' . $value );
			}
		}
		$billing_line_2 = implode( ', ', $billing_line_2_parts );

		$shipping_data = $address_data['shipping'];
		if ( empty( array_filter( $shipping_data ) ) ) {
			$shipping_data = $address_data['billing'];
		}

		$base_shipping_line_1 = $order->get_shipping_address_1();
		if ( '' === trim( (string) $base_shipping_line_1 ) ) {
			$base_shipping_line_1 = $order->get_billing_address_1();
		}
		$shipping_line_1 = implode(
			', ',
			array_filter(
				array(
					$base_shipping_line_1,
					$shipping_data[ $street_number_key ] ?? '',
				)
			)
		);

		$shipping_line_2_parts = array();
		foreach ( $line_2_field_labels as $field_key => $label ) {
			$value = $shipping_data[ $field_key ] ?? '';
			if ( '' !== trim( (string) $value ) ) {
				$shipping_line_2_parts[] = trim( $label . ' ' . $value );
			}
		}
		$shipping_line_2 = implode( ', ', $shipping_line_2_parts );

		$order->set_billing_address_1( $billing_line_1 );
		$order->set_billing_address_2( $billing_line_2 );
		$order->set_shipping_address_1( $shipping_line_1 );
		$order->set_shipping_address_2( $shipping_line_2 );

		$order->save();
	}

	/**
	 * Glue Ecolet additional address fields into address lines for Store API (Blocks checkout) orders.
	 *
	 * Woo Additional Checkout Fields API persists values into order meta keys:
	 * - _wc_billing/<field_id>
	 * - _wc_shipping/<field_id>
	 *
	 * This method mirrors the classic checkout "glue" behavior by composing address_1/2.
	 *
	 * @param WC_Order $order Order object.
	 * @return void
	 */
	public function ecolet_glue_address_lines_for_store_api_order( $order ) {
		static $already_glued = false;
		if ( $already_glued ) {
			return;
		}

		if ( ! $this->is_ecolet_checkout_additional_fields_enabled() ) {
			return;
		}

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

		$street_number_id = 'alsendo-connect/ecolet-street-number';
		$line_2_field_ids = array(
			'alsendo-connect/ecolet-house-block'    => esc_html__( 'block', 'alsendo-connect' ),
			'alsendo-connect/ecolet-house-entrance' => esc_html__( 'entrance', 'alsendo-connect' ),
			'alsendo-connect/ecolet-floor'          => esc_html__( 'floor', 'alsendo-connect' ),
			'alsendo-connect/ecolet-flat'           => esc_html__( 'flat', 'alsendo-connect' ),
		);

		$get_meta_value = function ( $prefix, $field_id ) use ( $order ) {
			$value = $order->get_meta( $prefix . $field_id, true );
			return is_string( $value ) ? trim( $value ) : '';
		};

		$billing_prefix  = '_wc_billing/';
		$shipping_prefix = '_wc_shipping/';

		$billing_street_number  = $get_meta_value( $billing_prefix, $street_number_id );
		$shipping_street_number = $get_meta_value( $shipping_prefix, $street_number_id );

		$billing_line_1 = implode(
			', ',
			array_filter(
				array(
					trim( (string) $order->get_billing_address_1() ),
					$billing_street_number,
				)
			)
		);

		$billing_line_2_parts = array();
		foreach ( $line_2_field_ids as $field_id => $label ) {
			$value = $get_meta_value( $billing_prefix, $field_id );
			if ( '' !== $value ) {
				$billing_line_2_parts[] = trim( $label . ' ' . $value );
			}
		}
		$billing_line_2 = implode( ', ', $billing_line_2_parts );

		$base_shipping_line_1 = trim( (string) $order->get_shipping_address_1() );
		if ( '' === $base_shipping_line_1 ) {
			$base_shipping_line_1 = trim( (string) $order->get_billing_address_1() );
		}

		$shipping_street_number_effective = $shipping_street_number;
		if ( '' === $shipping_street_number_effective ) {
			$shipping_street_number_effective = $billing_street_number;
		}

		$shipping_line_1 = implode(
			', ',
			array_filter(
				array(
					$base_shipping_line_1,
					$shipping_street_number_effective,
				)
			)
		);

		$shipping_line_2_parts = array();
		foreach ( $line_2_field_ids as $field_id => $label ) {
			$value = $get_meta_value( $shipping_prefix, $field_id );
			if ( '' === $value ) {
				$value = $get_meta_value( $billing_prefix, $field_id );
			}
			if ( '' !== $value ) {
				$shipping_line_2_parts[] = trim( $label . ' ' . $value );
			}
		}
		$shipping_line_2 = implode( ', ', $shipping_line_2_parts );

		$order->set_billing_address_1( $billing_line_1 );
		$order->set_billing_address_2( $billing_line_2 );
		$order->set_shipping_address_1( $shipping_line_1 );
		$order->set_shipping_address_2( $shipping_line_2 );
		$order->save();

		$already_glued = true;
	}

	/**
	 * Determines whether Ecolet checkout additional fields feature is enabled.
	 *
	 * @return bool
	 */
	private function is_ecolet_checkout_additional_fields_enabled() {
		if ( 'ecolet' !== alsendo_connect()->get_main_settings_api() ) {
			return false;
		}

		return 'yes' === get_option( 'alsendo_connect_settings_general_ecolet_checkout_additional_fields' );
	}


	/**
	 * Integrates with WooCommerce Subscriptions to copy data between orders.
	 *
	 * @param array $data The subscription data.
	 * @param mixed $to_object The target object.
	 * @param mixed $from_object The source object.
	 * @return array The modified subscription data.
	 *
	 * @since 1.0.2
	 * @access public
	 */
	public function woo_subscriptions_integration( $data, $to_object, $from_object ) {

		$subscription_id = null;
		$new_order_id    = null;

		if ( ( is_object( $from_object ) ) ) {
			$subscription_id = $from_object->get_id();
		} else {
			$subscription_id = is_numeric( $from_object ) ? $from_object : null;
		}

		if ( ( is_object( $to_object ) ) ) {
			$new_order_id = $to_object->get_id();
		} else {
			$new_order_id = is_numeric( $to_object ) ? $to_object : null;
		}

		if ( ! empty( $subscription_id ) && ! empty( $new_order_id ) ) {
			$this->copy_apaczka_data_to_new_order( $subscription_id, $new_order_id );
		}

		return $data;
	}


	/**
	 * Copies Apaczka shipping data from one order to another.
	 *
	 * @param int $subscription_id The source order ID.
	 * @param int $new_order_id The target order ID.
	 * @return void
	 *
	 * @since 1.0.2
	 * @access public
	 */
	public function copy_apaczka_data_to_new_order( $subscription_id, $new_order_id ) {

		$subscription    = null;
		$parent_order_id = null;

		if ( function_exists( 'wcs_get_subscription' ) ) {
			$subscription = wcs_get_subscription( $subscription_id );
		}

		if ( ! $subscription || is_wp_error( $subscription ) ) {
			return;
		}

		$parent_order_id = $subscription->get_parent_id();

		if ( empty( $parent_order_id ) ) {
			return;
		}

		$new_order = wc_get_order( $new_order_id );

		if ( ! $new_order || is_wp_error( $new_order ) ) {
			return;
		}

		$parent_order = wc_get_order( $parent_order_id );
		$this->log_order_shipping_data( $parent_order, 'check address data in parent order' );

		$alsendo_wc_order_data  = $this->helper->get_woo_order_meta( $parent_order_id, 'alsendo_connect_wc_order' );
		$alsendo_delivery_point = $this->helper->get_woo_order_meta( $parent_order_id, 'alsendo_connect_delivery_point' );

		if ( ! empty( $alsendo_wc_order_data ) ) {
			if ( isset( $apaczka_wc_order_data['order_send'] ) ) {
				unset( $apaczka_wc_order_data['order_send'] );
			}
			if ( isset( $apaczka_wc_order_data['package_send'] ) ) {
				unset( $apaczka_wc_order_data['package_send'] );
			}
			$apaczka_wc_order_data = $this->update_apaczka_receiver_from_order( $apaczka_wc_order_data, $new_order, $subscription, $parent_order );
			$new_order->update_meta_data( 'alsendo_connect_wc_order', $alsendo_wc_order_data );
			$new_order->save();
		}

		if ( ! empty( $alsendo_delivery_point ) ) {
			$new_order->update_meta_data( 'alsendo_connect_delivery_point', $alsendo_delivery_point );
			$new_order->save();
		}
	}


	/**
	 * Integrates with Subscriptions for WooCommerce plugin to copy shipping data to renewal orders.
	 *
	 * @param WC_Order $new_order The new renewal order.
	 * @param int      $subscription_id The subscription ID.
	 * @return void
	 *
	 * @since 1.0.2
	 * @access public
	 */
	public function sfw_subscriptions_integration( $new_order, $subscription_id ) {

		if ( ! $new_order || is_wp_error( $new_order ) ) {
			return;
		}

		$subscription     = null;
		$wcs_subscription = null;
		$parent_order_id  = null;

		if ( function_exists( 'wcs_get_subscription' ) ) {
			$wcs_subscription = wcs_get_subscription( $subscription_id );
		}

		if ( 'yes' === get_option( 'woocommerce_custom_orders_table_enabled' ) ) {
			if ( class_exists( 'WPS_Subscription' ) ) {
				$subscription = new \WPS_Subscription( $subscription_id );
			}
		} else {
			$subscription = get_post( $subscription_id );
		}

		if ( $subscription ) {
			$parent_order_id = $subscription->get_meta( 'wps_parent_order' );
		}

		if ( ! $parent_order_id && $wcs_subscription && ! is_wp_error( $wcs_subscription ) ) {
			$parent_order_id = $wcs_subscription->get_parent_id();
		}

		if ( ! $parent_order_id ) {
			return;
		}

		$parent_order = wc_get_order( $parent_order_id );
		$this->log_order_shipping_data( $parent_order, 'check address data in parent order' );
		$this->log_order_shipping_data( $wcs_subscription, 'check address data in subscription object' );

		$alsendo_wc_order_data  = $this->helper->get_woo_order_meta( $parent_order_id, 'alsendo_connect_wc_order' );
		$alsendo_delivery_point = $this->helper->get_woo_order_meta( $parent_order_id, 'alsendo_connect_delivery_point' );

		if ( ! empty( $alsendo_wc_order_data ) ) {
			if ( isset( $apaczka_wc_order_data['order_send'] ) ) {
				unset( $apaczka_wc_order_data['order_send'] );
			}
			if ( isset( $apaczka_wc_order_data['package_send'] ) ) {
				unset( $apaczka_wc_order_data['package_send'] );
			}
			$apaczka_wc_order_data = $this->update_apaczka_receiver_from_order( $apaczka_wc_order_data, $new_order, $wcs_subscription, $parent_order );

			$new_order->update_meta_data( 'alsendo_connect_wc_order', $alsendo_wc_order_data );
			$new_order->save();
		}

		if ( ! empty( $alsendo_delivery_point ) ) {
			$new_order->update_meta_data( 'alsendo_connect_delivery_point', $alsendo_delivery_point );
			$new_order->save();
		}
	}

	/**
	 * Updates Apaczka receiver data with address details from an order.
	 *
	 * @param array             $data          Apaczka data array.
	 * @param WC_Order          $order         Renewal order.
	 * @param WC_Subscription   $subscription  Subscription object with latest customer shipping data.
	 * @param WC_Order|null     $parent_order  Parent order as fallback source.
	 * @return array
	 */
	private function update_apaczka_receiver_from_order( $data, $order, $subscription = null, $parent_order = null ) {
		if ( function_exists( 'wc_get_logger' ) ) {
			\wc_get_logger()->debug( 'update_apaczka_receiver_from_order: start', array( 'source' => 'subscription-alsendo-connect-debug' ) );
			\wc_get_logger()->debug( print_r( $data, true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		}

		if ( ! is_array( $data ) ) {
			if ( function_exists( 'wc_get_logger' ) ) {
				\wc_get_logger()->debug( 'update_apaczka_receiver_from_order: input data is not an array', array( 'source' => 'subscription-alsendo-connect-debug' ) );
			}
			return $data;
		}

		if ( ! isset( $data['receiver'] ) || ! is_array( $data['receiver'] ) ) {
			$data['receiver'] = array();
		}

		// Do not fallback company to parent order for "name", otherwise stale values can override updated customer data.
		$receiver_company    = $this->get_shipping_value_from_sources( 'company', $order, $subscription, null );
		$shipping_first_name = $this->get_shipping_value_from_sources( 'first_name', $order, $subscription, $parent_order );
		$shipping_last_name  = $this->get_shipping_value_from_sources( 'last_name', $order, $subscription, $parent_order );
		$full_name           = trim( $shipping_first_name . ' ' . $shipping_last_name );

		$this->log_order_shipping_data( $order, 'check address data in new order' );
		$this->log_order_shipping_data( $subscription, 'check address data in subscription object (mapping source)' );

		$data['receiver']['country_code']   = $this->get_shipping_value_from_sources( 'country', $order, $subscription, $parent_order );
		$data['receiver']['postal_code']    = $this->get_shipping_value_from_sources( 'postcode', $order, $subscription, $parent_order );
		$data['receiver']['city']           = $this->get_shipping_value_from_sources( 'city', $order, $subscription, $parent_order );
		$data['receiver']['line1']          = $this->get_shipping_value_from_sources( 'address_1', $order, $subscription, $parent_order );
		$data['receiver']['line2']          = $this->get_shipping_value_from_sources( 'address_2', $order, $subscription, $parent_order );
		$data['receiver']['name']           = ! empty( $receiver_company ) ? $receiver_company : $full_name;
		$data['receiver']['contact_person'] = $full_name;

		$data['receiver']['phone'] = $this->get_shipping_value_from_sources( 'phone', $order, $subscription, $parent_order );

		$data['receiver']['email'] = $this->get_shipping_value_from_sources( 'email', $order, $subscription, $parent_order );

		if ( function_exists( 'wc_get_logger' ) ) {
			\wc_get_logger()->debug( 'receiver after base mapping', array( 'source' => 'subscription-alsendo-connect-debug' ) );
			\wc_get_logger()->debug( print_r( $data['receiver'], true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		}

		$receiver_address_line_full = '';
		if ( ! empty( $data['receiver']['line1'] ) ) {
			$receiver_address_line_full = trim( $data['receiver']['line1'] );
		}

		if ( ! empty( $data['receiver']['line2'] ) ) {
			$receiver_address_line_2     = trim( $data['receiver']['line2'] );
			$receiver_address_line_full .= ', ' . $receiver_address_line_2;
		}

		$data['receiver']['line1'] = $receiver_address_line_full;
		$data['receiver']['line2'] = '';

		if ( function_exists( 'wc_get_logger' ) ) {
			\wc_get_logger()->debug( 'receiver after line merge', array( 'source' => 'subscription-alsendo-connect-debug' ) );
			\wc_get_logger()->debug( print_r( $data['receiver'], true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
			\wc_get_logger()->debug( 'update_apaczka_receiver_from_order: end', array( 'source' => 'subscription-alsendo-connect-debug' ) );
		}

		return $data;
	}

	/**
	 * Logs shipping data from an order for debugging.
	 *
	 * @param mixed $order   Order object.
	 * @param string        $message Log message prefix.
	 * @return void
	 */
	private function log_order_shipping_data( $order, $message ) {
		if ( ! function_exists( 'wc_get_logger' ) ) {
			return;
		}

		if ( ! $order || is_wp_error( $order ) ) {
			\wc_get_logger()->debug( $message . ': order not found', array( 'source' => 'subscription-alsendo-connect-debug' ) );
			return;
		}

		$receiver_company    = $order->get_shipping_company();
		$shipping_first_name = $order->get_shipping_first_name();
		$shipping_last_name  = $order->get_shipping_last_name();

		\wc_get_logger()->debug( $message, array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $receiver_company, true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $shipping_first_name, true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $shipping_last_name, true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $order->get_shipping_country(), true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $order->get_shipping_postcode(), true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $order->get_shipping_city(), true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $order->get_shipping_address_1(), true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
		\wc_get_logger()->debug( print_r( $order->get_shipping_address_2(), true ), array( 'source' => 'subscription-alsendo-connect-debug' ) );
	}

	/**
	 * Returns shipping field value with source priority:
	 * subscription -> new order -> parent order.
	 *
	 * @param string                $field        Shipping field key.
	 * @param WC_Order              $order        Renewal order.
	 * @param WC_Subscription|null  $subscription Subscription object.
	 * @param WC_Order|null         $parent_order Parent order fallback object.
	 * @return string
	 */
	private function get_shipping_value_from_sources( $field, $order, $subscription = null, $parent_order = null ) {
		$sources = array( $subscription, $order, $parent_order );

		foreach ( $sources as $source ) {
			$value = $this->get_shipping_value_with_fallback( $source, $field );
			if ( '' !== $value ) {
				return $value;
			}
		}

		return '';
	}

	/**
	 * Returns shipping field value using robust fallbacks on one WC object.
	 *
	 * @param WC_Data $wc_data_object WC order/subscription object.
	 * @param string  $field  Shipping field key.
	 * @return string
	 */
	private function get_shipping_value_with_fallback( $wc_data_object, $field ) {
		if ( ! $wc_data_object || is_wp_error( $wc_data_object ) || ! method_exists( $wc_data_object, 'get_meta' ) ) {
			return '';
		}

		$object_id    = method_exists( $wc_data_object, 'get_id' ) ? $wc_data_object->get_id() : 0;
		$fresh_object = $wc_data_object;

		if ( $object_id && function_exists( 'wcs_get_subscription' ) && class_exists( 'WC_Subscription' ) && $wc_data_object instanceof \WC_Subscription ) {
			$fresh_subscription = wcs_get_subscription( $object_id );
			if ( $fresh_subscription && ! is_wp_error( $fresh_subscription ) ) {
				$fresh_object = $fresh_subscription;
			}
		} elseif ( $object_id ) {
			$fresh_order = wc_get_order( $object_id );
			if ( $fresh_order && ! is_wp_error( $fresh_order ) ) {
				$fresh_object = $fresh_order;
			}
		}

		$getter_map = array(
			'company'    => 'get_shipping_company',
			'first_name' => 'get_shipping_first_name',
			'last_name'  => 'get_shipping_last_name',
			'country'    => 'get_shipping_country',
			'postcode'   => 'get_shipping_postcode',
			'city'       => 'get_shipping_city',
			'address_1'  => 'get_shipping_address_1',
			'address_2'  => 'get_shipping_address_2',
			'phone'      => 'get_shipping_phone',
			'email'      => 'get_shipping_email',
		);

		$meta_map = array(
			'company'    => '_shipping_company',
			'first_name' => '_shipping_first_name',
			'last_name'  => '_shipping_last_name',
			'country'    => '_shipping_country',
			'postcode'   => '_shipping_postcode',
			'city'       => '_shipping_city',
			'address_1'  => '_shipping_address_1',
			'address_2'  => '_shipping_address_2',
			'phone'      => '_shipping_phone',
			'email'      => '_shipping_email',
		);

		$value = '';

		if ( isset( $getter_map[ $field ] ) ) {
			$getter = $getter_map[ $field ];
			if ( method_exists( $fresh_object, $getter ) ) {
				$value = (string) $fresh_object->{$getter}();
			}

			if ( '' === trim( $value ) && method_exists( $wc_data_object, $getter ) ) {
				$value = (string) $wc_data_object->{$getter}();
			}
		}

		if ( '' === trim( $value ) && isset( $meta_map[ $field ] ) ) {
			$meta_key = $meta_map[ $field ];
			$value    = (string) $fresh_object->get_meta( $meta_key, true );
			if ( '' === trim( $value ) ) {
				$value = (string) $wc_data_object->get_meta( $meta_key, true );
			}
		}

		if ( '' === trim( $value ) && 'phone' === $field ) {
			if ( method_exists( $fresh_object, 'get_billing_phone' ) ) {
				$value = (string) $fresh_object->get_billing_phone();
			}
			if ( '' === trim( $value ) && method_exists( $wc_data_object, 'get_billing_phone' ) ) {
				$value = (string) $wc_data_object->get_billing_phone();
			}
		}

		if ( '' === trim( $value ) && 'email' === $field ) {
			if ( method_exists( $fresh_object, 'get_billing_email' ) ) {
				$value = (string) $fresh_object->get_billing_email();
			}
			if ( '' === trim( $value ) && method_exists( $wc_data_object, 'get_billing_email' ) ) {
				$value = (string) $wc_data_object->get_billing_email();
			}
		}

		return is_string( $value ) ? trim( $value ) : '';
	}
}
