<?php
/**
 * Registers B2BKing custom fields with the WooCommerce Blocks checkout
 * using the woocommerce_register_additional_checkout_field API.
 * Handles field display, default value population, validation, and order meta saving.
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

add_action( 'woocommerce_init', 'b2bking_register_blocks_checkout_fields' );

function b2bking_register_blocks_checkout_fields() {

	// Not needed on admin pages outside of REST/AJAX context.
	if ( is_admin() && ! defined( 'REST_REQUEST' ) && ! wp_doing_ajax() ) {
		return;
	}

	// Fallback: add_filter( 'b2bking_blocks_use_legacy_fields', '__return_true' );
	if ( apply_filters( 'b2bking_blocks_use_legacy_fields', false ) ) {
		return;
	}

	if ( ! function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
		return;
	}

	// Resolve user ID, using top-level parent for subaccounts.
	if ( is_user_logged_in() ) {
		$user_id = get_current_user_id();
		if ( apply_filters( 'b2bking_subaccounts_use_same_fields', true ) ) {
			$user_id = b2bking()->get_top_parent_account( $user_id );
		}
	} else {
		$user_id = 0;
	}

	// Build group visibility condition for the meta query.
	$array_groups_visible = array( 'relation' => 'OR' );

	if ( ! is_user_logged_in() ) {
		$array_groups_visible[] = array(
			'key'     => 'b2bking_custom_field_multiple_groups',
			'value'   => 'group_loggedout',
			'compare' => 'LIKE',
		);
	} elseif ( get_user_meta( $user_id, 'b2bking_b2buser', true ) !== 'yes' ) {
		$array_groups_visible[] = array(
			'key'     => 'b2bking_custom_field_multiple_groups',
			'value'   => 'group_b2c',
			'compare' => 'LIKE',
		);
	} else {
		$array_groups_visible[] = array(
			'key'     => 'b2bking_custom_field_multiple_groups',
			'value'   => 'group_' . b2bking()->get_user_group( $user_id ),
			'compare' => 'LIKE',
		);
		$array_groups_visible[] = array(
			'key'     => 'b2bking_custom_field_multiple_groups',
			'value'   => 'group_b2b',
			'compare' => 'LIKE',
		);
	}

	// Load enabled custom fields, cached per user and mapping flag.
	$custom_mapping_enabled = apply_filters( 'b2bking_show_custom_mapping_fields_billing', false ) ? '1' : '0';
	$cache_key              = 'b2bking_blocks_billing_fields_' . $user_id . '_mapping' . $custom_mapping_enabled;
	$custom_fields          = get_transient( $cache_key );

	if ( false === $custom_fields ) {
		$custom_fields = get_posts( array(
			'post_type'   => 'b2bking_custom_field',
			'post_status' => 'publish',
			'numberposts' => -1,
			'orderby'     => 'menu_order',
			'order'       => 'ASC',
			'meta_query'  => array(
				'relation' => 'AND',
				array(
					'key'   => 'b2bking_custom_field_status',
					'value' => 1,
				),
				array(
					'relation' => 'OR',
					array(
						'key'   => 'b2bking_custom_field_billing_connection',
						'value' => 'none',
					),
					array(
						'key'   => 'b2bking_custom_field_billing_connection',
						'value' => 'billing_vat',
					),
				),
				array(
					'key'   => 'b2bking_custom_field_add_to_billing',
					'value' => 1,
				),
				$array_groups_visible,
			),
		) );

		if ( $custom_mapping_enabled === '1' ) {
			$custom_fields2 = get_posts( array(
				'post_type'   => 'b2bking_custom_field',
				'post_status' => 'publish',
				'numberposts' => -1,
				'orderby'     => 'menu_order',
				'order'       => 'ASC',
				'meta_query'  => array(
					'relation' => 'AND',
					array(
						'key'   => 'b2bking_custom_field_status',
						'value' => 1,
					),
					array(
						'relation' => 'OR',
						array(
							'key'   => 'b2bking_custom_field_billing_connection',
							'value' => 'custom_mapping',
						),
					),
					$array_groups_visible,
				),
			) );
			$custom_fields = array_merge( $custom_fields, $custom_fields2 );
		}

		set_transient( $cache_key, $custom_fields, 0 );
	}

	$supported_field_types = array( 'text', 'select', 'checkbox' );
	$priority              = 200;

	foreach ( $custom_fields as $custom_field ) {

		$field_type         = get_post_meta( $custom_field->ID, 'b2bking_custom_field_field_type', true );
		$required           = intval( get_post_meta( $custom_field->ID, 'b2bking_custom_field_required_billing', true ) );
		$billing_connection = get_post_meta( $custom_field->ID, 'b2bking_custom_field_billing_connection', true );

		// VAT fields are always text (or select); required is handled in validation
		// so the field can be conditionally shown/hidden per country.
		if ( $billing_connection === 'billing_vat' ) {
			$field_type = ( $field_type === 'radio' || $field_type === 'checkbox' ) ? 'select' : 'text';
			if ( apply_filters( 'b2bking_blocks_vat_disable_required', false ) ) {
				$required = 0;
			}
		}

		if ( $field_type === 'file' ) {
			$priority++;
			continue;
		}

		// Normalise types to those supported by the blocks checkout API.
		if ( $field_type === 'radio' )                                                      { $field_type = 'select'; }
		if ( $field_type === 'number' || $field_type === 'email' || $field_type === 'tel' ) { $field_type = 'text'; }

		if ( ! in_array( $field_type, $supported_field_types, true ) ) {
			$priority++;
			continue;
		}

		$wpml_id           = apply_filters( 'wpml_object_id', $custom_field->ID, 'post', true );
		$field_label       = get_post_meta( $wpml_id, 'b2bking_custom_field_field_label', true );
		$field_placeholder = get_post_meta( $wpml_id, 'b2bking_custom_field_field_placeholder', true );
		$required_bool     = ( intval( $required ) === 1 );

		// Build options array for select fields (supports label:value or plain value format).
		$options_array = array();
		if ( $field_type === 'select' ) {
			$user_choices  = get_post_meta( $custom_field->ID, 'b2bking_custom_field_user_choices', true );
			$user_choices  = b2bking()->escape_user_choices( $user_choices );
			$choices_array = explode( ',', $user_choices );
			$choices_array = b2bking()->unescape_user_choices( $choices_array );
			foreach ( $choices_array as $choice ) {
				$optionvalue = explode( ':', $choice );
				if ( count( $optionvalue ) === 2 ) {
					$options_array[ trim( $optionvalue[0] ) ] = array(
						'label' => trim( $optionvalue[0] ),
						'value' => trim( $optionvalue[1] ),
					);
				} else {
					$options_array[ trim( $choice ) ] = array(
						'label' => trim( $choice ),
						'value' => trim( $choice ),
					);
				}
			}
		}

		$editable = intval( get_post_meta( $custom_field->ID, 'b2bking_custom_field_editable', true ) );

		$blocks_args = array(
			'id'         => 'b2bking/b2bking_custom_field_' . $custom_field->ID,
			'label'      => sanitize_text_field( $field_label ),
			'location'   => 'address',
			'required'   => $required_bool,
			'type'       => sanitize_text_field( $field_type ),
			'attributes' => array(
				'title' => sanitize_text_field( $field_label ),
			),
		);

		if ( ! empty( $options_array ) ) {
			$blocks_args['options'] = $options_array;
		}

		if ( is_user_logged_in() && $editable !== 1 ) {
			$blocks_args['attributes']['readOnly'] = 'readonly';
		}

		woocommerce_register_additional_checkout_field( $blocks_args );

		// Pre-populate field with the value saved to user meta.
		add_filter(
			'woocommerce_get_default_value_for_b2bking/b2bking_custom_field_' . $custom_field->ID,
			function ( $value, $group, $wc_object ) use ( $custom_field ) {
				$saved = get_user_meta( get_current_user_id(), 'b2bking_custom_field_' . $custom_field->ID, true );
				return ( $saved !== null && $saved !== '' ) ? $saved : $value;
			},
			10,
			3
		);

		// Save submitted value to user meta and run VAT/VIES validation.
		add_action(
			'woocommerce_blocks_validate_location_address_fields',
			function ( \WP_Error $errors, $fields, $group ) use ( $custom_field ) {

				if ( $group !== 'billing' ) {
					return;
				}

				$field_key   = 'b2bking/b2bking_custom_field_' . $custom_field->ID;
				$field_value = isset( $fields[ $field_key ] ) ? $fields[ $field_key ] : '';

				update_user_meta( get_current_user_id(), 'b2bking_custom_field_' . $custom_field->ID, $field_value );

				$billing_connection = get_post_meta( $custom_field->ID, 'b2bking_custom_field_billing_connection', true );
				if ( $billing_connection !== 'billing_vat' ) {
					return;
				}

				$vat_number_inputted = strtoupper( str_replace( array( '.', ' ' ), '', $field_value ) );

				if ( ! empty( $vat_number_inputted ) ) {
					$prefix = apply_filters( 'b2bking_set_default_prefix_vat', false );
					if ( $prefix !== false && substr( $vat_number_inputted, 0, 2 ) !== $prefix ) {
						$vat_number_inputted = $prefix . $vat_number_inputted;
					}
				}

				$country_inputted = isset( $fields['country'] ) ? sanitize_text_field( $fields['country'] ) : 'none';
				if ( $country_inputted === 'none' || empty( $country_inputted ) ) {
					$countries = WC()->countries->get_allowed_countries();
					if ( count( $countries ) === 1 ) {
						$country_inputted = array_keys( $countries )[0];
					}
				}

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

				$vat_field_vies_validation_setting = get_post_meta( $custom_field->ID, 'b2bking_custom_field_VAT_VIES_validation', true );

				$countries_list_eu = apply_filters( 'b2bking_country_list_vies', array(
					'AT', 'BE', 'BG', 'HR', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR',
					'DE', 'GR', 'EL', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT',
					'NL', 'PL', 'PT', 'RO', 'SK', 'SI', 'ES', 'SE',
				) );

				if ( ! in_array( $country_inputted, $countries_list_eu, true ) || intval( $vat_field_vies_validation_setting ) !== 1 ) {
					return;
				}

				$error_details = '';
				try {
					$country_code  = substr( $vat_number_inputted, 0, 2 );
					$vat_number    = substr( $vat_number_inputted, 2 );
					$validation    = b2bking()->vies_validation( $country_code, $vat_number );
					$error_details = 'VAT Validation Issue';

					// Greece uses GR as country code but EL as VAT prefix.
					if ( trim( strtolower( $country_inputted ) ) !== trim( strtolower( $country_code ) ) ) {
						$is_greece_exception = ( trim( strtolower( $country_inputted ) ) === 'gr' && trim( strtolower( $country_code ) ) === 'el' );
						if ( ! $is_greece_exception ) {
							$errors->add( 'validation', esc_html__( 'VAT Number you entered is for a different country than the country you selected', 'b2bking' ) );
						}
					}
				} catch ( Exception $e ) {
					$error       = $e->getMessage();
					$error_array = array(
						'INVALID_INPUT'         => esc_html__( 'CountryCode is invalid or the VAT number is empty.', 'b2bking' ),
						'SERVICE_UNAVAILABLE'   => esc_html__( 'VIES VAT Service is unavailable. Try again later.', 'b2bking' ),
						'MS_UNAVAILABLE'        => esc_html__( 'VIES VAT Member State Service is unavailable.', 'b2bking' ),
						'TIMEOUT'               => esc_html__( 'Service timeout. Try again later', 'b2bking' ),
						'SERVER_BUSY'           => esc_html__( 'VAT Server is too busy. Try again later.', 'b2bking' ),
						'MS_MAX_CONCURRENT_REQ' => esc_html__( 'Too many requests. The Europa.eu VIES server cannot process your request right now.', 'b2bking' ),
					);
					$error_details .= isset( $error_array[ $error ] ) ? $error_array[ $error ] : $error;

					// Service errors (timeout, unavailable) let the order through; admin is notified.
					if ( apply_filters( 'b2bking_allow_vat_timeouts_unavailable_errors', true ) && $error !== 'INVALID_INPUT' ) {
						$validation        = new stdClass();
						$validation->valid = 1;

						$recipient    = apply_filters( 'b2bking_invalid_vat_number_email', get_option( 'admin_email' ), 0 );
						$current_user = wp_get_current_user();
						$user_email   = $current_user->ID ? $current_user->user_email : 'Logged out user';

						$message  = 'A customer registered / ordered on your shop, but the VIES Validation encountered an issue which is not the fault of the user. The request was accepted, but you should manually check this VAT number and customer.';
						$message .= '<br><br>Error details: ' . $error;
						if ( isset( $error_array[ $error ] ) ) {
							$message .= ' (' . $error_array[ $error ] . ')';
						}
						$message .= '<br><br>The VAT number is: ' . $country_code . $vat_number;
						$message .= '<br><br>The email of the user is: ' . $user_email;

						do_action( 'b2bking_new_message', $recipient, $message, 'Quoteemail:1', 0 );
					}
				}

				if ( ! isset( $validation ) ) {
					$errors->add( 'validation', esc_html__( 'VAT Number is Invalid.', 'b2bking' ) . ' ' . $error_details );
					return;
				}

				if ( intval( $validation->valid ) === 1 ) {
					if ( is_user_logged_in() ) {
						$vat_field = get_posts( array(
							'post_type'   => 'b2bking_custom_field',
							'post_status' => 'publish',
							'fields'      => 'ids',
							'numberposts' => -1,
							'meta_query'  => array(
								'relation' => 'AND',
								array( 'key' => 'b2bking_custom_field_status', 'value' => 1 ),
								array( 'key' => 'b2bking_custom_field_billing_connection', 'value' => 'billing_vat' ),
							),
						) );
						if ( ! empty( $vat_field ) ) {
							update_user_meta( get_current_user_id(), 'b2bking_custom_field_' . $vat_field[0], $vat_number_inputted );
							update_user_meta( get_current_user_id(), 'b2bking_custom_field_' . $vat_field[0] . 'bis', $vat_number_inputted );
							update_user_meta( get_current_user_id(), 'vat_number', $vat_number_inputted );
							update_user_meta( get_current_user_id(), 'b2bking_user_vat_status', 'validated_vat' );
						}
					}
				} else {
					$errors->add( 'validation', esc_html__( 'VAT Number is Invalid.', 'b2bking' ) . ' ' . $error_details );
				}
			},
			10,
			3
		);

		$priority++;
	}
}

// Ensure custom field values are saved to order meta for blocks checkout orders.
// The Store API does not fire woocommerce_checkout_update_order_meta (classic only),
// so we hook the same function here via its blocks equivalent.
add_action(
	'woocommerce_store_api_checkout_order_processed',
	array( 'B2bking_Public', 'b2bking_add_custom_fields_to_order_meta' ),
	20,
	1
);
