<?php
/**
 * Oxygen MyData Class File
 *
 * @package Oxygen
 * @summary Class to add WooCommerce settings tab and fields, WooCommerce Helper Funtions
 * @version 2.0.38
 * @since  1.0.0
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}
/**
 * Class OxygenHelperFunctions
 *
 * A utility class that provides helper functions used throughout the Oxygen WooCommerce Plugin.
 *
 * @package OxygenWooCommercePlugin
 */
class OxygenHelperFunctions {


	/**
	 * Singleton Instance of Oxygen Woo Settings
	 *
	 * @var OxygenHelperFunctions
	 **/
	private static $instance = null;


	/**
	 * Singleton init Function
	 *
	 * @static
	 */
	public static function init() {
		if ( ! self::$instance ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 *  Cache user meta keys.
	 *
	 *  @return array of user meta keys
	 */
	public static function generate_user_meta_keys() {
		global $wpdb;

		$query     = "
			SELECT DISTINCT($wpdb->usermeta.meta_key) 
			FROM $wpdb->usermeta 
			WHERE $wpdb->usermeta.meta_key != '' 
			AND $wpdb->usermeta.meta_key NOT RegExp '(^[0-9]+$)'
		";
		// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- Static query without user input; safe to run as-is.
		$meta_keys = $wpdb->get_col( $query );
		set_transient( 'oxygen_user_meta_keys', $meta_keys, 60 * 60 * 24 ); // create 1 Day Expiration.
		return $meta_keys;
	}

	/**
	 *  Get cached ot cache user meta keys.
	 *
	 *  @return array of user meta keys
	 */
	public static function get_user_meta_keys() {
		$cache     = get_transient( 'oxygen_user_meta_keys' );
		$meta_keys = $cache ? $cache : self::generate_user_meta_keys();
		return array_combine( $meta_keys, $meta_keys );
	}

	/**
	 *  Get_option wrapper
	 *
	 *  @param string $option meta key.
	 *  @return WC_Admin_Settings
	 */
	public static function get_option( $option ) {

		return WC_Admin_Settings::get_option( $option );
	}

	/**
	 *  Oxygen API Document Types
	 *
	 *  @return array
	 */
	public static function document_types(): array {

		return array(
			'tpy'        => 's',
			'tpda'       => 'p',
			'tpda_intra' => 'p',
			'tpy_intra'  => 's',
			'apy'        => 'rs',
			'alp'        => 'rp',
			'notice'     => 'notice'
		);
	}

		/**
		 *  Oxygen API Document Types Names
		 *
		 *  @return array
		 */
	public static function document_type_names() {

		return array(
			'0'          => __( 'Select document type', 'oxygen' ),
			'apy'        => __( 'Receipt of Service:', 'oxygen' ),
			'alp'        => __( 'Receipt of Goods:', 'oxygen' ),
			'tpy'        => __( 'Invoice of Service:', 'oxygen' ),
			'tpda'       => __( 'Invoice of Goods/Shipping:', 'oxygen' ),
			'tpda_intra' => __( 'Invoice of Goods/Intra-Community Shipping:', 'oxygen' ),
			'tpy_intra'  => __( 'Invoice of Service/Intra-Community Service:', 'oxygen' ),
			'notice'     => __( 'Notice:', 'oxygen' ),
		);
	}

	/**
	 *  Oxygen API Document Types Names
	 *
	 *  @return array
	 */
	public static function document_type_names_box() {

		return array(
			'0'          => __( 'Select document type', 'oxygen' ),
			'apy'        => __( 'Receipt of Service', 'oxygen' ),
			'alp'        => __( 'Receipt of Goods', 'oxygen' ),
			'tpy'        => __( 'Invoice of Service', 'oxygen' ),
			'tpda'       => __( 'Invoice of Goods/Shipping', 'oxygen' ),
			'tpda_intra' => __( 'Invoice of Goods/Intra-Community Shipping', 'oxygen' ),
			'tpy_intra'  => __( 'Invoice of Service/Intra-Community Service', 'oxygen' ),
		);
	}

	/**
	 *  Oxygen API myData Document Types
	 *
	 *  @return array
	 */
	public static function mydata_document_types() {

		return array(

			'tpy'        => '2.1',
			'tpda'       => '1.1',
			'tpy_intra'  => '2.2',
			'tpda_intra' => '1.2',
			'apy'        => '11.2',
			'alp'        => '11.1',
			'notice'     => 'notice',
		);
	}


	/**
	 * Returns the list of available MyData classification categories used by the Oxygen API.
	 *
	 * If an index is provided, returns only the matching classification category.
	 *
	 * @param string|null $index Optional. Specific category key to return.
	 * @return array Returns the full array of classification categories, or a single category if index is provided and found.
	 */
	public static function mydata_classification_categories( $index = null ): array {

		$categories = array(
			'0'           => __( 'Select Category', 'oxygen' ),
			'category1_1' => 'category1_1 - Έσοδα από Πώληση Εμπορευμάτων',
			'category1_2' => 'category1_2 - Έσοδα από Πώληση Προϊόντων',
			'category1_3' => 'category1_3 - Έσοδα από Παροχή Υπηρεσιών',
		);

		if ( ! empty( $index ) ) {
			return array(
				'0'    => __( 'Select Category', 'oxygen' ),
				$index => $categories[ $index ],
			);
		}
		return $categories;
	}

	/**
	 *  Oxygen API myData Classification Types
	 *
	 *  @return array
	 */
	public static function mydata_classification_types_receipts() {

		return array(
			'0'          => __( 'Select Type', 'oxygen' ),
			'E3_561_003' => 'E3_561_003 - Πωλήσεις αγαθών και υπηρεσιών Λιανικές - Ιδιωτική Πελατεία',
			'E3_561_004' => 'E3_561_004 - Πωλήσεις αγαθών και υπηρεσιών Λιανικές βάσει άρθρου 39α παρ 5 του Κώδικα Φ.Π.Α. (Ν.2859/2000)',
			'E3_561_005' => 'E3_561_005 - Πωλήσεις αγαθών και υπηρεσιών Εξωτερικού Ενδοκοινοτικές',
			'E3_561_006' => 'E3_561_006 - Πωλήσεις αγαθών και υπηρεσιών Εξωτερικού Τρίτες Χώρες',
			'E3_561_007' => 'E3_561_007 - Πωλήσεις αγαθών και υπηρεσιών Λοιπά',
			'E3_562'     => 'E3_562 - Λοιπά συνήθη έσοδα',

		);
	}

	/**
	 * Returns the list of available MyData classification types for invoices used by the Oxygen API.
	 *
	 * If an index is provided, returns only the matching classification type.
	 *
	 * @param string|null $index Optional. Specific type key to return.
	 * @return array Returns the full array of classification types, or a single type if index is provided and found.
	 */
	public static function mydata_classification_types_invoices( $index = null ) {

		$types = array(
			'0'          => __( 'Select Type', 'oxygen' ),
			'E3_561_001' => 'E3_561_001 - Πωλήσεις αγαθών και υπηρεσιών Χονδρικές - Επιτηδευματιών',
			'E3_561_002' => 'E3_561_002 - Πωλήσεις αγαθών και υπηρεσιών Χονδρικές βάσει άρθρου 39α παρ 5 του Κώδικα Φ.Π.Α. (Ν.2859/2000)',
			'E3_561_005' => 'E3_561_005 - Πωλήσεις αγαθών και υπηρεσιών Εξωτερικού Ενδοκοινοτικές',
			'E3_561_007' => 'E3_561_007 - Πωλήσεις αγαθών και υπηρεσιών Λοιπά',
			'E3_562'     => 'E3_562 - Λοιπά συνήθη έσοδα',
		);

		if ( ! empty( $index ) ) {
			return array(
				'0'    => __( 'Select Type', 'oxygen' ),
				$index => $types[ $index ],
			);
		}

		return $types;
	}

	/**
	 *  Get Oxygen Numbering Sequences array.
	 *
	 *  @return array|bool of sequence data fetched by Oxygen API
	 */
	public static function oxygen_sequences_options() {

		$oxygen_get_sequences = OxygenApi::get_sequences();
		$oxygen_sequences     = array();

		if ( is_array( $oxygen_get_sequences ) && isset( $oxygen_get_sequences['code'] ) && 200 !== $oxygen_get_sequences['code'] ) {
			return false;
		}

		if ( is_array( $oxygen_get_sequences ) && isset( $oxygen_get_sequences['body'] ) && ! empty( $oxygen_get_sequences['body'] ) ) {

			$oxygen_sequences_json = json_decode( $oxygen_get_sequences['body'], true );

			foreach ( $oxygen_sequences_json['data'] as $oxygen_sequence ) {

				if ( 0 === $oxygen_sequence['status'] ) {
					continue;
				}

				$oxygen_sequences[ $oxygen_sequence['document_type'] ][ $oxygen_sequence['id'] ] = $oxygen_sequence['title'] . ' ' . $oxygen_sequence['name'] . ' ' . ( 0 === $oxygen_sequence['status'] ? ' - ' . __( 'Inactive', 'oxygen' ) : '' );

			}
		}

		return array( '0' => __( 'Select', 'oxygen' ) ) + $oxygen_sequences;
	}

	/**
	 *  Get Oxygen Tax Rates array.
	 *
	 *  @return array of tax data fetched by Oxygen API
	 */
	public static function oxygen_tax_options() {

		$oxygen_get_taxes = OxygenApi::get_taxes();
		$oxygen_taxes     = array();

		if ( is_array( $oxygen_get_taxes ) && ! empty( $oxygen_get_taxes['body'] ) ) {

			$oxygen_taxes_json = json_decode( $oxygen_get_taxes['body'], true );

			foreach ( $oxygen_taxes_json['data'] as $oxygen_tax ) {

				if ( count( $oxygen_taxes_json['data'] ) > 1 ) {

					foreach ( $oxygen_taxes_json['data'] as $item ) {

						$tax_entry = $item['title'] . ' - ' . $item['rate'];

						if ( ! empty( $item['mydata_vat_exemption_category'] ) ) {
							$tax_exemption = $item['mydata_vat_exemption_category'];
							$tax_entry    .= ' - Κατηγορία εξαίρεσης ΦΠΑ ' . $tax_exemption;
						}
						// Store the tax in the array.
						$oxygen_taxes[ $item['id'] ] = $tax_entry;
					}
				} else {

					$oxygen_taxes[ $oxygen_tax['id'] ] = $oxygen_tax['title'] . ' - ' . $oxygen_tax['rate'];

					if ( ! empty( $oxygen_tax['mydata_vat_exemption_category'] ) ) {
						$tax_exemption                      = $oxygen_tax['mydata_vat_exemption_category'];
						$oxygen_taxes[ $oxygen_tax['id'] ] .= ' - Κατηγορία εξαίρεσης ΦΠΑ ' . $tax_exemption;

					}
				}
			}
		}

		return array( '0' => __( 'Select', 'oxygen' ) ) + $oxygen_taxes;
	}

	/**
	 *  Get all WooCommerce Tax Rates array.
	 *
	 *  @return array Taxes data
	 */
	public static function woo_tax_rates() {

		$all_tax_rates = array();

		$tax_classes = WC_Tax::get_tax_classes(); // Retrieve all tax classes.
		if ( ! in_array( '', $tax_classes ) ) { // Make sure "Standard rate" (empty class name) is present.
			array_unshift( $tax_classes, '' );
		}
		foreach ( $tax_classes as $tax_class ) { // For each tax class, get all rates.
			$taxes         = WC_Tax::get_rates_for_tax_class( $tax_class );
			$all_tax_rates = array_merge( $all_tax_rates, $taxes );
		}

		return $all_tax_rates;
	}


	/**
	 *  Get Oxygen remote logos array.
	 *
	 *  @return array of logos data fetched by Oxygen API
	 */
	public static function get_logos() {

		$logos          = OxygenApi::get_logos();
		$logos_settings = array();

		if ( empty( $logos ) ) {
			return array();
		}

		if ( is_array( $logos ) ) {

			foreach ( $logos as $logo ) {

				if ( is_array( $logo ) && isset( $logo['id'] ) ) {
					$logos_settings[ $logo['id'] ] = $logo['title'] ." - ".$logo['language'];
				}
			}
		}

		return $logos_settings;
	}

	/**
	 *  Get Oxygen default logo id.
	 *
	 *  @return string | false the default logo id or false if not set
	 */
	public static function get_default_logo_id() {

		$logos = OxygenApi::get_logos();

		if ( empty( $logos ) || ! is_array( $logos ) ) {
			return false;
		}

		$default = array_search( true, array_column( $logos, 'is_default' ) );

		if ( false === $default ) {
			return false;
		}

		return $logos[ $default ]['id'];
	}

	/**
	 *  Get Oxygen Payment Methods array.
	 *
	 *  @return array of payment methods data fetched by Oxygen API
	 */
	public static function oxygen_payment_methods() {

		$oxygen_get_payment_methods = OxygenApi::get_payment_methods();
		$oxygen_payment_methods     = array();

		if ( is_array( $oxygen_get_payment_methods ) && isset( $oxygen_get_payment_methods['code'] ) && 200 !== $oxygen_get_payment_methods['code'] ) {
			return array();
		}

		if ( is_array( $oxygen_get_payment_methods ) && isset( $oxygen_get_payment_methods['body'] ) && ! empty( $oxygen_get_payment_methods['body'] ) ) {

			$oxygen_payment_methods_json = json_decode( $oxygen_get_payment_methods['body'], true );

			foreach ( $oxygen_payment_methods_json['data'] as $oxygen_pm ) {

				if ( true !== $oxygen_pm['status'] ) {
					continue;
				}

				$oxygen_payment_methods[ $oxygen_pm['id'] ] = $oxygen_pm['title_gr'];

			}
		}

		return array( '0' => __( 'Select', 'oxygen' ) ) + $oxygen_payment_methods;
	}

	/**
	 *  Oxygen API Checks
	 */
	public static function api_checks() {

		$errors = array();

		$api_key = get_option( 'oxygen_api_key' );

		/*
		Document type i - v2+
		$oxygen_enable_simple_invoice = get_option( 'oxygen_enable_simple_invoice' );
		*/

		$oxygen_only_receipts                  = get_option( 'oxygen_only_receipts' );
		$oxygen_enable_intra_community_invoice = get_option( 'oxygen_enable_intra_community_invoice' );

		/* invoices settings tab*/

		$invoices_fields_with_errors = array(
			'oxygen_mydata_category_tpda'            => array(
				'value' => get_option( 'oxygen_mydata_category_tpda' ),
				'error' => __( 'myDATA Category for Invoice of Goods/Shipping is empty.', 'oxygen' ),
			),
			'oxygen_mydata_tpda_classification_type' => array(
				'value' => get_option( 'oxygen_mydata_tpda_classification_type' ),
				'error' => __( 'myDATA Classification Type for Invoice of Goods/Shipping is empty.', 'oxygen' ),
			),
			'oxygen_mydata_category_tpy'             => array(
				'value' => get_option( 'oxygen_mydata_category_tpy' ),
				'error' => __( 'myDATA classification Category for Invoice of Service is empty.' ),
			),
			'oxygen_mydata_tpy_classification_type'  => array(
				'value' => get_option( 'oxygen_mydata_tpy_classification_type' ),
				'error' => __( 'myDATA classification Type for Invoice of Service is empty.' ),
			),
			'oxygen_num_sequencetpy'                 => array(
				'value' => get_option( 'oxygen_num_sequence_tpy' ),
				'error' => __( 'Document Series for Invoice of Service has not been set. If you don’t set it, then all invoices will be created without one.' ),
			),
			'oxygen_num_sequencetpda'                => array(
				'value' => get_option( 'oxygen_num_sequence_tpda' ),
				'error' => __( 'Document Series for Invoice of Goods/Shipping has not been set. If you don’t set it, then all invoices will be created without one.' ),
			),
		);

		if ( 'yes' !== $oxygen_only_receipts ) { /* an exei epilexei mono receipta den mas noiazoun invoices errors*/
			self::process_errors( $invoices_fields_with_errors, $errors, 'invoices' );
		}

		/* END invoices settings tab */

		$receipts_fields_with_errors = array(
			'oxygen_mydata_category_receipt_alp'    => array(
				'value' => get_option( 'oxygen_mydata_category_receipt_alp' ),
				'error' => __( 'myDATA classification Category for Receipt of Goods is empty.' ),
			),
			'oxygen_mydata_classification_type_alp' => array(
				'value' => get_option( 'oxygen_mydata_classification_type_alp' ),
				'error' => __( 'myDATA classification Type for Receipt of Goods is empty.' ),
			),
			'oxygen_mydata_category_receipt_apy'    => array(
				'value' => get_option( 'oxygen_mydata_category_receipt_apy' ),
				'error' => __( 'myDATA classification Category for Receipt of Service is empty.' ),
			),
			'oxygen_mydata_classification_type_apy' => array(
				'value' => get_option( 'oxygen_mydata_classification_type_apy' ),
				'error' => __( 'myDATA classification Type for Receipt of Service is empty.' ),
			),
			'oxygen_num_sequenceapy'                => array(
				'value' => get_option( 'oxygen_num_sequence_apy' ),
				'error' => __( 'Document Series for Receipt of Service has not been set. If you don’t set it, then all invoices will be created without one.' ),
			),
			'oxygen_num_sequencealp'                => array(
				'value' => get_option( 'oxygen_num_sequence_alp' ),
				'error' => __( 'Document Series for Receipt of Goods has not been set. If you don’t set it, then all invoices will be created without one.' ),
			),
		);
		self::process_errors( $receipts_fields_with_errors, $errors, 'receipts' );

		/* END receipts */

		$intra_fields_with_errors = array(
			'oxygen_endokoinotiko_invoice_category_pwlisis' => array(
				'value' => get_option( 'oxygen_mydata_category_tpda_intra' ),
				'error' => __( 'myDATA classification Category for Invoice of Goods/Intra-Community Shipping is empty.' ),
			),
			'oxygen_endokoinotiko_classification_type_pwlisis' => array(
				'value' => get_option( 'oxygen_mydata_classification_type_tpda_intra' ),
				'error' => __( 'myDATA classification Type for Invoice of Goods/Intra-Community Shipping is empty.' ),
			),
			'oxygen_endokoinotiko_invoice_category_paroxis' => array(
				'value' => get_option( 'oxygen_mydata_category_tpy_intra' ),
				'error' => __( 'myDATA classification Category for Invoice of Service/Intra-Community Services is empty.' ),
			),
			'oxygen_endokoinotiko_classification_type_paroxis' => array(
				'value' => get_option( 'oxygen_mydata_classification_type_tpy_intra' ),
				'error' => __( 'myDATA classification Type for Invoice of Service/Intra-Community Services is empty.' ),
			),
			'oxygen_intra_community_tax_invoices' => array(
				'value' => get_option( 'oxygen_intra_community_tax_invoices' ),
				'error' => __( 'No Tax selected for Intra-Community Invoices.' ),
			),
		);
		if ( 'yes' === $oxygen_enable_intra_community_invoice && 'no' === $oxygen_only_receipts ) {
			self::process_errors( $intra_fields_with_errors, $errors, 'intra' );
		}


		if ( empty( $api_key ) ) {
			$errors['api_key_error'] = esc_attr__( 'Enter your api key to complete the settings.', 'oxygen' );
		} elseif ( isset( $errors['api_key_error'] ) ) {
				unset( $errors['api_key_error'] );
		}


		if ( ! empty( $errors ) ) {
			set_transient( 'oxygen_api_errors', $errors, '20' ); // Store errors for 20 seconds.
			foreach ( $errors as $error ) {
				echo '<div class="notice notice-error is-dismissible">';
				echo '<p>' . esc_html( $error ) . '</p>';
				echo '</div>';
			}
			delete_transient( 'oxygen_api_errors' );
		} else {
			delete_transient( 'oxygen_api_errors' );
		}
	}

	/**
	 * Processes form field errors and updates the `$errors` array with messages.
	 *
	 * Checks each field's value and adds an error message if the value is '0'.
	 * If the value is not '0', any existing error for that field is removed.
	 *
	 * @param array  $fields_with_errors    Associative array of field keys and their values with 'value' and 'error' keys.
	 * @param array  &$errors    Reference to the array that collects error messages.
	 * @param string $type  The type of validation context (unused but reserved for future use).
	 *
	 * @return void
	 */
	public static function process_errors( $fields_with_errors, &$errors, $type ) {


		foreach ( $fields_with_errors as $key => $data ) {
			if ( '0' === $data['value'] ) { // Check if the value is '0'.
				$error = $data['error'];
				$errors[ $key . '_error' ] = esc_attr( __( $error, 'oxygen' ) );// phpcs:ignore
			} else {
				unset( $errors[ $key . '_error' ] );
			}
		}
	}


	/**
	 *  Oxygen Debug
	 *
	 *  @param array  $log Array of strings to log.
	 *  @param string $type String of log type.
	 *
	 *  @return void
	 */
	public static function debug( $log = array(), $type = 'error' ) {

		if ( 'yes' === get_option( 'oxygen_debug' ) && function_exists( 'wc_get_logger' ) && ( is_array( $log ) && ! empty( $log ) ) ) {

			$logger = wc_get_logger();

			foreach ( $log as $l ) {

				$log_string = print_r( $l, true );

				if ( 'info' === $type ) {

					$logger->info( $log_string, array( 'source' => 'oxygen' ) );

				} elseif ( 'alert' === $type ) {

					$logger->alert( $log_string, array( 'source' => 'oxygen' ) );

				} elseif ( 'notice' === $type ) {

					$logger->notice( $log_string, array( 'source' => 'oxygen' ) );

				} elseif ( 'debug' === $type ) {

					$logger->debug( $log_string, array( 'source' => 'oxygen' ) );

				} elseif ( 'emergency' === $type ) {

					$logger->emergency( $log_string, array( 'source' => 'oxygen' ) );

				} elseif ( 'critical' === $type ) {

					$logger->critical( $log_string, array( 'source' => 'oxygen' ) );

				} elseif ( 'warning' === $type ) {

					$logger->warning( $log_string, array( 'source' => 'oxygen' ) );

				} else {

					$logger->error( $log_string, array( 'source' => 'oxygen' ) );
				}
			}
		}
	}

	/**
	 * Retrieves all Oxygen plugin settings.
	 *
	 * This method collects and returns an associative array of all settings used by the Oxygen plugin,
	 * including API keys, configuration options, and enabled features. It is commonly used for exporting
	 * settings or debugging.
	 *
	 * @return string JSON-encoded settings array.
	 */
	public static function retrieve_oxygen_settings() {
		// Retrieve the settings.
		$settings = array(
			'ALP - MYDATA CATEGORY'                       => get_option( 'oxygen_mydata_category_receipt_alp' ),
			'ALP - MYDATA TYPE'                           => get_option( 'oxygen_mydata_classification_type_alp' ),
			'ALP - default'                               => get_option( 'oxygen_default_receipt_alp' ),
			'APY - MYDATA CATEGORY'                       => get_option( 'oxygen_mydata_category_receipt_apy' ),
			'APY - MYDATA TYPE'                           => get_option( 'oxygen_mydata_classification_type_apy' ),
			'APY - default'                               => get_option( 'oxygen_default_receipt_apy' ),
			'PRINT TYPE RECEIPTS'                         => get_option( 'oxygen_receipt_print_type' ),
			'TPDA - MYDATA CATEGORY'                      => get_option( 'oxygen_mydata_category_tpda' ),
			'TPDA - MYDATA TYPE'                          => get_option( 'oxygen_mydata_tpda_classification_type' ),
			'TPDA - default'                              => get_option( 'oxygen_default_invoice_tpda' ),
			'TPY - MYDATA CATEGORY'                       => get_option( 'oxygen_mydata_category_tpy' ),
			'TPY - MYDATA TYPE'                           => get_option( 'oxygen_mydata_tpy_classification_type' ),
			'TPY - default'                               => get_option( 'oxygen_default_invoice_tpy' ),
			'USE PLUGIN S FIELDS ON CHECKOUT FOR INVOICE' => get_option( 'oxygen_self_fields' ),
			'VAT'                                         => get_option( 'oxygen_vat_metakey' ),
			'JOB'                                         => get_option( 'oxygen_working_field_metakey' ),
			'TAX OFFICE'                                  => get_option( 'oxygen_tax_office' ),
			'CREATE INVOICE WHEN THIS FIELD IS SELECTED'  => get_option( 'oxygen_issue_invoice_metakey' ),
			'VIES'                                        => get_option( 'oxygen_fetch_vat_fields' ),
			'INTRA COMMUNITY 1.2 - CATEGORY'              => get_option( 'oxygen_endokoinotiko_invoice_category_pwlisis' ),
			'INTRA COMMUNITY 1.2 - TYPE'                  => get_option( 'oxygen_endokoinotiko_classification_type_pwlisis' ),
			'INTRA COMMUNITY 1.2 - default'               => get_option( 'oxygen_default_intra_sell' ),
			'INTRA COMMUNITY 2.2 - CATEGORY'              => get_option( 'oxygen_endokoinotiko_invoice_category_paroxis' ),
			'INTRA COMMUNITY 2.2 - TYPE'                  => get_option( 'oxygen_endokoinotiko_classification_type_paroxis' ),
			'INTRA COMMUNITY 2.2 - default'               => get_option( 'oxygen_default_intra_paroxis' ),
			'LOGO'                                        => get_option( 'oxygen_logo' ),
			'DOCUMENT LANGUAGE'                           => get_option( 'oxygen_language' ),
			'SHIPPING CODE'                               => get_option( 'oxygen_shipping_code' ),
			'ATTACH DOCUMENT ON EMAILS'                   => get_option( 'oxygen_order_attachment' ),
			'AUTO CREATION ON THIS ORDER STATUS'          => get_option( 'oxygen_order_status' ),
			'VARIATIONS - USE PARENT SKU'                 => get_option( 'oxygen_products_variations' ),
			'ORDER STATUS AFTER OXYGEN PAYMENTS'          => get_option( 'oxygen_payment_order_status' ),
			'PAYMENT WAY - default'                       => get_option( 'oxygen_payment_default' ),
			'API KEY'                                     => get_option( 'oxygen_api_key' ),
			'ENVIRONMENT'                                 => get_option( 'oxygen_status' ),
			/* document type i ( xwris stoixeia diakinisis ) - v2+  'USE INVOICE TYPE (i)' => get_option('oxygen_enable_simple_invoice'),*/
			'USE ONLY RECEIPTS'                           => get_option( 'oxygen_only_receipts' ),
			'USE INTRA COMMUNITY DOCUMENTS'               => get_option( 'oxygen_enable_intra_community_invoice' ),
			'DEBUG'                                       => get_option( 'oxygen_debug' ),
		);

		return json_encode( $settings, JSON_PRETTY_PRINT );
	}


	/**
	 * Finds the most recent Oxygen log file.
	 *
	 * Scans the WooCommerce log directory for log files related to the Oxygen plugin
	 * and returns the most recently modified one.
	 *
	 * @return string|null The name of the most recent log file, or null if none found.
	 */
	public static function find_most_recent_oxygen_log() {

		if ( ! defined( 'WC_LOG_DIR' ) ) {
			define( 'WC_LOG_DIR', WP_CONTENT_DIR . '/uploads/wc-logs/' );
		}

		// Define the path to WooCommerce log files.
		$log_dir = WC_LOG_DIR;

		// Define the pattern to match files that start with 'oxygen-'.
		$file_pattern = $log_dir . 'oxygen-*';

		// Get only the files that start with 'oxygen-'.
		$log_files = glob( $file_pattern );

		// Initialize a variable to store the most recent file.
		$most_recent_file = null;
		$most_recent_time = 0;

		// Iterate through the log files and find the most recent match.
		foreach ( $log_files as $file ) {
			$file_time = filemtime( $file ); // Get the last modification time.
			if ( $file_time > $most_recent_time ) {
				$most_recent_time = $file_time;
				$most_recent_file = $file;
			}
		}

		// If a file is found, return its URL.
		if ( $most_recent_file ) {
			return $most_recent_file;
		}

		$log = array( '----------------- no oxygen log file found ----------------', $most_recent_file );
		self::debug( $log , 'debug');
		return false;
	}

	/**
	 * Removes specific settings from the settings array based on given IDs.
	 *
	 * Iterates through the provided settings array and excludes any setting
	 * whose ID exists in the $ids_to_remove array.
	 *
	 * @param array $settings       The full list of settings.
	 * @param array $ids_to_remove  The setting IDs to be removed.
	 *
	 * @return array Filtered settings array without the specified IDs.
	 */
	public static function remove_settings_by_ids( $settings, $ids_to_remove ): array {

		foreach ( $settings as $key => $setting ) {
			// Check if 'id' exists and matches any of the IDs in the array.
			if ( isset( $setting['id'] ) && in_array( $setting['id'], $ids_to_remove, true ) ) {
				unset( $settings[ $key ] );
			}
		}
		// Reindex the array (optional, if needed).
		return array_values( $settings );
	}

	/**
	 *  Get the customer billing VAT data by order ID.
	 *
	 *  @param integer $order_id the WC order ID.
	 *
	 *  @return array|false
	 */
	public static function get_billing_vat_info( int $order_id ) {

		$order = wc_get_order( $order_id );

		if ( ! $order_id ) {
			self::debug( 'Invalid order ID' );
			return false;
		} else {
			self::debug( array( 'Order id is ' . $order_id ) , 'debug');
		}

		if ( 'yes' === get_option( 'oxygen_self_fields' ) ) {

			$billing_vat        = $order->get_meta( '_billing_vat', true );
			$billing_job        = $order->get_meta( '_billing_job', true );
			$billing_tax_office = $order->get_meta( '_billing_tax_office', true );
			$billing_invoice    = $order->get_meta( '_billing_invoice', true );
			$billing_company    = $order->get_billing_company();

		} else {

            $oxygen_vat_metakey           = get_option( 'oxygen_vat_metakey' );
            $oxygen_working_field_metakey = get_option( 'oxygen_working_field_metakey' );
            $oxygen_tax_office_metakey    = get_option( 'oxygen_tax_office' );
            $oxygen_issue_invoice_metakey = get_option( 'oxygen_issue_invoice_metakey' );

            self::debug( array( 'In get_billing_vat_info fields names are: ' . $oxygen_vat_metakey . ', Job: ' . $oxygen_working_field_metakey . ', Tax Office: ' . $oxygen_tax_office_metakey . ', Invoice: ' . $oxygen_issue_invoice_metakey ) , 'debug');

            $billing_vat = $oxygen_vat_metakey
                ? (string) ( $order->get_meta( '_' . $oxygen_vat_metakey, true ) ?: $order->get_meta( $oxygen_vat_metakey, true ) )
                : '';

            $billing_job = $oxygen_working_field_metakey
                ? (string) ( $order->get_meta( '_' . $oxygen_working_field_metakey, true ) ?: $order->get_meta( $oxygen_working_field_metakey, true ) )
                : '';

            $billing_tax_office = $oxygen_tax_office_metakey
                ? (string) ( $order->get_meta( '_' . $oxygen_tax_office_metakey, true ) ?: $order->get_meta( $oxygen_tax_office_metakey, true ) )
                : '';

            $billing_invoice_raw = $oxygen_issue_invoice_metakey ? (string) ( $order->get_meta( '_' . $oxygen_issue_invoice_metakey, true ) ?: $order->get_meta( $oxygen_issue_invoice_metakey, true ) )
                : '';

            $billing_invoice     = (
                $billing_invoice_raw === 'Y' || $billing_invoice_raw === 'y' ||
                $billing_invoice_raw === 'yes' || $billing_invoice_raw === 'on' ||
                $billing_invoice_raw == 1
            ) ? '1' : '0';

            $billing_company    = (string) $order->get_billing_company();
		}

		self::debug( array( 'In get_billing_vat_info - Billing VAT: ' . $billing_vat . ', Job: ' . $billing_job . ', Tax Office: ' . $billing_tax_office . ', Invoice: ' . $billing_invoice . ', Company: ' . $billing_company ) , 'debug');

		if ( empty( $billing_vat ) ) {
			$billing_vat = $order->get_meta( '_billing_vat', true );
		}
		if ( empty( $billing_job ) ) {
			$billing_job = $order->get_meta( '_billing_job', true );
		}
		if ( empty( $billing_tax_office ) ) {
			$billing_tax_office = $order->get_meta( '_billing_tax_office', true );
		}
		if ( empty( $billing_invoice ) ) {
			$billing_invoice = !empty( $order->get_meta( '_billing_invoice', true ) ) ? $order->get_meta( '_billing_invoice', true ) : $order->get_meta( 'billing_invoice', true );
		}

		if ( (1 === $billing_invoice || '1' === $billing_invoice) && ! empty( $billing_vat ) && ! empty( $billing_job ) && ! empty( $billing_invoice ) && ! empty( $billing_company ) ) {

			$info = array(
				'billing_vat'        => $billing_vat,
				'billing_job'        => $billing_job,
				'billing_tax_office' => $billing_tax_office,
				'billing_invoice'    => $billing_invoice,
				'billing_company'    => $billing_company,
			);

			self::debug( array( '----------------- TPDA OR TPY -----------------' ) , 'debug');

			return $info;

		} else {
			$missing_fields = array();

			if ( 0 === $billing_invoice || '0' === $billing_invoice || '' === $billing_invoice ) {
				$info = array(
					'billing_vat'        => '',
					'billing_job'        => '',
					'billing_tax_office' => '',
					'billing_invoice'    => 0,
					'billing_company'    => '',
				);

				$doc_key = '';
				if ( isset( $_GET['_oxygen_payment_note_type'] ) && ! empty( $_GET['_oxygen_payment_note_type'] ) ) {
					$doc_key = sanitize_text_field( wp_unslash( $_GET['_oxygen_payment_note_type'] ) );
				}

				if ( 'tpda_intra' === $doc_key || 'tpy_intra' === $doc_key || 'tpy' === $doc_key || 'tpda' === $doc_key ) {

					foreach ( $info as $key => $value ) {
						if ( empty( $value ) ) {
							$missing_fields[] = $key;
						}
					}

					if ( empty( $billing_vat ) || empty( $billing_job ) || empty( $billing_tax_office ) || empty( $billing_invoice ) || empty( $billing_company ) ) {
						self::debug( array( '----------------- Missing VAT info -----------------', json_encode( $info ) ) );
						WC_Admin_Notices::add_custom_notice( 'oxygen_vat_info_error', '<p class="oxygen_error">' . __( 'One or more fields mandatory for invoice creation are empty.', 'oxygen' ) . '  -  ' . json_encode( $missing_fields ) . '</p>' );
					}
				}

				self::debug( array( '----------------- ALP OR APY -----------------' ) , 'debug');
				return $info;

			} else {
				$info = array(
					'billing_vat'        => $billing_vat,
					'billing_job'        => $billing_job,
					'billing_tax_office' => $billing_tax_office,
					'billing_invoice'    => $billing_invoice,
					'billing_company'    => $billing_company,
				);

				// Check for missing fields.
				foreach ( $info as $key => $value ) {
					if ( empty( $value ) ) {
						$missing_fields[] = $key;
					}
				}

				if ( empty( $billing_vat ) || empty( $billing_job ) || empty( $billing_tax_office ) || empty( $billing_invoice ) || empty( $billing_company ) ) {
					self::debug( array( '----------------- Missing VAT info -----------------', json_encode( $info ) ) );
					WC_Admin_Notices::add_custom_notice( 'oxygen_vat_info_error', '<p class="oxygen_error">' . __( 'One or more fields mandatory for invoice creation are empty.', 'oxygen' ) . '  -  ' . json_encode( $missing_fields ) . '</p>' );

				}
			}
		}

		return false;
	}

	/**
	 *  Create new contact
	 *
	 *  @param object     $order WC_Order.
	 *  @param array|bool $get_billing_vat_info billing info.
	 *  @return array|boolean
	 */
	public static function create_new_contact( object $order, $get_billing_vat_info ) {

		$log = array( '----------------- START CREATING NEW CONTACT -----------------' );
		self::debug( $log , 'debug');

		$billing_invoice    = get_post_meta( $order->get_id(), '_billing_invoice', true );
		$billing_vat        = false;
		$billing_job        = false;
		$billing_tax_office = false;
		$customer_type      = 1;

		if ( $get_billing_vat_info ) {

			$billing_vat        = $get_billing_vat_info['billing_vat'];
			$billing_job        = $get_billing_vat_info['billing_job'];
			$billing_tax_office = $get_billing_vat_info['billing_tax_office'];
			$billing_invoice    = $get_billing_vat_info['billing_invoice'];

			// set costumer type to 2 ONLY if all values are set.
			if ( ! empty( $billing_vat ) && ! empty( $order->get_billing_company() ) ) {

				$log = array( '---- billing vat & billing company is ----', $billing_vat, $order->get_billing_company() );
				self::debug( $log , 'debug');
				$customer_type = 2;
			}
		}

		$address_street   = '';
		$address_number   = '0';
		$checkout_address = $order->get_billing_address_1();

		if ( ! empty( $checkout_address ) ) {

			if ( preg_match( '/^(\d+\s+[^\d]+)\s+\d+$/', $checkout_address, $match_street ) ) { /* letters and numbers between */
				$address_street = trim( $match_street[1] );

			} elseif ( strpos( $checkout_address, ',' ) !== false ) { /* comma between example Θερίσου , 28 */

				$parts          = explode( ',', $checkout_address ); // Split at the comma.
				$address_street = trim( $parts[0] );

				if ( count( $parts ) > 1 && ! is_numeric( $parts[1] ) ) {
					$address_street = trim( $parts[0] ) . ' ' . trim( $parts[1] );

					$only_text = preg_replace( '/\d+/', '', $address_street );
					if ( $only_text ) {
						$address_street = trim( $only_text );
					}
				}

				if ( preg_match( '/^[^\d]+/', $address_street, $matches ) ) {
					$address_street = trim( $matches[0] );
				}

				if ( is_numeric( trim( $parts[1] ) ) ) {
					$address_number = trim( $parts[1] );
				}
			} elseif ( preg_match( '/^(.*)\s+(\d+\s*[A-Za-zΑ-Ωα-ω]*)$/u', $checkout_address, $matches ) ) { /* gets only string first part of an address */
				$address_street = trim( $matches[1] );

				if ( preg_match( '/\s\d+\s*[A-Za-z]?\b/', $checkout_address, $matches ) ) {
					$address_number = trim( $matches[0] ); // Extracted number.
				}
			} else {
				$address_street = trim( $checkout_address ); // Letters only with spaces.
			}

			if ( preg_match( '/\d+$/', $checkout_address, $match_number ) ) { /* gets only number at the end of an address */
				$address_number = trim( $match_number[0] );
			}
		} else {
			self::debug( array( 'Billing address 1 is empty.' ) , 'debug');
		}

		self::debug( array( 'Address for new contact is street : ' . $address_street . ' and number : ' . $address_number ) , 'debug');

		$contact_args = array_filter(
			array(
				'code'         => '',
				'type'         => $customer_type,
				'is_client'    => true,
				'name'         => $order->get_billing_first_name(),
				'surname'      => $order->get_billing_last_name(),
				'company_name' => '1' === $billing_invoice ? $order->get_billing_company() : '',
				'profession'   => $billing_job,
				'vat_number'   => $billing_vat,
				'tax_office'   => $billing_tax_office,
				'telephone'    => $order->get_billing_phone(),
				'mobile'       => $order->get_billing_phone(),
				'email'        => $order->get_billing_email(),
				'street'       => $address_street,
				'number'       => $address_number,
				'city'         => $order->get_billing_city(),
				'zip_code'     => $order->get_billing_postcode(),
				'country'      => $order->get_billing_country(),
			)
		);

		if ( empty( $billing_vat ) ) {
			unset( $contact_args['vat_number'] );
		}

		$contact_args['is_supplier'] = false;
		$contact                     = json_decode( OxygenApi::add_contact( $contact_args ), true );

		$log = array( '----------------- CONTACT IS -----------------', $contact );
		self::debug( $log , 'info');

		if ( ! is_array( $contact ) || ! isset( $contact['id'] ) ) {

			WC_Admin_Notices::add_custom_notice( 'oxygen_contact_error', '<p>' . __( 'Could not create contact', 'oxygen' ) . '</p>' );

			if ( ! empty( $contact['errors'] ) ) {
				// Collect all error messages.
				$error_messages = array();
				foreach ( $contact['errors'] as $field => $messages ) {
					foreach ( $messages as $message ) {
						$error_messages[] = $message;
					}
				}
				$errors_html = implode( ' | ', $error_messages );
				// Add the notice using WC_Admin_Notices.
				WC_Admin_Notices::add_custom_notice( 'oxygen_contact_error', '<p><strong>' . __( 'The following errors were found when creating a new contact:', 'oxygen' ) . '</strong></p><p>' . $errors_html . '</p>' );
			}
			return false;
		}

		return $contact;
	}

	/**
	 * Format a debug message with the notetype and document key.
	 *
	 * This utility function is used to create consistent debug message strings
	 * for logging purposes within the plugin.
	 *
	 * @param string $notetype The type of document (e.g., 'invoice', 'notice').
	 * @param string $doc_key  The specific document key (e.g., 'tpda', 'tpy').
	 * @param string $message  The actual debug message content.
	 *
	 * @return string Formatted debug message string.
	 */
	public static function format_debug_message( $notetype, $doc_key, $message ) {
		return "DEBUG: {$notetype}/{$doc_key} - {$message}";
	}


	/**
	 * Select contact id for invoice/notice
	 *
	 * @param string   $notetype type invoice/notice.
	 * @param string   $doc_key document key alp/tpy etc.
	 * @param int      $order_id The WC order ID.
	 * @param WC_Order $order The WooCommerce order object.
	 *
	 * @return string
	 */
	public static function select_contact_id_per_invoice_type( $notetype, $doc_key, $order, $order_id ) {

		$oxygen_customer_id   = '';
		$get_billing_vat_info = self::get_billing_vat_info( $order_id );

		if ( ( 'invoice' === $notetype || 'intra' === $notetype ) && in_array( $doc_key, array( 'tpy', 'tpda', 'tpda_intra', 'tpy_intra' ) ) ) {

			self::debug( array( self::format_debug_message( $notetype, $doc_key, "Processing invoice with doc_key '{$doc_key}'" ) ) , 'debug');

			$checkout_email = $order->get_billing_email();
			$checkout_vat   = $get_billing_vat_info['billing_vat'];

			if ( ! empty( $checkout_vat ) ) {

				$contact_by_vat = OxygenApi::get_contact_by_vat( $checkout_vat );
				self::debug( array( self::format_debug_message( $notetype, $doc_key, 'Retrieved contacts by VAT: ' . json_encode( $contact_by_vat ) ) ) , 'debug');

				if ( empty( $contact_by_vat['data'] ) ) { /* No existing contact */

					$new_contact = self::create_new_contact( $order, $get_billing_vat_info ); /* returns false in case of error */
					if ( $new_contact ) {
						$oxygen_customer_id = $new_contact['id'];
						self::debug( array( self::format_debug_message( $notetype, $doc_key, "No existing contact found by VAT. Created new contact with ID: {$oxygen_customer_id}" ) ) , 'debug');
					}
					return $oxygen_customer_id;

				} elseif ( count( $contact_by_vat['data'] ) > 1 ) {
					/* Multiple contacts for the same VAT */

						self::debug( array( self::format_debug_message( $notetype, $doc_key, "Multiple contacts found for VAT '{$checkout_vat}'" ) ) , 'debug');

					foreach ( $contact_by_vat['data'] as $item ) {
						// Check if contact type is a company.
						if ( isset( $item['type'] ) && 2 === $item['type'] ) {

							if ( ! empty( $checkout_email ) && $checkout_email !== $item['email'] && $checkout_vat !== $item['vat_number'] ) {
								/* Checkout email differs from contact's email and VAT number */

								$new_contact = self::create_new_contact( $order, $get_billing_vat_info );
								if ( $new_contact ) {
									$oxygen_customer_id = $new_contact['id'];
									self::debug( array( self::format_debug_message( $notetype, $doc_key, "Checkout email '{$checkout_email}' differs from contact's email or VAT. Created new contact with ID: {$oxygen_customer_id}" ) ) , 'debug');
								}
								return $oxygen_customer_id;

							} else { /* Contact VAT data are filled AND checkout email matches */

								$oxygen_customer_id = $item['id'];
								self::debug( array( self::format_debug_message( $notetype, $doc_key, "Existing contact found with matching VAT. Using contact ID: {$oxygen_customer_id}" ) ) , 'debug');
								return $oxygen_customer_id;
							}
						} else { /* Contact type is not 'C' */

								$new_contact = self::create_new_contact( $order, $get_billing_vat_info );
							if ( $new_contact ) {
								$oxygen_customer_id = $new_contact['id'];
								self::debug( array( self::format_debug_message( $notetype, $doc_key, "Contact type is not 'C'. Created new contact with ID: {$oxygen_customer_id}" ) ), 'debug' );
							}
								return $oxygen_customer_id;
						}
					}
				} else { /* Only one contact */

                    $existing_contact = $contact_by_vat['data'][0];

					if ( ! empty( $checkout_email ) && $checkout_email !== $existing_contact['email'] && $checkout_vat !== $existing_contact['vat_number'] ) {
						/* Checkout email differs from contact's email and VAT number */

						$new_contact = self::create_new_contact( $order, $get_billing_vat_info );
						if ( $new_contact ) {
							$oxygen_customer_id = $new_contact['id'];
							self::debug( array( self::format_debug_message( $notetype, $doc_key, "Checkout email '{$checkout_email}' differs from contact's email or VAT. Created new contact with ID: {$oxygen_customer_id}" ) ) , 'debug');
						}
						return $oxygen_customer_id;

					} else { /* Contact VAT data are filled AND checkout email matches */
                        /* TODO check for identical else update contact before get it - WCP-169*/

                        $is_identical_company = OxygenHelperFunctions::check_identical_company_data( $order_id, $contact_by_vat );

                        // If identical, just return the existing contact id
                        if ( $is_identical_company === true ) {
                            $oxygen_customer_id = $existing_contact['id'];
                            self::debug( array( self::format_debug_message( $notetype, $doc_key, "Identical company contact found. Using contact ID: {$oxygen_customer_id}" ) ) , 'info');
                            return $oxygen_customer_id;
                        }

                        // If we have differences array, try to update the contact before using it
                        if ( is_array( $is_identical_company ) && ! empty( $is_identical_company ) ) {

                            $update_contact = self::update_contact_fields_for_company( $existing_contact, $is_identical_company, $notetype, $doc_key );
                            return $update_contact ?? $existing_contact['id'];
                        }

                        // Fallback: use existing contact as-is
                        $oxygen_customer_id = $existing_contact['id'];
                        self::debug( array( self::format_debug_message( $notetype, $doc_key, "SEC - Existing contact found with matching VAT and email. Using contact ID: {$oxygen_customer_id}" ) ) , 'debug');
                        return $oxygen_customer_id;
					}
				}
			}
		} elseif ( ( 'invoice' === $notetype || 'receipt' === $notetype ) && in_array( $doc_key, array( 'alp', 'apy' ) ) ) {

			self::debug( array( self::format_debug_message( $notetype, $doc_key, "Processing ALP/APY invoice with doc_key '{$doc_key}'" ) ) , 'debug');

			$checkout_email = $order->get_billing_email();

			if ( ! empty( $checkout_email ) ) {

				self::debug( array( 'order at this point is ' . $order_id ) , 'debug');

				$is_identical = self::check_identical_contact( $order_id );
				self::debug( " -------- function execution {$is_identical}" , 'debug');

				if ( empty( $is_identical ) ) {

					$new_contact = self::create_new_contact( $order, $get_billing_vat_info );
					if ( $new_contact ) {
						$oxygen_customer_id = $new_contact['id'];
						self::debug(
							array(
								self::format_debug_message(
									$notetype,
									$doc_key,
									"Is not identical - Created new contact with ID: {$oxygen_customer_id}"
								),
							)
						);
					}
					return $oxygen_customer_id;
				} else {
					self::debug(
						array(
							self::format_debug_message(
								$notetype,
								$doc_key,
								"Is identical - return contact with ID: {$is_identical}"
							),
						)
					);
					/* epistrefei to contact_id tis epafhs poy einai tautosimh */
					return $is_identical;
				}
			} else { /* Empty checkout email */

				self::debug( array( self::format_debug_message( $notetype, $doc_key, 'Checkout email is empty. Creating new contact.' ) ) );

				$new_contact = self::create_new_contact( $order, $get_billing_vat_info );
				if ( $new_contact ) {
					$oxygen_customer_id = $new_contact['id'];
					self::debug(
						array(
							self::format_debug_message(
								$notetype,
								$doc_key,
								"Created new contact with ID: {$oxygen_customer_id}"
							),
						)
					);
				}
				return $oxygen_customer_id;
			}
		} elseif ( 'notice' === $notetype ) {

			self::debug( array( self::format_debug_message( $notetype, $doc_key, 'Processing notice.' ) ) );

			$checkout_email = $order->get_billing_email();

			if ( ! empty( $checkout_email ) ) {

				$is_identical = self::check_identical_contact( $order_id );
				self::debug( "Notice -------- if contact is identical {$is_identical}" , 'debug');

				if ( empty( $is_identical ) ) {
					$new_contact = self::create_new_contact( $order, $get_billing_vat_info );
					if ( $new_contact ) {
						$oxygen_customer_id = $new_contact['id'];
						self::debug(
							array(
								self::format_debug_message(
									$notetype,
									$doc_key,
									"Notice - Created new contact with ID: {$oxygen_customer_id}"
								),
							)
						);
					}

					return $oxygen_customer_id;
				} else {
					self::debug(
						array(
							self::format_debug_message(
								$notetype,
								$doc_key,
								"Notice - Is identical - return contact with ID: {$is_identical}"
							),
						)
					);

					/* epistrefei to contact_id tis epafhs poy einai tautosimh */
					return $is_identical;
				}
			} else {

				$new_contact = self::create_new_contact( $order, $get_billing_vat_info );
				if ( $new_contact ) {
					$oxygen_customer_id = $new_contact['id'];
					self::debug(
						array(
							self::format_debug_message(
								$notetype,
								$doc_key,
								"Notice - empty checkout email - Created new contact with ID: {$oxygen_customer_id}"
							),
						)
					);
				}

				return $oxygen_customer_id;
			}
		}

		self::debug( array( self::format_debug_message( $notetype, $doc_key, 'No conditions met. Returning empty customer ID.' ) ) );
		return $oxygen_customer_id;
	}


	/**
	 *  Helper method to allow only latin and numbers on strings
	 *
	 *  @param string $string the text to be cleaned.
	 *  @return string
	 */
	public static function clean_for_shipping( $string ) {

		$string = str_replace( ' ', '-', $string ); // Replaces all spaces with hyphens.

		return preg_replace( '/[^A-Za-z0-9\-]/', '', $string ); // Removes special chars.
	}


	/**
	 *  Returns subfix for mydata category and type
	 *
	 *  @param String $doc_key alp,apy,tpda,tpy.
	 *  @return String
	 */
	public static function find_subfix_mydata_category( $doc_key ) {

		$class_cat_subfix = '';

		switch ( $doc_key ) {
			case 'alp':
				$class_cat_subfix = '_alp';
				break;
			case 'apy':
				$class_cat_subfix = '_apy';
				break;
			case 'tpda':
				$class_cat_subfix = '_tpda';
				break;
			case 'tpy':
				$class_cat_subfix = '_tpy';
				break;
			case 'tpda_intra':
				$class_cat_subfix = '_tpda_intra';
				break;
			case 'tpy_intra':
				$class_cat_subfix = '_tpy_intra';
				break;
			default:
				$class_cat_subfix = '';
				break;
		}

		return $class_cat_subfix;
	}

	/**
	 *  Fetches product myData settings
	 *
	 *  @param int $product_id the ID of the product.
	 *  @return array
	 */
	// phpcs:disable

    public static function get_product_mydata_info( $product_id ) {

        if(!empty($product_id)) {
            $meta = get_post_meta( $product_id );
            self::debug( array( 'Product with id ' . $product_id . " has meta fields", json_encode( $meta ) ) , 'debug');

            $product_meta = array(
                'oxygen_mydata_category_tpda'                  => $meta['oxygen_mydata_cat_tpda_product_panel'] ?? '',
                'oxygen_mydata_classification_type_tpda'       => $meta['oxygen_mydata_clas_type_tpda_product_panel'] ?? '',
                'oxygen_mydata_category_tpy'                   => $meta['oxygen_mydata_cat_tpy_product_panel'] ?? '',
                'oxygen_mydata_classification_type_tpy'        => $meta['oxygen_mydata_clas_type_tpy_product_panel'] ?? '',
                'oxygen_mydata_category_alp'                   => $meta['oxygen_mydata_cat_alp_product_panel'] ?? '',
                'oxygen_mydata_classification_type_alp'        => $meta['oxygen_mydata_clas_type_alp_product_panel'] ?? '',
                'oxygen_mydata_category_apy'                   => $meta['oxygen_mydata_cat_apy_product_panel'] ?? '',
                'oxygen_mydata_classification_type_apy'        => $meta['oxygen_mydata_clas_type_apy_product_panel'] ?? '',
                'oxygen_mydata_category_tpda_intra'            => $meta['oxygen_mydata_cat_tpda_intra_product_panel'] ?? '',
                'oxygen_mydata_classification_type_tpda_intra' => $meta['oxygen_mydata_clas_type_tpda_intra_product_panel'] ?? '',
                'oxygen_mydata_category_tpy_intra'             => $meta['oxygen_mydata_cat_tpy_intra_product_panel'] ?? '',
                'oxygen_mydata_classification_type_tpy_intra'  => $meta['oxygen_mydata_clas_type_tpy_intra_product_panel'] ?? '',
            );

            if ( !empty(array_filter( $product_meta )) ) {
                self::debug( array( 'Product with id ' . $product_id . " has its own settings for invoicing, check product's settings", json_encode( $product_meta ) ) , 'debug');
                return $product_meta;
            }

            $categories = get_the_terms( $product_id, 'product_cat' );

            if ( ! empty( $categories ) && is_array( $categories ) ) {

                foreach ( $categories as $cat ) {

                    $category_meta = array(
                        'oxygen_mydata_category_tpda'       => get_term_meta( $cat->term_id, 'oxygen_mydata_cat_tpda_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_category_tpda', '' ),
                        'oxygen_mydata_classification_type_tpda' => get_term_meta( $cat->term_id, 'oxygen_mydata_clas_type_tpda_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_classification_type_tpda', '' ),
                        'oxygen_mydata_category_tpy'        => get_term_meta( $cat->term_id, 'oxygen_mydata_cat_tpy_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_category_tpy', '' ),
                        'oxygen_mydata_classification_type_tpy' => get_term_meta( $cat->term_id, 'oxygen_mydata_clas_type_tpy_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_classification_type_tpy', '' ),
                        'oxygen_mydata_category_alp'        => get_term_meta( $cat->term_id, 'oxygen_mydata_cat_alp_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_category_alp', '' ),
                        'oxygen_mydata_classification_type_alp' => get_term_meta( $cat->term_id, 'oxygen_mydata_clas_type_alp_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_classification_type_alp', '' ),
                        'oxygen_mydata_category_apy'        => get_term_meta( $cat->term_id, 'oxygen_mydata_cat_apy_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_category_apy', '' ),
                        'oxygen_mydata_classification_type_apy' => get_term_meta( $cat->term_id, 'oxygen_mydata_clas_type_apy_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_classification_type_apy', '' ),
                        'oxygen_mydata_category_tpda_intra' => get_term_meta( $cat->term_id, 'oxygen_mydata_cat_tpda_intra_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_category_tpda_intra', '' ),
                        'oxygen_mydata_classification_type_tpda_intra' => get_term_meta( $cat->term_id, 'oxygen_mydata_clas_type_tpda_intra_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_classification_type_tpda_intra', '' ),
                        'oxygen_mydata_category_tpy_intra'  => get_term_meta( $cat->term_id, 'oxygen_mydata_cat_tpy_intra_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_category_tpy_intra', '' ),
                        'oxygen_mydata_classification_type_tpy_intra' => get_term_meta( $cat->term_id, 'oxygen_mydata_clas_type_tpy_intra_product_panel_cat_taxonomy', true ) ?? get_option( 'oxygen_mydata_classification_type_tpy_intra', '' ),
                    );
                    // phpcs:enable WordPress.CodeStyle.ShortTernary.Found

                    if ( !empty( array_filter( $category_meta )) ) {
                        self::debug( array( 'Product with id ' . $product_id . " has its own settings for invoicing in category '.$cat->term_id.' ,check category's settings" ) , 'debug');
                        return $category_meta;
                    }
                }
            }
        }

        return array(
            'oxygen_mydata_category_tpda'                  => get_option( 'oxygen_mydata_category_tpda', true ) ?? '',
            'oxygen_mydata_classification_type_tpda'       => get_option( 'oxygen_mydata_classification_type_tpda', true ) ?? '',
            'oxygen_mydata_category_tpy'                   => get_option( 'oxygen_mydata_category_tpy', true ) ?? '',
            'oxygen_mydata_classification_type_tpy'        => get_option( 'oxygen_mydata_classification_type_tpy', true ) ?? '',
            'oxygen_mydata_category_alp'                   => get_option( 'oxygen_mydata_category_alp', true ) ?? '',
            'oxygen_mydata_classification_type_alp'        => get_option( 'oxygen_mydata_classification_type_alp', true ) ?? '',
            'oxygen_mydata_category_apy'                   => get_option( 'oxygen_mydata_category_apy', true ) ?? '',
            'oxygen_mydata_classification_type_apy'        => get_option( 'oxygen_mydata_classification_type_apy', true ) ?? '',
            'oxygen_mydata_category_tpda_intra'            => get_option( 'oxygen_mydata_category_tpda_intra', true ) ?? '',
            'oxygen_mydata_classification_type_tpda_intra' => get_option( 'oxygen_mydata_classification_type_tpda_intra', true ) ?? '',
            'oxygen_mydata_category_tpy_intra'             => get_option( 'oxygen_mydata_category_tpy_intra', true ) ?? '',
            'oxygen_mydata_classification_type_tpy_intra'  => get_option( 'oxygen_mydata_classification_type_tpy_intra', true ) ?? '',
        );

    }
	// phpcs:enable

	/**
	 * Retrieve the default document-related plugin options.
	 *
	 * This method returns an array of default option values used for various
	 * document settings such as receipts, invoices, and notices.
	 *
	 * @return array Associative array of default Oxygen document options.
	 */
	public static function get_default_option_documents() {

		$oxygen_default_receipt_doctype = '';

		if ( get_option( 'oxygen_default_receipt_type' ) === 'alp' ) {
			$oxygen_default_receipt_doctype = 'alp';
		} elseif ( get_option( 'oxygen_default_receipt_type' ) === 'apy' ) {
			$oxygen_default_receipt_doctype = 'apy';
		}

		$oxygen_default_invoice_doctype = '';

		if ( get_option( 'oxygen_default_invoice_type' ) === 'tpda' ) {
			$oxygen_default_invoice_doctype = 'tpda';
		} elseif ( get_option( 'oxygen_default_invoice_type' ) === 'tpy' ) {
			$oxygen_default_invoice_doctype = 'tpy';
		}

		$oxygen_default_intra_doctype = '';

		if ( get_option( 'oxygen_default_intra_type' ) === 'tpda_intra' ) {
			$oxygen_default_intra_doctype = 'tpda_intra';
		} elseif ( get_option( 'oxygen_default_intra_type' ) === 'tpy_intra' ) {
			$oxygen_default_intra_doctype = 'tpy_intra';
		}

		return array(
			'oxygen_default_receipt_doctype' => $oxygen_default_receipt_doctype,
			'oxygen_default_invoice_doctype' => $oxygen_default_invoice_doctype,
			'oxygen_default_intra_doctype'   => $oxygen_default_intra_doctype,
		);
	}

	/**
	 *  Check for duplicate contact by email address on checkout
	 *
	 *  @param array $order_id WC_Order.
	 *
	 *  @return string response
	 */
	public static function check_identical_contact( $order_id ) {

		$order = wc_get_order( $order_id );

		self::debug( array( $order . '------------check_identical_contact ----------' ) , 'debug');

		if ( $order ) {

			$checkout_fields  = array();
			$address_number   = '0';
			$address_street   = '';
			$checkout_address = $order->get_billing_address_1();

			if ( ! empty( $checkout_address ) ) {

				if ( preg_match( '/^(\d+\s+[^\d]+)\s+\d+$/', $checkout_address, $match_street ) ) { /* letters and numbers between */
					$address_street = trim( $match_street[1] );

				} elseif ( strpos( $checkout_address, ',' ) !== false ) { /* comma between example Θερίσου , 28 */

					$parts          = explode( ',', $checkout_address ); // Split at the comma.
					$address_street = trim( $parts[0] );

					if ( count( $parts ) > 1 && ! is_numeric( $parts[1] ) ) {
						$address_street = trim( $parts[0] ) . ' ' . trim( $parts[1] );

						$only_text = preg_replace( '/\d+/', '', $address_street );
						if ( $only_text ) {
							$address_street = trim( $only_text );
						}
					}

					if ( preg_match( '/^[^\d]+/', $address_street, $matches ) ) {
						$address_street = trim( $matches[0] );
					}

					if ( is_numeric( trim( $parts[1] ) ) ) {
						$address_number = trim( $parts[1] );
					}
				} elseif ( preg_match( '/^(.*)\s+(\d+\s*[A-Za-zΑ-Ωα-ω]*)$/u', $checkout_address, $matches ) ) { /* gets only string first part of an address */
					$address_street = trim( $matches[1] );

					if ( preg_match( '/\s\d+\s*[A-Za-z]?\b/', $checkout_address, $matches ) ) {
						$address_number = trim( $matches[0] ); // Extracted number.
					}
				} else {
					$address_street = trim( $checkout_address ); // letters only with spaces.
				}

				if ( preg_match( '/\d+$/', $checkout_address, $match_number ) ) { /* gets only number at the end of an address */
					$address_number = trim( $match_number[0] );
				}
			} else {
				self::debug( array( 'Billing address 1 is empty.' ) , 'debug');
			}

			self::debug( array( 'Address for new contact is street : ' . $address_street . ' and number : ' . $address_number ) , 'debug' );

			/* checkout contact fields */
			$checkout_fields['billing'] = array(
				'name'         => $order->get_billing_first_name(),
				'surname'      => $order->get_billing_last_name(),
				'company_name' => $order->get_billing_company(),
				'vat_number'   => ( self::get_billing_vat_info( $order_id ) !== false && isset( $billing_vat_info['billing_vat'] ) ) ? $billing_vat_info['billing_vat'] : '',
				'email'        => $order->get_billing_email(),
				'street'       => $address_street,
				'number'       => $address_number,
				'city'         => $order->get_billing_city(),
				'zip_code'     => $order->get_billing_postcode(),
				'country'      => $order->get_billing_country(),
				'phone'        => $order->get_billing_phone(),
			);

			$checkout_email   = $order->get_billing_email();
			$contact_by_email = OxygenApi::get_contact_by_email( $checkout_email );

			if ( ! empty( $contact_by_email['data'] ) ) {

				self::debug( array( '------------ contact_by_email is/are ' . json_encode( $contact_by_email['data'] ) . ' ----------' ) , 'debug');

				$matching_contact_id = ''; // To store the ID of the first fully matching contact.

				foreach ( $contact_by_email['data'] as $item ) {

					$differences = array(); // Differences for this contact.
					$same        = array(); // Matching fields for this contact.

					$fields_to_compare = array( 'name', 'surname', 'street', 'number', 'city', 'zip_code', 'country' );
					/* name, surname, country , street , number , city ,zip_code , telephone , mobile  -- names of api */

					if ( ! empty( $item['type'] ) && 2 === $item['type'] ) { /* Contact type is not 'P' is company */

						$fields_to_compare = array( 'name', 'surname', 'street', 'number', 'city', 'zip_code', 'country', 'company_name', 'vat_number' );
					}

					foreach ( $fields_to_compare as $field ) {
						if ( isset( $checkout_fields['billing'][ $field ] ) && isset( $item[ $field ] ) ) {
							if ( $checkout_fields['billing'][ $field ] !== $item[ $field ] ) {
								$differences[ $field ] = array(
									'checkout' => $checkout_fields['billing'][ $field ],
									'api'      => $item[ $field ],
								);
							} else {
								$same[ $field ] = $item[ $field ];
							}
						}
					}

					// Check if all fields match for this contact.
					$all_fields_match = empty( array_diff( $fields_to_compare, array_keys( $same ) ) );

					if ( $all_fields_match ) {
						// Fully matching contact found.
						$matching_contact_id = $item['id'];
						self::debug( array( "Type contact {$item['type']} : Identical contact found on order and Pelatologio API for order {$order_id} matching_contact_id is {$matching_contact_id}" ) , 'debug');
						return $matching_contact_id; // Stop further processing.

					} else {
						// Add differences for this contact.
						self::debug( array( "Type contact {$item['type']} : Contact on order and pelatologio app has some differences " . json_encode( $differences ) ) , 'debug');
					}
				}
			}
		} else {

			self::debug( array( 'Empty order id in check_identical_contact' ) );

		}
		return '';
	}

    /**
     * Check if the checkout company data are identical to a company contact returned by VAT lookup.
     *
     * Builds a normalized array of checkout billing fields and compares them against the
     * provided $contact_by_vat (as returned by OxygenApi::get_contact_by_vat). If an
     * identical company (type = 2) contact is found, returns true; otherwise returns
     * an associative array of the differing fields so the caller can update the contact.
     *
     * @param int   $order_id        The WooCommerce order ID.
     * @param array $contact_by_vat  The result from OxygenApi::get_contact_by_vat($vat).
     *
     * @return bool|array True if an identical company contact is found, otherwise an
     *                   associative array of differences for the best matching company contact.
     */
    public static function check_identical_company_data( $order_id, $contact_by_vat ) {

        $order = wc_get_order( $order_id );
        if ( ! $order ) {
            self::debug( array( 'Empty order id in check_identical_company_data' ) );
            return false;
        }

        $address_number   = '0';
        $address_street   = '';
        $checkout_address = $order->get_billing_address_1();

        if ( ! empty( $checkout_address ) ) {
            if ( preg_match( '/^(\d+\s+[^\d]+)\s+\d+$/', $checkout_address, $match_street ) ) {
                $address_street = trim( $match_street[1] );
            } elseif ( strpos( $checkout_address, ',' ) !== false ) {
                $parts          = explode( ',', $checkout_address );
                $address_street = trim( $parts[0] );
                if ( count( $parts ) > 1 && ! is_numeric( $parts[1] ) ) {
                    $address_street = trim( $parts[0] ) . ' ' . trim( $parts[1] );
                    $only_text      = preg_replace( '/\d+/', '', $address_street );
                    if ( $only_text ) {
                        $address_street = trim( $only_text );
                    }
                }
                if ( preg_match( '/^[^\d]+/', $address_street, $matches ) ) {
                    $address_street = trim( $matches[0] );
                }
                if ( is_numeric( trim( $parts[1] ) ) ) {
                    $address_number = trim( $parts[1] );
                }
            } elseif ( preg_match( '/^(.*)\s+(\d+\s*[A-Za-zΑ-Ωα-ω]*)$/u', $checkout_address, $matches ) ) {
                $address_street = trim( $matches[1] );
                if ( preg_match( '/\s\d+\s*[A-Za-z]?\b/', $checkout_address, $matches ) ) {
                    $address_number = trim( $matches[0] );
                }
            } else {
                $address_street = trim( $checkout_address );
            }
            if ( preg_match( '/\d+$/', $checkout_address, $match_number ) ) {
                $address_number = trim( $match_number[0] );
            }
        } else {
            self::debug( array( 'Billing address 1 is empty.' ) , 'debug');
        }

        $billing_vat_info = self::get_billing_vat_info( $order_id );
        $billing_vat      = '';
        $billing_tax_off  = '';
        $billing_job = '';

        if ( $billing_vat_info ) {
            $billing_vat     = isset( $billing_vat_info['billing_vat'] ) ? $billing_vat_info['billing_vat'] : '';
            $billing_tax_off = isset( $billing_vat_info['billing_tax_office'] ) ? $billing_vat_info['billing_tax_office'] : '';
            $billing_job = isset( $billing_vat_info['billing_job'] ) ? $billing_vat_info['billing_job'] : '';
        }

        $checkout_fields = array(
            'billing' => array(
                'name'         => $order->get_billing_first_name(),
                'surname'      => $order->get_billing_last_name(),
                'company_name' => $order->get_billing_company(),
                'vat_number'   => $billing_vat,
                'email'        => $order->get_billing_email(),
                'street'       => $address_street,
                'number'       => $address_number,
                'city'         => $order->get_billing_city(),
                'zip_code'     => $order->get_billing_postcode(),
                'country'      => $order->get_billing_country(),
                'phone'        => $order->get_billing_phone(),
                'tax_office'   => $billing_tax_off,
                'profession'   => $billing_job
            ),
        );

        // Normalize input contacts array.
        $contacts = array();
        if ( is_array( $contact_by_vat ) ) {
            if ( isset( $contact_by_vat['data'] ) && is_array( $contact_by_vat['data'] ) ) {
                $contacts = $contact_by_vat['data'];
            } elseif ( isset( $contact_by_vat[0] ) ) {
                $contacts = $contact_by_vat;
            } else {
                $contacts = array( $contact_by_vat );
            }
        }

        if ( empty( $contacts ) ) {
            self::debug( array( 'check_identical_company_data: No contacts provided for comparison.' ) );
            // Return an empty differences array to indicate nothing to compare/update.
            return array();
        }

        $fields_to_compare = array( 'name', 'surname', 'street', 'number', 'city', 'zip_code', 'country', 'company_name', 'vat_number', 'email', 'tax_office', 'phone' , 'profession' );

        $best_diff       = null;
        $best_contact_id = null;

        foreach ( $contacts as $item ) {
            // Only compare company type contacts.
            if ( empty( $item['type'] ) || (int) $item['type'] !== 2 ) {
                continue;
            }

            $differences = array();

            foreach ( $fields_to_compare as $field ) {
                $checkout_val = isset( $checkout_fields['billing'][ $field ] ) ? (string) $checkout_fields['billing'][ $field ] : '';

                // Compute API value, including alternate keys for phone.
                if ( $field === 'phone' ) {
                    $api_val = isset( $item['telephone'] ) && $item['telephone'] !== ''
                        ? (string) $item['telephone']
                        : ( isset( $item['mobile'] ) ? (string) $item['mobile'] : '' );
                } else {
                    $api_val = isset( $item[ $field ] ) ? (string) $item[ $field ] : '';
                }

                // Normalize simple phone formats (strip spaces and leading +30 or 0030)
                if ( $field === 'phone' ) {
                    $norm = function( $v ) {
                        $v = preg_replace( '/\s+/', '', (string) $v );
                        $v = preg_replace( '/^(\+30|0030)/', '', $v );
                        return $v;
                    };
                    $checkout_val = $norm( $checkout_val );
                    $api_val      = $norm( $api_val );
                }

                if ( $checkout_val !== $api_val ) {
                    $differences[ $field ] = array(
                        'checkout' => $checkout_val,
                        'api'      => $api_val,
                    );
                }
            }

            if ( empty( $differences ) ) {
                self::debug( array( 'check_identical_company_data: Identical company contact found.' ) , 'info');
                return true;
            }

            // Track the company contact with the fewest differences as the best candidate to update.
            if ( $best_diff === null || count( $differences ) < count( $best_diff ) ) {
                $best_diff       = $differences;
                $best_contact_id = isset( $item['id'] ) ? $item['id'] : null;
            }
        }

        self::debug( array( 'check_identical_company_data: No identical company contact found. Returning differences for best matching company.' ) , 'info');
        if ( $best_diff !== null ) {
            // Include the contact id to simplify updates by the caller.
            return array(
                'contact_id'  => $best_contact_id,
                'differences' => $best_diff,
            );
        }

        // No company contacts present; return empty differences.
        return array();
    }

	/**
	 *  Check if args are correct
	 *
	 *  @param array $args doc args.
	 *
	 *  @return boolean
	 */
	public static function check_document_for_missing_fields( $order, $args , $notetype, $doc_key) {

		$order_id = $order->get_id();

		if(empty($order_id)){
			return false;
		}

		$mandatory_fields = array(
			'description'                    => __('Product Description', 'oxygen'),
			'quantity'                       => __('Quantity', 'oxygen'),
			'unit_net_value'                 => __('Unit Net Value', 'oxygen'),
			'tax_id'                         => __('Tax ID', 'oxygen'),
			'vat_amount'                     => __('VAT Amount', 'oxygen'),
			'net_amount'                     => __('Net Amount', 'oxygen'),
			'mydata_classification_category' => __('myDATA Classification Category', 'oxygen'),
			'mydata_classification_type'     => __('myDATA Classification Type', 'oxygen'),
		);

		self::debug( array( "SHIPPING DATA IS " ,get_option( 'oxygen_enable_shipping_data' )) , 'debug');

		if( 'yes' === get_option( 'oxygen_enable_shipping_data' ) && ('alp' === $doc_key || 'tpda' === $doc_key ) ){ /* mono pwlisi */

			$mandatory_fields = array_merge( $mandatory_fields, array(
				'measurement_unit_id' =>   __('Measurement Unit', 'oxygen'),
			));

			if( ! self::check_default_shipping_data() ){
				self::debug( array( "default shipping data check is false") );
				if ( ! self::check_orders_shipping_data($order)){
					self::debug( array( "orders shipping data check is false") , 'debug');
					return false;
				}
				return false;
			}

		}


		$fee_items = $order->get_items( 'fee' );
		$shipping_items = $order->get_items( 'shipping' );


		if ( 'invoice' === $notetype ) {

			foreach ( $args['items'] as $index => $item ) {

				$is_fee_or_shipping = false;

				// Match with fee items
				foreach ( $fee_items as $fee ) {
					if (
						isset( $item['name'], $item['total'] ) &&
						$item['name'] === $fee->get_name() &&
						$item['total'] == $fee->get_total()
					) {
						$is_fee_or_shipping = true;
						break;
					}
				}

				// Match with shipping items
				if ( ! $is_fee_or_shipping ) {
					foreach ( $shipping_items as $ship ) {
						if (
							isset( $item['name'], $item['total'] ) &&
							$item['name'] === $ship->get_name() &&
							$item['total'] == $ship->get_total()
						) {
							$is_fee_or_shipping = true;
							break;
						}
					}
				}

				// Skip validation for fee or shipping items
				if ( $is_fee_or_shipping ) {
					continue;
				}

				// Validate mandatory fields for non-fee/shipping items
				foreach ( $mandatory_fields as $key => $field_name ) {

					if (
						! isset( $item[ $key ] ) ||
						$item[ $key ] === '' ||
						$item[ $key ] === null
					) {
						WC_Admin_Notices::add_custom_notice(
							'oxygen_invoice_error',
							'<p class="oxygen_error">' . sprintf(
								__( 'Could not create invoice: Empty field %1$s in products line item #%2$d', 'oxygen' ),
								$field_name,
								$index + 1
							) . '</p>'
						);
						return false;
					}
				}
			}
		}

		return true;
	}

	public static function check_default_shipping_data () {

		$shipping_fields = array(
			'oxygen_move_purpose'             => __('Move purpose', 'oxygen'),
			'oxygen_pickup_branch_code'       => __('Pick up branch code', 'oxygen'),
			'oxygen_pickup_street'            => __('Pick up street', 'oxygen'),
			'oxygen_pickup_address_number'    => __('Pick up address number', 'oxygen'),
			'oxygen_pickup_postal_code'       => __('Pick up postal code', 'oxygen'),
			'oxygen_pickup_city'              => __('Pick up city', 'oxygen'),
			'oxygen_pickup_country'           => __('Pick up country', 'oxygen')
		);

		foreach ( $shipping_fields as $key => $label ) {

			$value = OxygenHelperFunctions::get_option(  $key, true );

			if($key === 'oxygen_pickup_branch_code' && $value == 0){
				self::debug( array( "oxygen_pickup_branch_code is ",$value) , 'debug');
				continue;
			}
            if ( $value === '' && $value !== 0 ) {
				WC_Admin_Notices::add_custom_notice(
					'oxygen_invoice_error',
					sprintf(
						__( 'Could not auto create invoice , because of shipping data. Check fields <a href="%s">here</a>.', 'oxygen' ),
						admin_url( 'admin.php?page=wc-settings&tab=oxygen_tabs&section=shipping_data_settings' )
					)
				);
				return false;
			}
		}
		return true;
	}

	public static function check_orders_shipping_data( $order ) {

		$shipping_fields = array(
			'_oxygen_move_purpose'          => __('Move purpose', 'oxygen'),
			'_oxygen_pickup_branch_code'    => __('Pick up branch code', 'oxygen'),
			'_oxygen_pickup_street'         => __('Pick up street', 'oxygen'),
			'_oxygen_pickup_address_number' => __('Pick up address number', 'oxygen'),
			'_oxygen_pickup_postal_code'    => __('Pick up postal code', 'oxygen'),
			'_oxygen_pickup_city'           => __('Pick up city', 'oxygen'),
			'_oxygen_pickup_country'        => __('Pick up country', 'oxygen'),
		);

		$empty_fields = array();

		foreach ( $shipping_fields as $key => $label ) {
			$value = $order->get_meta( $key, true );

			if($key === '_oxygen_pickup_branch_code' && $value == 0){
				self::debug( array( "_oxygen_pickup_branch_code is ",$value) , 'debug');
				continue;
			}
			if ( empty( $value ) ) {
				$empty_fields[ $key ] = $label;
			}
		}

		if ( ! empty( $empty_fields ) ) {
			foreach ( $empty_fields as $key => $label ) {
				WC_Admin_Notices::add_custom_notice(
					'oxygen_invoice_error_' . $key, // unique key per field
					'<p class="oxygen_error">' . sprintf(
						__( 'Could not create invoice: Empty field %1$s for shipping data.', 'oxygen' ),
						$label
					) . '</p>'
				);
				return false;
			}
		}

		return true;

	}


	/* SHIPPING DATA */

	public static function move_purposes(): array
	{
		return [
			0  => __('Select', 'oxygen'),
			1  => __('Πώληση', 'oxygen'),
			2  => __('Πώληση για Λογαριασμό Τρίτων', 'oxygen'),
			3  => __('Δειγματισμός', 'oxygen'),
			4  => __('Έκθεση', 'oxygen'),
			5  => __('Επιστροφή', 'oxygen'),
			6  => __('Φύλαξη', 'oxygen'),
			7  => __('Επεξεργασία Συναρμολόγηση', 'oxygen'),
			8  => __('Μεταξύ Εγκαταστάσεων Οντότητας', 'oxygen'),
			9  => __('Αγορά', 'oxygen'),
			10 => __('Εφοδιασμός πλοίων και αεροσκαφών', 'oxygen'),
			11 => __('Δωρεάν διάθεση', 'oxygen'),
			12 => __('Εγγύηση', 'oxygen'),
			13 => __('Χρησιδανεισμός', 'oxygen'),
			14 => __('Αποθήκευση σε Τρίτους', 'oxygen'),
			15 => __('Επιστροφή από Φύλαξη', 'oxygen'),
			16 => __('Ανακύκλωση', 'oxygen'),
			17 => __('Καταστροφή άχρηστου υλικού', 'oxygen'),
			18 => __('Διακίνηση Παγίων (Ενδοδιακίνηση)', 'oxygen'),
			19 => __('Λοιπές Διακινήσεις', 'oxygen'),
		];
	}

	public static function countries(): array {

		return [
			'0' => __('Select', 'oxygen'),
			'GR' => 'Greece',
			'US' => 'United States',
			'GB' => 'United Kingdom',
			'DE' => 'Germany',
			'FR' => 'France',
			'IT' => 'Italy',
			'ES' => 'Spain',
			'NL' => 'Netherlands',
			'BE' => 'Belgium',
			'PT' => 'Portugal',
			'IE' => 'Ireland',
			'CY' => 'Cyprus',
			'AT' => 'Austria',
			'SE' => 'Sweden',
			'FI' => 'Finland',
			'DK' => 'Denmark',
			'NO' => 'Norway',
			'PL' => 'Poland',
			'CZ' => 'Czech Republic',
			'HU' => 'Hungary',
			'SK' => 'Slovakia',
			'RO' => 'Romania',
			'BG' => 'Bulgaria',
			'HR' => 'Croatia',
			'SI' => 'Slovenia',
			'MT' => 'Malta',
			'EE' => 'Estonia',
			'LV' => 'Latvia',
			'LT' => 'Lithuania',
			'LU' => 'Luxembourg',
			'CH' => 'Switzerland',
			'IS' => 'Iceland',
			'TR' => 'Turkey',
			'AU' => 'Australia',
			'CA' => 'Canada',
			'NZ' => 'New Zealand',
			'BR' => 'Brazil',
			'AR' => 'Argentina',
			'MX' => 'Mexico',
			'ZA' => 'South Africa',
			'CN' => 'China',
			'JP' => 'Japan',
			'KR' => 'South Korea',
			'IN' => 'India',
			'RU' => 'Russia',
			'IL' => 'Israel',
			'AE' => 'United Arab Emirates',
			'SA' => 'Saudi Arabia'
		];
	}

	public static function get_custom_admin_order_fields() {

		return array(
			'_oxygen_tranfer_header' => array(
				'title' => __( 'Transfer Data', 'oxygen' ),
				'type'  => 'title',
			),
			'_oxygen_move_purpose' => array(
				'label' => __( 'Move purpose', 'oxygen' ),
				'type' => 'select',
				'options' => self::move_purposes(),
			),
			'_oxygen_other_move_purpose_title' => array(
				'label' => __( 'Other move purpose title', 'oxygen' ),
				'type' => 'text',
			),
			'_oxygen_vehicle_number' => array(
				'label' => __( 'Vehicle number', 'oxygen' ),
				'type' => 'text',
			),
			'_oxygen_shipping_comments' => array(
				'label' => __( 'Comments', 'oxygen' ),
				'type' => 'textarea',
			),
			'oxygen_pickup_header' => array(
				'title' => __( 'Pick up details', 'oxygen' ),
				'type'  => 'title',
			),
			'_oxygen_pickup_branch_code' => array(
				'label' => __( 'Pick up branch code', 'oxygen' ),
				'type' => 'number',
			),
			'_oxygen_pickup_street' => array(
				'label' => __( 'Pick up street', 'oxygen' ),
				'type' => 'text',
			),
			'_oxygen_pickup_address_number' => array(
				'label' => __( 'Pick up address number', 'oxygen' ),
				'type' => 'text',
			),
			'_oxygen_pickup_postal_code' => array(
				'label' => __( 'Pick up postal_code', 'oxygen' ),
				'type' => 'text',
			),
			'_oxygen_pickup_city' => array(
				'label' => __( 'Pick up city', 'oxygen' ),
				'type' => 'text',
			),
			'_oxygen_pickup_country' => array(
				'label' => __( 'Pick up country', 'oxygen' ),
				'type' => 'select',
				'options' => self::countries(),
			),
		);
	}



	/**
	 * Get order meta field with fallback from shipping to billing.
	 *
	 * @param int    $order_id
	 * @param string $field_key (e.g. 'address_1', 'city', 'phone')
	 * @return string
	 */
	public static function get_billing_or_shipping_meta($order, $field) {
		$shipping_method = "get_shipping_{$field}";

		if (method_exists($order, $shipping_method)) {
			$shipping =  $order->$shipping_method();
		}

		if(!empty($shipping)) {
			return $shipping;
		}

		$billing_method = "get_billing_{$field}";

		if (method_exists($order, $billing_method)) {
			$billing =  $order->$billing_method();
		}

		if (!empty($billing)) {
			return $billing;
		}

		return '';
	}

    /**
     * Update an existing company contact with the detected differences.
     *
     * This helper encapsulates the logic previously inlines (lines 1153–1267)
     * inside select_contact_id_per_invoice_type(). It attempts to update the
     * provided $existing_contact using the $is_identical_company differences
     * structure and returns the updated contact ID if an update occurred.
     *
     * @param array $existing_contact     The existing contact data from Oxygen API (must include 'id' and 'type').
     * @param array $is_identical_company The result from check_identical_company_data() when it returns differences.
     * @param string $notetype            The document notetype for logging.
     * @param string $doc_key             The document key for logging.
     * @return string                     The updated contact ID if updated, otherwise empty string.
     */
    public static function update_contact_fields_for_company( $existing_contact, $is_identical_company, $notetype, $doc_key ) {

        // If we have differences array, try to update the contact before using it
        if ( is_array( $is_identical_company ) && ! empty( $is_identical_company ) ) {

            self::debug( array( 'dif are ', $is_identical_company ) , 'debug');

            $contact_id  = $existing_contact['id'];

            $differences = isset( $is_identical_company['differences'] ) && is_array( $is_identical_company['differences'] )
                ? $is_identical_company['differences']
                : array();

            if ( $contact_id && ! empty( $differences ) ) {
                // Build update payload with only changed fields.
                $update_args        = array( 'id' => $contact_id );
                $field_map_api_keys = array(
                    'name'         => 'name',
                    'surname'      => 'surname',
                    'company_name' => 'company_name',
                    'vat_number'   => 'vat_number',
                    'email'        => 'email',
                    'street'       => 'street',
                    'number'       => 'number',
                    'city'         => 'city',
                    'zip_code'     => 'zip_code',
                    'country'      => 'country',
                    'tax_office'   => 'tax_office',
                    'profession'   => 'profession',
                );

                foreach ( $differences as $diff_field => $vals ) {
                    // Value provided at checkout (may be string or null)
                    $checkout_val = isset( $vals['checkout'] ) ? $vals['checkout'] : null;

                    if ( $diff_field === 'phone' ) {
                        // If checkout provided a non-empty phone, use it; otherwise, keep existing phone values
                        $phone_to_use = ( is_string( $checkout_val ) && trim( $checkout_val ) !== '' )
                            ? (string) $checkout_val
                            : ( isset( $existing_contact['telephone'] ) ? (string) $existing_contact['telephone'] : '' );

                        $update_args['telephone'] = $phone_to_use;
                        // Prefer same for mobile; if existing has a separate mobile and checkout empty, use existing mobile
                        $update_args['mobile']    = ( is_string( $checkout_val ) && trim( $checkout_val ) !== '' )
                            ? (string) $checkout_val
                            : ( isset( $existing_contact['mobile'] ) ? (string) $existing_contact['mobile'] : $phone_to_use );
                        continue;
                    }

                    if ( isset( $field_map_api_keys[ $diff_field ] ) ) {
                        $api_key = $field_map_api_keys[ $diff_field ];

                        // If there is a different value on checkout and it's non-empty, use it; else use existing_contact field
                        if ( is_string( $checkout_val ) && trim( $checkout_val ) !== '' ) {
                            $update_args[ $api_key ] = $checkout_val;
                        } else {
                            $update_args[ $api_key ] = isset( $existing_contact[ $api_key ] ) ? $existing_contact[ $api_key ] : '';
                        }
                    }
                }

                // Always preserve type (do not allow updates to it)
                $update_args['type'] = $existing_contact['type'];

                // If no difference was detected for certain fields, backfill them with existing data
                // so the API receives a complete and consistent payload.

                // 1) Backfill all mapped fields not present in $update_args
                foreach ( $field_map_api_keys as $diff_key => $api_key ) {
                    if ( ! isset( $update_args[ $api_key ] ) ) {
                        // Use existing contact's value when available; otherwise empty string as per previous logic
                        $update_args[ $api_key ] = isset( $existing_contact[ $api_key ] ) ? $existing_contact[ $api_key ] : '';
                    }
                }

                // 2) Special handling for phone when not changed: set telephone/mobile from existing
                if ( ! isset( $update_args['telephone'] ) ) {
                    $update_args['telephone'] = isset( $existing_contact['telephone'] ) ? (string) $existing_contact['telephone'] : '';
                }
                if ( ! isset( $update_args['mobile'] ) ) {
                    $update_args['mobile'] = isset( $existing_contact['mobile'] ) ? (string) $existing_contact['mobile'] : '';
                }

                // 3) Other fields that are required but may not be part of diffs
                if ( ! isset( $update_args['profession'] ) ) {
                    $update_args['profession'] = $existing_contact['profession'] ?? '';
                }
                if ( ! isset( $update_args['is_supplier'] ) ) {
                    $update_args['is_supplier'] = $existing_contact['is_supplier'] ?? false;
                }
                if ( ! isset( $update_args['is_client'] ) ) {
                    $update_args['is_client'] = $existing_contact['is_client'] ?? false;
                }

                $update_resp = OxygenApi::update_contact( $update_args );

                if ( is_array( $update_resp ) ) {
                    // Try common shapes:
                    // 1) Full wp_remote_response array with decoded body containing id
                    if ( isset( $update_resp['body'] ) ) {
                        $decoded = is_string( $update_resp['body'] ) ? json_decode( $update_resp['body'], true ) : $update_resp['body'];

                        self::debug( array( 'decode array contact : ', $decoded ) , 'debug');

                        if ( is_array( $decoded ) && isset( $decoded['id'] ) ) {
                            $updated_id = $decoded['id'];
                        }
                    } elseif ( isset( $update_resp['id'] ) ) {
                        // 2) Direct decoded array
                        $updated_id = $update_resp['id'];
                    }
                }

                $oxygen_customer_id = $updated_id ?? '';
                self::debug( array( self::format_debug_message( $notetype, $doc_key, "Updated existing contact. Using contact ID: {$oxygen_customer_id}" ) ) );
                return $oxygen_customer_id;
            }
        }

        // No update performed
        return '';
    }

	public static function oxygen_measurement_units(){

		$oxygen_get_measurement_units = OxygenApi::get_measurement_units();
		$oxygen_units     = array();

		foreach ( $oxygen_get_measurement_units['data'] as $oxygen_unit ) {
			if ( empty($oxygen_unit['id']) ) {
				continue;
			}

			$oxygen_units[ $oxygen_unit['id'] ] = $oxygen_unit['abbreviation'];
		}

		return array( '0' => __( 'Select', 'oxygen' ) ) + $oxygen_units;

	}

    public static function get_product_measurement_unit( $product_id ) {

        if ( empty( $product_id ) ) {
            self::debug( array( '------------- Measurement unit on product is EMPTY both ------------' ) , 'debug');
            return '';
        }

        $unit = get_post_meta( $product_id, 'oxygen_wc_measurement_unit', true );

        if ( empty( $unit ) ) {
            $unit = get_option( 'oxygen_measurement_unit_default', '' );
        }

        self::debug( array(
            '------------- Measurement unit on product is ------------ ' . $unit
        ) , 'debug');

        return $unit;
    }

	/**
	 * Get the logo ID that matches both the selected logo title and the given language.
	 *
	 * This function first retrieves all logos from the API, then checks which logo is currently selected
	 * via the `oxygen_logo` option. It finds the title of that selected logo, and finally searches for a
	 * logo that matches both the same title and the desired language.
	 *
	 * @param string $language_to_print The language code to match (e.g. 'en', 'el').
	 * @return string|false The ID of the matching logo, or false if no match is found.
	 */

	public static function get_logo_by_language($language_to_print) {

		$logos = OxygenApi::get_logos(); // Get the array of logo data

		if ( ! is_array( $logos ) ) {
			return false;
		}

		$selected_logo_id = OxygenHelperFunctions::get_option('oxygen_logo');

		foreach ( $logos as $logo ) {
			if ( isset( $logo['id'] ) && $logo['id'] === $selected_logo_id ) {
				$selected_title =  $logo['title'];
			}
			if($logo['title'] === $selected_title){

				if ( !empty( $logo['language'] ) && strtolower($logo['language']) === strtolower($language_to_print) ) {
					return $logo['id'];
				}
			}
		}

		return $selected_logo_id;
	}


}
