<?php
namespace WPO\IPS;

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

if ( ! class_exists( '\\WPO\\IPS\\Frontend' ) ) :

class Frontend {

	protected static ?self $_instance = null;

	/**
	 * Get the singleton instance of this class.
	 *
	 * @return self
	 */
	public static function instance(): self {
		if ( is_null( self::$_instance ) ) {
			self::$_instance = new self();
		}
		return self::$_instance;
	}

	/**
	 * Constructor
	 */
	public function __construct() {
		// PDF download link on My Account page
		add_filter( 'woocommerce_my_account_my_orders_actions', array( $this, 'my_account_invoice_actions' ), 999, 2 ); // needs to be triggered later because of Jetpack query string: https://github.com/Automattic/jetpack/blob/1a062c5388083c7f15b9a3e82e61fde838e83047/projects/plugins/jetpack/modules/woocommerce-analytics/classes/class-jetpack-woocommerce-analytics-my-account.php#L235
		add_action( 'wp_enqueue_scripts', array( $this, 'open_my_account_link_on_new_tab' ), 999 );

		// REST API
		add_filter( 'woocommerce_api_order_response', array( $this, 'add_invoice_number_to_wc_legacy_order_api' ), 10, 2 ); // support for legacy WC REST API
		add_filter( 'woocommerce_rest_prepare_shop_order_object', array( $this, 'add_invoice_number_to_wc_order_api' ), 10, 3 );

		// Shortcodes
		add_shortcode( 'wcpdf_download_invoice', array( $this, 'generate_document_shortcode' ) );
		add_shortcode( 'wcpdf_download_pdf', array( $this, 'generate_document_shortcode' ) );
		add_shortcode( 'wcpdf_document_link', array( $this, 'generate_document_shortcode' ) );

		// Optional Checkout field (General Settings).
		if ( $this->checkout_field_is_enabled() ) {
			// Blocks/store-api hooks
			$this->checkout_field_display_checkout_block_field();
			$this->checkout_field_set_checkout_block_field_value();

			add_action( 'woocommerce_set_additional_field_value', array( $this, 'checkout_field_save_checkout_block_field' ), 10, 4 );
			add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'checkout_field_remove_order_checkout_block_field_meta' ), 10, 1 );

			// Classic checkout hooks
			add_filter( 'woocommerce_checkout_fields', array( $this, 'checkout_field_display_classic_checkout_field' ), 10, 1 );
			add_filter( 'woocommerce_checkout_get_value', array( $this, 'checkout_field_set_classic_checkout_field_value' ), 10, 2 );
			add_action( 'woocommerce_after_checkout_validation', array( $this, 'checkout_field_validate_classic_checkout_field_value' ), 10, 2 );
			add_action( 'woocommerce_checkout_update_order_meta', array( $this, 'checkout_field_save_classic_checkout_field' ), 10, 2 );

			add_action( 'woocommerce_admin_order_data_after_billing_address', array( $this, 'checkout_field_display_admin_billing' ), 10, 1 );

			// My Account (Account details).
			if ( $this->checkout_field_is_my_account_enabled() ) {
				add_action( 'woocommerce_edit_account_form', array( $this, 'account_details_display_checkout_field' ), 20 );
				add_filter( 'woocommerce_save_account_details_errors', array( $this, 'account_details_validate_checkout_field' ), 20, 2 );
				add_action( 'woocommerce_save_account_details', array( $this, 'account_details_save_checkout_field' ), 20, 1 );
			}

		}
	}

	/**
	 * Display My Account invoice actions.
	 *
	 * @param array              $actions
	 * @param \WC_Abstract_Order $order
	 * @return array
	 */
	public function my_account_invoice_actions( array $actions, \WC_Abstract_Order $order ): array {
		$this->disable_storing_document_settings();

		$document_type  = 'invoice';
		$document_title = __( 'Invoice', 'woocommerce-pdf-invoices-packing-slips' );
		$invoice        = wcpdf_get_document( $document_type, $order );

		if ( ! $invoice ) {
			return apply_filters( 'wpo_wcpdf_myaccount_actions', $actions, $order );
		}

		$invoice_allowed = $invoice->is_allowed_in_my_account( 'available' );

		// Backward compatibility with the existing status-based filter.
		if ( ! $invoice_allowed ) {
			$invoice_allowed = in_array(
				$order->get_status(),
				apply_filters( 'wpo_wcpdf_myaccount_allowed_order_statuses', array() ),
				true
			);
		}

		if ( $invoice_allowed ) {
			$name = is_callable( array( $invoice, 'get_title' ) )
				? $invoice->get_title()
				: $document_title;

			$endpoint_instance = WPO_WCPDF()->endpoint;

			$actions[ $document_type ] = array(
				'url'  => $endpoint_instance->get_document_link( $order, $document_type, array( 'my-account' => 'true' ) ),
				'name' => apply_filters( 'wpo_wcpdf_myaccount_button_text', $name, $invoice ),
			);

			if ( $invoice->is_enabled( 'xml' ) && wpo_ips_edi_is_available() ) {
				$actions[ $document_type . '_xml' ] = array(
					'url'  => $endpoint_instance->get_document_link( $order, $document_type, array( 'output' => 'xml', 'my-account' => 'true' ) ),
					'name' => apply_filters( 'wpo_wcpdf_myaccount_button_text', "E-{$name}", $invoice ),
				);
			}
		}

		return apply_filters( 'wpo_wcpdf_myaccount_actions', $actions, $order );
	}

	/**
	 * Open link links in a new browser tab/window on the My Account and Thank You (Order Received) pages
	 *
	 * @return void
	 */
	public function open_my_account_link_on_new_tab(): void {
		$is_account        = function_exists( 'is_account_page' )        && is_account_page();
		$is_order_received = function_exists( 'is_order_received_page' ) && is_order_received_page();

		if ( $is_account || $is_order_received ) {
			$general_settings = get_option( 'wpo_wcpdf_settings_general', array() );

			if ( isset( $general_settings['download_display'] ) && 'display' === $general_settings['download_display'] ) {
				$suffix    = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
				$file_path = WPO_WCPDF()->plugin_path() . '/assets/js/my-account-link' . $suffix . '.js';

				if ( WPO_WCPDF()->file_system->exists( $file_path ) ) {
					$script = WPO_WCPDF()->file_system->get_contents( $file_path );

					if ( $script && WPO_WCPDF()->endpoint->pretty_links_enabled() ) {
						$script = str_replace( 'generate_wpo_wcpdf', WPO_WCPDF()->endpoint->get_identifier(), $script );
					}

					wp_add_inline_script( 'jquery', $script );
				}
			}
		}
	}

	/**
	 * Add invoice number to WC Legacy REST API.
	 *
	 * @param array $data
	 * @param \WC_Abstract_Order $order
	 *
	 * @return array
	 */
	public function add_invoice_number_to_wc_legacy_order_api( array $data, \WC_Abstract_Order $order ): array {
		$data['wpo_wcpdf_invoice_number'] = $this->get_invoice_number( $order );

		return $data;
	}

	/**
	 * Add invoice number to WC REST API.
	 *
	 * @param \WP_REST_Response $response
	 * @param \WC_Data $order
	 * @param \WP_REST_Request $request
	 *
	 * @return \WP_REST_Response
	 */
	public function add_invoice_number_to_wc_order_api( \WP_REST_Response $response, \WC_Data $order, \WP_REST_Request $request ): \WP_REST_Response {
		$data                             = $response->get_data();
		$data['wpo_wcpdf_invoice_number'] = $this->get_invoice_number( $order );
		$response->set_data( $data );

		return $response;
	}

	/**
	 * Retrieve formatted invoice number for a given order
	 *
	 * @param \WC_Abstract_Order|\WC_Order $order
	 * @return string
	 */
	private function get_invoice_number( $order ): string {
		$invoice_number = '';

		$this->disable_storing_document_settings();

		try {
			$invoice = wcpdf_get_document( 'invoice', $order );

			if ( ! $invoice || ! is_callable( array( $invoice, 'get_number' ) ) ) {
				return '';
			}

			$number = $invoice->get_number();

			if ( ! empty( $number ) ) {
				$invoice_number = is_callable( array( $number, 'get_formatted' ) )
					? $number->get_formatted()
					: (string) $number;
			}

		} finally {
			$this->restore_storing_document_settings();
		}

		return $invoice_number;
	}

	/**
	 * Generate a document download link via shortcode
	 *
	 * @param array $atts
	 * @param string|null $content
	 * @param string $shortcode_tag
	 * @return string
	 */
	public function generate_document_shortcode( array $atts, ?string $content = null, string $shortcode_tag = '' ): string {
		global $wp;

		if ( is_admin() ) {
			return '';
		}

		// Default values
		$values = shortcode_atts( array(
			'order_id'      => '',
			'link_text'     => '',
			'id'            => '',
			'class'         => 'wpo_wcpdf_document_link',
			'document_type' => 'invoice',
		), $atts );

		$values['order_id']      = absint( $values['order_id'] );
		$values['document_type'] = sanitize_key( $values['document_type'] );
		$has_explicit_order_id   = ! empty( $values['order_id'] );

		$is_document_type_valid = false;
		$documents              = WPO_WCPDF()->documents->get_documents();

		foreach ( $documents as $document ) {
			if ( $document->get_type() === $values['document_type'] ) {
				$is_document_type_valid = true;

				if ( ! empty( $values['link_text'] ) ) {
					$link_text = $values['link_text'];
				} else {
					$link_text = sprintf(
						/* translators: %s: Document type */
						__( 'Download %s (PDF)', 'woocommerce-pdf-invoices-packing-slips' ),
						wp_kses_post( $document->get_type() )
					);
				}

				break;
			}
		}

		if ( ! $is_document_type_valid ) {
			return '';
		}

		// Get $order
		$order = null;

		if ( ! $has_explicit_order_id ) {
			if ( is_checkout() && is_wc_endpoint_url( 'order-received' ) && isset( $wp->query_vars['order-received'] ) ) {
				$order = wc_get_order( $wp->query_vars['order-received'] );
			} elseif ( is_account_page() && is_wc_endpoint_url( 'view-order' ) && isset( $wp->query_vars['view-order'] ) ) {
				$order = wc_get_order( $wp->query_vars['view-order'] );
			}
		} else {
			$order = wc_get_order( $values['order_id'] );
		}

		if ( empty( $order ) || ! is_object( $order ) ) {
			return '';
		}

		if ( $has_explicit_order_id && ! $this->current_user_can_access_shortcode_order( $order, $values['document_type'] ) ) {
			return '';
		}

		$document = wcpdf_get_document( $values['document_type'], $order );

		if ( ! $document || ! $document->is_allowed() ) {
			return '';
		}

		$pdf_url = WPO_WCPDF()->endpoint->get_document_link( $order, $values['document_type'], [ 'shortcode' => 'true' ] );

		if ( 'wcpdf_document_link' === $shortcode_tag ) {
			return esc_url( $pdf_url );
		}

		return sprintf(
			'<p><a %s class="%s" href="%s" target="_blank">%s</a></p>',
			( ! empty( $values['id'] ) ? 'id="' . esc_attr( $values['id'] ) . '"' : '' ),
			esc_attr( $values['class'] ),
			esc_url( $pdf_url ),
			esc_html( $link_text )
		);
	}

	/**
	 * Document objects are created in order to check for existence and retrieve data,
	 * but we don't want to store the settings for uninitialized documents.
	 * Only use in frontend/backed (page requests), otherwise settings will never be stored!
	 *
	 * @return void
	 */
	public function disable_storing_document_settings(): void {
		add_filter( 'wpo_wcpdf_document_store_settings', '__return_false', 9999 );
	}

	/**
	 * Restore the original document settings storing behavior.
	 * This should be called after disabling storing settings to avoid affecting other parts of the code.
	 *
	 * @return void
	 */
	public function restore_storing_document_settings(): void {
		remove_filter( 'wpo_wcpdf_document_store_settings', '__return_false', 9999 );
	}

	/**
	 * Display optional checkout field in the Checkout Block.
	 *
	 * @return void
	 */
	public function checkout_field_display_checkout_block_field(): void {
		if ( ! $this->checkout_field_is_enabled() ) {
			return;
		}

		$field_id = 'wpo-ips/checkout-field';

		$args = array(
			'id'                => $field_id,
			'label'             => $this->checkout_field_get_label(),
			'location'          => 'order',
			'type'              => 'text',
			'sanitize_callback' => static function ( $val ) {
				$val = sanitize_text_field( (string) $val );
				return (string) apply_filters( 'wpo_ips_checkout_field_sanitize', $val );
			},
			'validate_callback' => function ( $val ) {
				$val = (string) $val;

				// If not treated as VAT, keep the existing flexible hook.
				if ( ! $this->checkout_field_is_vat_number() ) {
					$result = apply_filters( 'wpo_ips_checkout_field_validate', true, $val );
					return ( $result instanceof \WP_Error ) ? $result : true;
				}

				$result = apply_filters( 'wpo_ips_checkout_field_validate', $this->checkout_field_validate_vat_number_value( $val ), $val );
				return ( $result instanceof \WP_Error ) ? $result : true;
			},
		);

		$args = apply_filters( 'wpo_ips_checkout_field_block_args', $args );

		wpo_ips_register_additional_checkout_field( $args );
	}

	/**
	 * Set default value for the optional checkout field in the Checkout Block.
	 *
	 * @return void
	 */
	public function checkout_field_set_checkout_block_field_value(): void {
		$field_id = 'wpo-ips/checkout-field';

		add_filter(
			"woocommerce_get_default_value_for_{$field_id}",
			static function ( $value, string $group, \WC_Data $wc_object ) {
				// Our field is in 'order' location, so group is typically 'other'.
				if ( ! $wc_object instanceof \WC_Customer ) {
					return (string) $value;
				}

				$user_id = $wc_object->get_id();
				if ( ! $user_id ) {
					return (string) $value;
				}

				$stored = (string) get_user_meta( $user_id, 'wpo_ips_checkout_field', true );

				return (string) apply_filters( 'wpo_ips_checkout_field_default_value', $stored, $value, $group, $wc_object );
			},
			10,
			3
		);
	}

	/**
	 * Save optional checkout field from the Checkout Block.
	 *
	 * @param string $key Field key.
	 * @param mixed $value Field value.
	 * @param string $group Group name.
	 * @param object $wc_object WC object (e.g. order).
	 * @return void
	 */
	public function checkout_field_save_checkout_block_field( string $key, $value, string $group, object $wc_object ): void {
		if ( ! $this->checkout_field_is_enabled() ) {
			return;
		}

		$field_id = 'wpo-ips/checkout-field';

		if ( $key !== $field_id ) {
			return;
		}

		if ( ! ( $wc_object instanceof \WC_Order ) ) {
			return;
		}

		$val = sanitize_text_field( (string) wp_unslash( $value ) );
		$val = (string) apply_filters( 'wpo_ips_checkout_field_sanitize', $val );

		// Save on order.
		$order_meta_key = '_wpo_ips_checkout_field';

		if ( '' === trim( $val ) ) {
			$wc_object->delete_meta_data( $order_meta_key );
		} else {
			$wc_object->update_meta_data( $order_meta_key, $val );
		}

		$wc_object->save_meta_data();

		// Save on customer (if available).
		$customer_id = is_callable( array( $wc_object, 'get_customer_id' ) ) ? absint( $wc_object->get_customer_id() ) : 0;
		if ( $customer_id > 0 ) {
			if ( '' === trim( $val ) ) {
				delete_user_meta( $customer_id, 'wpo_ips_checkout_field' );
			} else {
				update_user_meta( $customer_id, 'wpo_ips_checkout_field', $val );
			}
		}
	}

	/**
	 * Remove optional checkout field from order meta after checkout.
	 *
	 * @param \WC_Abstract_Order $order
	 * @return void
	 */
	public function checkout_field_remove_order_checkout_block_field_meta( \WC_Abstract_Order $order ): void {
		$field_id = 'wpo-ips/checkout-field';

		$order->delete_meta_data( '_wc_other/' . $field_id );
		$order->save_meta_data();
	}

	/**
	 * Display optional checkout field in the Classic Checkout page.
	 *
	 * @param mixed $fields
	 * @return array
	 */
	public function checkout_field_display_classic_checkout_field( $fields ): array {
		if ( ! is_array( $fields ) ) {
			$fields = array();
		}

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

		$fields['order'] = $fields['order'] ?? array();

		$key = 'wpo_ips_checkout_field';

		$args = array(
			'type'     => 'text',
			'label'    => $this->checkout_field_get_label(),
			'required' => false,
			'class'    => array( 'form-row-wide' ),
		);

		$fields['order'][ $key ] = apply_filters( 'wpo_ips_checkout_field_classic_args', $args );

		return $fields;
	}

	/**
	 * Set default value for the optional checkout field in the Classic Checkout page.
	 *
	 * @param mixed $value
	 * @param string $input
	 * @return mixed
	 */
	public function checkout_field_set_classic_checkout_field_value( $value, string $input ) {
		if ( 'wpo_ips_checkout_field' !== $input ) {
			return $value;
		}

		$user_id = get_current_user_id();
		if ( ! $user_id ) {
			return $value;
		}

		$stored = (string) get_user_meta( $user_id, 'wpo_ips_checkout_field', true );

		return (string) apply_filters( 'wpo_ips_checkout_field_default_value', $stored, $value, 'classic', null );
	}

	/**
	 * Validate optional checkout field from the Classic Checkout page.
	 *
	 * @param mixed $data
	 * @param mixed $errors
	 * @return void
	 */
	public function checkout_field_validate_classic_checkout_field_value( $data, $errors ): void {
		if ( ! $this->checkout_field_is_enabled() || ! $errors instanceof \WP_Error ) {
			return;
		}

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

		$key = 'wpo_ips_checkout_field';
		$raw = isset( $data[ $key ] ) ? (string) $data[ $key ] : '';
		$val = sanitize_text_field( $raw );
		$val = (string) apply_filters( 'wpo_ips_checkout_field_sanitize', $val );

		if ( '' === trim( $val ) ) {
			return;
		}

		if ( $this->checkout_field_is_vat_number() ) {
			$result = $this->checkout_field_validate_vat_number_value( $val );

			if ( $result instanceof \WP_Error ) {
				$errors->add( $result->get_error_code(), $result->get_error_message(), array( 'id' => $key ) );
			}

			return;
		}

		// Non-VAT mode: keep existing flexibility.
		$result = apply_filters( 'wpo_ips_checkout_field_validate', true, $val );

		if ( $result instanceof \WP_Error ) {
			$errors->add( $result->get_error_code(), $result->get_error_message(), array( 'id' => $key ) );
		}
	}

	/**
	 * Save optional checkout field from the Classic Checkout page.
	 *
	 * @param int $order_id
	 * @param array $data
	 * @return void
	 */
	public function checkout_field_save_classic_checkout_field( int $order_id, array $data ): void {
		if ( ! $this->checkout_field_is_enabled() ) {
			return;
		}

		$order = wc_get_order( $order_id );
		if ( empty( $order ) ) {
			return;
		}

		$key            = 'wpo_ips_checkout_field';
		$order_meta_key = '_wpo_ips_checkout_field';

		$raw = isset( $data[ $key ] ) ? (string) $data[ $key ] : '';
		$val = sanitize_text_field( $raw );
		$val = (string) apply_filters( 'wpo_ips_checkout_field_sanitize', $val );

		// Order meta
		if ( '' === trim( $val ) ) {
			$order->delete_meta_data( $order_meta_key );
		} else {
			$order->update_meta_data( $order_meta_key, $val );
		}
		$order->save_meta_data();

		// Customer meta (if available)
		$customer_id = is_callable( array( $order, 'get_customer_id' ) ) ? absint( $order->get_customer_id() ) : 0;
		if ( $customer_id > 0 ) {
			if ( '' === trim( $val ) ) {
				delete_user_meta( $customer_id, 'wpo_ips_checkout_field' );
			} else {
				update_user_meta( $customer_id, 'wpo_ips_checkout_field', $val );
			}
		}
	}

	/**
	 * Display the optional checkout field under the Billing address in wp-admin.
	 *
	 * @param \WC_Order $order
	 * @return void
	 */
	public function checkout_field_display_admin_billing( \WC_Order $order ): void {
		// If your setting disables the field, don't show it.
		if ( ! $this->checkout_field_is_enabled() ) {
			return;
		}

		$value = (string) $order->get_meta( '_wpo_ips_checkout_field', true );
		$value = trim( $value );

		if ( '' === $value ) {
			return;
		}

		$label = $this->checkout_field_get_label();

		echo '<p><strong>' . esc_html( $label ) . ':</strong><br>' . esc_html( $value ) . '</p>';
	}

	/**
	 * Display the optional checkout field in My Account > Account details.
	 *
	 * @return void
	 */
	public function account_details_display_checkout_field(): void {
		if ( ! $this->checkout_field_is_my_account_enabled() ) {
			return;
		}

		$user_id = get_current_user_id();
		if ( ! $user_id ) {
			return;
		}

		$key   = 'wpo_ips_checkout_field';
		$value = (string) get_user_meta( $user_id, $key, true );
		$value = (string) apply_filters( 'wpo_ips_checkout_field_default_value', $value, $value, 'my-account', null );

		$label       = $this->checkout_field_get_label();
		$description = '';

		if ( $this->checkout_field_is_vat_number() ) {
			$description = __( 'Please include the country prefix (for example NL123456789).', 'woocommerce-pdf-invoices-packing-slips' );
		}

		echo '<p class="woocommerce-form-row woocommerce-form-row--wide form-row form-row-wide">';
		echo '<label for="' . esc_attr( $key ) . '">' . esc_html( $label ) . '</label>';
		echo '<input type="text" class="woocommerce-Input woocommerce-Input--text input-text" name="' . esc_attr( $key ) . '" id="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
		if ( '' !== $description ) {
			echo '<span class="description">' . esc_html( $description ) . '</span>';
		}
		echo '</p>';
	}

	/**
	 * Validate the My Account field.
	 *
	 * @param \WP_Error $errors
	 * @param \WP_User  $user
	 * @return \WP_Error
	 */
	public function account_details_validate_checkout_field( \WP_Error $errors, $user ): \WP_Error {
		if ( ! $this->checkout_field_is_my_account_enabled() ) {
			return $errors;
		}

		$key = 'wpo_ips_checkout_field';

		// Field is optional: if missing, don't block save.
		if ( ! isset( $_POST[ $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			return $errors;
		}

		$val = (string) sanitize_text_field( wp_unslash( $_POST[ $key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
		$val = (string) apply_filters( 'wpo_ips_checkout_field_sanitize', $val );

		if ( '' === trim( $val ) ) {
			return $errors;
		}

		// VAT mode.
		if ( $this->checkout_field_is_vat_number() ) {
			$result = $this->checkout_field_validate_vat_number_value( $val );

			if ( $result instanceof \WP_Error ) {
				$errors->add( $result->get_error_code(), $result->get_error_message() );
			}

			return $errors;
		}

		// Non-VAT mode: keep your flexible validation hook.
		$result = apply_filters( 'wpo_ips_checkout_field_validate', true, $val );
		if ( $result instanceof \WP_Error ) {
			$errors->add( $result->get_error_code(), $result->get_error_message() );
		}

		return $errors;
	}

	/**
	 * Save the My Account field (user meta only).
	 *
	 * @param int $user_id
	 * @return void
	 */
	public function account_details_save_checkout_field( int $user_id ): void {
		if ( ! $this->checkout_field_is_my_account_enabled() ) {
			return;
		}

		$key = 'wpo_ips_checkout_field';

		if ( ! isset( $_POST[ $key ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			// If the field isn't present in the form submission, do nothing.
			return;
		}

		$val = (string) sanitize_text_field( wp_unslash( $_POST[ $key ] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
		$val = (string) apply_filters( 'wpo_ips_checkout_field_sanitize', $val );

		if ( '' === trim( $val ) ) {
			delete_user_meta( $user_id, $key );
		} else {
			update_user_meta( $user_id, $key, $val );
		}
	}

	/**
	 * Check if the checkout field should be treated as a VAT number.
	 *
	 * @return bool
	 */
	public function checkout_field_is_vat_number(): bool {
		$general_settings = get_option( 'wpo_wcpdf_settings_general', array() );
		$enabled          = ! empty( $general_settings['checkout_field_as_vat_number'] );

		if ( ! $enabled ) {
			return false;
		}

		// Prevent conflicts with VAT plugins.
		if ( \WPO_WCPDF()->vat_plugins->has_active() ) {
			return false;
		}

		return true;
	}

	/**
	 * Check if the checkout field is enabled in settings.
	 *
	 * @return bool
	 */
	private function checkout_field_is_enabled(): bool {
		$general_settings = get_option( 'wpo_wcpdf_settings_general', array() );
		return ! empty( $general_settings['checkout_field_enable'] ?? '' );
	}

	/**
	 * Check if the My Account field is enabled in settings.
	 *
	 * @return bool
	 */
	private function checkout_field_is_my_account_enabled(): bool {
		if ( ! $this->checkout_field_is_enabled() ) {
			return false;
		}

		$general_settings = get_option( 'wpo_wcpdf_settings_general', array() );
		return ! empty( $general_settings['checkout_field_enable_my_account'] ?? '' );
	}

	/**
	 * Get the checkout field label from settings.
	 *
	 * @return string
	 */
	private function checkout_field_get_label(): string {
		$default          = __( 'Customer identification', 'woocommerce-pdf-invoices-packing-slips' );
		$general_settings = get_option( 'wpo_wcpdf_settings_general', array() );
		$label            = trim( $general_settings['checkout_field_label'] ?? '' );

		if ( '' === $label ) {
			$label = $default;
		}

		return (string) apply_filters( 'wpo_ips_checkout_field_label', $label );
	}

	/**
	 * Validate the checkout field value when treated as a VAT number.
	 *
	 * @param string $raw_value
	 * @return true|\WP_Error
	 */
	private function checkout_field_validate_vat_number_value( string $raw_value ) {
		$vat = strtoupper( preg_replace( '/\s+/', '', trim( $raw_value ) ) );

		// Optional field: empty is always OK.
		if ( '' === $vat ) {
			return true;
		}

		/**
		 * Allow other code to normalize the VAT number before validation.
		 *
		 * @param string $vat
		 * @param string $raw_value
		 */
		$vat = (string) apply_filters( 'wpo_ips_checkout_field_vat_normalize', $vat, $raw_value );

		// Must start with a valid country prefix.
		if ( ! wpo_ips_edi_vat_number_has_country_prefix( $vat ) ) {
			$error = new \WP_Error(
				'invalid_vat_prefix',
				__( 'Please enter a VAT number including a valid country prefix (for example PT123456789).', 'woocommerce-pdf-invoices-packing-slips' )
			);

			/**
			 * Allow overriding the error returned by the base validation.
			 *
			 * @param \WP_Error $error
			 * @param string   $vat
			 */
			return apply_filters( 'wpo_ips_checkout_field_vat_prefix_error', $error, $vat );
		}

		/**
		 * Allow additional VAT checks (format, length, VIES, etc).
		 * Return true to accept, or WP_Error to reject.
		 *
		 * @param true|\WP_Error $result
		 * @param string         $vat
		 * @param string         $raw_value
		 */
		return apply_filters( 'wpo_ips_checkout_field_vat_validate', true, $vat, $raw_value );
	}

	/**
	 * Check whether the current user can use a shortcode with an explicit order ID.
	 *
	 * @param \WC_Abstract_Order $order
	 * @param string             $document_type
	 * @return bool
	 */
	protected function current_user_can_access_shortcode_order( \WC_Abstract_Order $order, string $document_type ): bool {
		if ( WPO_WCPDF()->admin->user_can_manage_document( $document_type ) ) {
			return true;
		}

		return is_user_logged_in() && current_user_can( 'view_order', $order->get_id() );
	}

}

endif; // class_exists
