<?php

namespace WarrantyCart\Frontend;

use WC_Order;

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

/**
 * Checkout Fields Class
 *
 * Handles custom checkout fields for warranty purchases
 */
class CheckoutFields {

	/**
	 * Constructor
	 */
	public function __construct() {
		// Classic checkout hooks
		add_action( 'woocommerce_checkout_before_customer_details', array( $this, 'add_checkout_fields_section' ) );
		add_action( 'woocommerce_checkout_process', array( $this, 'validate_checkout_fields' ) );
		add_action( 'woocommerce_checkout_create_order', array( $this, 'save_checkout_fields_to_order' ) );

		// Block checkout hooks
		add_action( 'init', array( $this, 'register_block_checkout_fields' ) );
		add_action( 'woocommerce_set_additional_field_value', array( $this, 'save_blocks_field_to_order' ), 10, 4 );

		// Billing phone requirement
		add_filter( 'woocommerce_checkout_fields', array( $this, 'modify_billing_phone_requirement' ) );
	}

	/**
	 * Modify billing phone requirement
	 *
	 * Makes the billing phone field required when the setting is enabled and warranty products are in cart.
	 *
	 * @param array $fields Checkout fields array.
	 *
	 * @return array Modified checkout fields array.
	 */
	public function modify_billing_phone_requirement( $fields ): array {
		// Only modify if cart contains warranty products and setting is enabled
		if ( ! $this->cart_has_warranty_products() ) {
			return $fields;
		}

		$require_phone = get_option( 'warranty_require_billing_phone', false );
		if ( ! $require_phone ) {
			return $fields;
		}

		// Make billing phone required
		if ( isset( $fields['billing']['billing_phone'] ) ) {
			$fields['billing']['billing_phone']['required'] = true;
		}

		/**
		 * Filter modified checkout fields for billing phone requirement.
		 *
		 * @param array $fields        Checkout fields array.
		 * @param bool  $require_phone Whether phone is required.
		 */
		return apply_filters( 'warranty_cart_checkout_fields_billing_phone', $fields, $require_phone );
	}

	/**
	 * Add checkout fields section
	 *
	 * Adds custom warranty fields to the checkout page when warranty products are in cart.
	 */
	public function add_checkout_fields_section(): void {
		// Only show if cart contains warranty products
		if ( ! $this->cart_has_warranty_products() ) {
			return;
		}

		$fields = $this->get_checkout_fields();
		if ( empty( $fields ) ) {
			return;
		}

		/**
		 * Filter checkout fields section HTML
		 *
		 * @param string $section_html Section HTML.
		 * @param array  $fields       Checkout fields.
		 */
		$section_html = apply_filters(
			'warranty_cart_checkout_fields_section_html',
			'<div class="warranty-checkout-fields-section">
				<h3>' . esc_html__( 'Warranty Information', 'warranty-cart' ) . '</h3>' .
			wc_get_template_html(
				'checkout/warranty-fields.php',
				array(
					'fields' => $fields,
				),
				'',
				WARRANTY_CART_PATH . 'templates/'
			) .
			'</div>',
			$fields
		);

		// Output the warranty checkout section HTML
		// HTML is generated by wc_get_template_html() which properly escapes output
		echo wp_kses_post( $section_html );
	}

	/**
	 * Validate checkout fields
	 *
	 * Validates custom warranty checkout fields for required fields and data types.
	 */
	public function validate_checkout_fields(): void {
		// Verify nonce for security
		if ( ! isset( $_POST['woocommerce-process-checkout-nonce'] ) ||
			! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ), 'woocommerce-process_checkout' ) ) {
			return;
		}

		// Only validate if cart contains warranty products
		if ( ! $this->cart_has_warranty_products() ) {
			return;
		}

		$fields = $this->get_checkout_fields();

		/**
		 * Validates the structure and content of a checkout field configuration.
		 *
		 * @param array $field Field configuration array.
		 *
		 * @return bool True if valid, false otherwise
		 */
		do_action( 'warranty_cart_before_validate_checkout_fields', $fields );

		foreach ( $fields as $field ) {
			if ( ! $field['enabled'] ) {
				continue;
			}

			$field_name = 'warranty_' . $field['id'];
			$value      = isset( $_POST[ $field_name ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field_name ] ) ) : '';

			// Check required fields
			if ( $field['required'] && empty( $value ) ) {
				wc_add_notice(
					sprintf(
					/* translators: %s: field label */
						__( '%s is a required field.', 'warranty-cart' ),
						$field['label']
					),
					'error'
				);
			}

			// Validate email fields
			if ( 'email' === $field['type'] && ! empty( $value ) && ! is_email( $value ) ) {
				wc_add_notice(
					sprintf(
					/* translators: %s: field label */
						__( '%s must be a valid email address.', 'warranty-cart' ),
						$field['label']
					),
					'error'
				);
			}

			// Validate number fields
			if ( 'number' === $field['type'] && ! empty( $value ) && ! is_numeric( $value ) ) {
				wc_add_notice(
					sprintf(
					/* translators: %s: field label */
						__( '%s must be a number.', 'warranty-cart' ),
						$field['label']
					),
					'error'
				);
			}
		}

		/**
		 * Action after validating checkout fields
		 *
		 * @param array $fields Checkout fields.
		 */
		do_action( 'warranty_cart_after_validate_checkout_fields', $fields );
	}

	/**
	 * Save checkout fields to order
	 *
	 * Saves custom warranty checkout fields data to the order meta.
	 *
	 * @param WC_Order $order Order object.
	 */
	public function save_checkout_fields_to_order( WC_Order $order ): void {
		// Verify nonce for security
		if ( ! isset( $_POST['woocommerce-process-checkout-nonce'] ) ||
			! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['woocommerce-process-checkout-nonce'] ) ), 'woocommerce-process_checkout' ) ) {
			return;
		}

		// Only save if cart contains warranty products
		if ( ! $this->cart_has_warranty_products() ) {
			return;
		}

		$fields     = $this->get_checkout_fields();
		$field_data = array();

		/**
		 * Action before saving checkout fields to order
		 *
		 * @param WC_Order $order  Order object.
		 * @param array    $fields Checkout fields.
		 */
		do_action( 'warranty_cart_before_save_checkout_fields_to_order', $order, $fields );

		foreach ( $fields as $field ) {
			if ( ! $field['enabled'] ) {
				continue;
			}

			$field_name = 'warranty_' . $field['id'];
			$value      = isset( $_POST[ $field_name ] ) ? sanitize_text_field( wp_unslash( $_POST[ $field_name ] ) ) : '';

			if ( ! empty( $value ) ) {
				$field_data[ $field['id'] ] = array(
					'label' => $field['label'],
					'value' => $value,
					'type'  => $field['type'],
				);
			}
		}

		if ( ! empty( $field_data ) ) {
			$order->update_meta_data( '_warranty_checkout_fields', $field_data );
		}

		/**
		 * Action after saving checkout fields to order
		 *
		 * @param WC_Order $order      Order object.
		 * @param array    $fields     Checkout fields.
		 * @param array    $field_data Saved field data.
		 */
		do_action( 'warranty_cart_after_save_checkout_fields_to_order', $order, $fields, $field_data );
	}

	/**
	 * Register block checkout fields
	 *
	 * Registers custom warranty fields with WooCommerce Blocks checkout.
	 */
	public function register_block_checkout_fields(): void {
		// Register fields with WooCommerce Blocks using the proper API
		if ( function_exists( 'woocommerce_register_additional_checkout_field' ) ) {
			$this->register_blocks_fields();
		}
	}

	/**
	 * Register checkout fields with WooCommerce Blocks
	 *
	 * Handles the registration of warranty fields with the WooCommerce Blocks API.
	 */
	private function register_blocks_fields(): void {
		$warranty_fields = $this->get_checkout_fields();

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

		foreach ( $warranty_fields as $field ) {
			try {
				// Validate field configuration
				if ( ! $this->validate_field_config( $field ) ) {
					wc_get_logger()->warning(
						sprintf(
						/* translators: %s: field ID */
							__( 'Invalid warranty checkout field configuration for field ID: %s', 'warranty-cart' ),
							$field['id'] ?? 'unknown'
						)
					);
					continue;
				}

				$field_config = array(
					'id'       => 'warranty/' . $field['id'],
					'label'    => $field['label'],
					'location' => 'order', // Order information section
					'type'     => $this->map_field_type_to_blocks( $field['type'] ),
					'required' => $field['required'],
				);

				// Add placeholder
				if ( ! empty( $field['placeholder'] ) ) {
					$field_config['optionalLabel'] = $field['placeholder'];
				}

				// Add options for select fields
				if ( 'select' === $field['type'] && ! empty( $field['options'] ) && is_array( $field['options'] ) ) {
					$field_config['options'] = array_map(
						function ( $option ) {
							return array(
								'label' => $option,
								'value' => $option,
							);
						},
						$field['options']
					);
				}

				// Add validation callback
				$field_config['validate_callback'] = function ( $field_value ) use ( $field ) {
					return $this->validate_field_value( $field_value, $field );
				};

				// Add sanitize callback
				$field_config['sanitize_callback'] = function ( $field_value ) {
					return sanitize_text_field( $field_value );
				};

				woocommerce_register_additional_checkout_field( $field_config );
			} catch ( \Throwable $e ) {
				wc_get_logger()->error(
					sprintf(
					/* translators: 1: field ID, 2: error message */
						__( 'Error registering warranty checkout field "%1$s": %2$s', 'warranty-cart' ),
						$field['id'] ?? 'unknown',
						$e->getMessage()
					)
				);
			}
		}
	}

	/**
	 * Add checkout fields for WooCommerce Blocks
	 *
	 * Adds warranty fields to the WooCommerce Blocks checkout fields array.
	 *
	 * @param array $fields Checkout fields array.
	 *
	 * @return array Modified checkout fields array.
	 */
	public function add_block_checkout_fields( $fields ): array {
		// Only add fields if cart contains warranty products
		if ( ! $this->cart_has_warranty_products() ) {
			return $fields;
		}

		$warranty_fields = $this->get_checkout_fields();

		// Add fields to the order section
		if ( ! isset( $fields['order'] ) ) {
			$fields['order'] = array();
		}

		foreach ( $warranty_fields as $field ) {
			$field_key = 'warranty_' . $field['id'];

			$fields['order'][ $field_key ] = array(
				'type'     => $this->map_field_type_to_woocommerce( $field['type'] ),
				'label'    => $field['label'],
				'required' => $field['required'],
				'class'    => array( 'form-row-wide', 'warranty-field' ),
				'priority' => 10 + $field['order'],
			);

			// Add placeholder
			if ( ! empty( $field['placeholder'] ) ) {
				$fields['order'][ $field_key ]['placeholder'] = $field['placeholder'];
			}

			// Add options for select fields
			if ( 'select' === $field['type'] && ! empty( $field['options'] ) ) {
				$fields['order'][ $field_key ]['options'] = array_combine( $field['options'], $field['options'] );
			}
		}

		/**
		 * Filter checkout fields for WooCommerce Blocks.
		 *
		 * @param array $fields          Checkout fields array.
		 * @param array $warranty_fields Warranty fields configuration.
		 */
		return apply_filters( 'warranty_cart_block_checkout_fields', $fields, $warranty_fields );
	}

	/**
	 * Save Blocks field value to order
	 *
	 * Saves warranty field values from WooCommerce Blocks to order meta.
	 *
	 * @param string               $key       Field key.
	 * @param mixed                $value     Field value.
	 * @param string               $group     Field group.
	 * @param WC_Order|WC_Customer $wc_object Order or customer object.
	 */
	public function save_blocks_field_to_order( $key, $value, $group, $wc_object ): void {
		try {
			// Only handle warranty fields
			if ( strpos( $key, 'warranty/' ) !== 0 ) {
				return;
			}

			// Only save to orders
			if ( ! $wc_object instanceof WC_Order ) {
				return;
			}

			// Extract field ID from key (remove 'warranty/' prefix)
			$field_id = str_replace( 'warranty/', '', $key );

			if ( empty( $field_id ) ) {
				wc_get_logger()->warning( __( 'Empty field ID in warranty checkout field save attempt', 'warranty-cart' ) );

				return;
			}

			// Get field configuration
			$fields       = $this->get_checkout_fields();
			$field_config = null;

			foreach ( $fields as $field ) {
				if ( $field['id'] === $field_id ) {
					$field_config = $field;
					break;
				}
			}

			if ( ! $field_config ) {
				wc_get_logger()->warning(
					sprintf(
					/* translators: %s: field ID */
						__( 'Field configuration not found for warranty field ID: %s', 'warranty-cart' ),
						$field_id
					)
				);

				return;
			}

			// Get existing field data
			$existing_data = $wc_object->get_meta( '_warranty_checkout_fields', true );
			if ( ! is_array( $existing_data ) ) {
				$existing_data = array();
			}

			// Add/update field data
			$existing_data[ $field_id ] = array(
				'label' => $field_config['label'],
				'value' => $value,
				'type'  => $field_config['type'],
			);

			$wc_object->update_meta_data( '_warranty_checkout_fields', $existing_data );
		} catch ( \Throwable $e ) {
			wc_get_logger()->error(
				sprintf(
				/* translators: 1: field key, 2: error message */
					__( 'Error saving warranty checkout field "%1$s": %2$s', 'warranty-cart' ),
					$key,
					$e->getMessage()
				)
			);
		}
	}

	/**
	 * Map field type to WooCommerce Blocks field type
	 *
	 * Converts internal field types to WooCommerce Blocks compatible types.
	 *
	 * @param string $field_type Internal field type.
	 *
	 * @return string WooCommerce Blocks field type.
	 */
	private function map_field_type_to_blocks( $field_type ): string {
		$mapping = array(
			'text'     => 'text',
			'email'    => 'text', // Blocks doesn't have email type, use text
			'number'   => 'text', // Blocks doesn't have number type, use text
			'textarea' => 'text', // Blocks doesn't have textarea type, use text
			'select'   => 'select',
			'checkbox' => 'checkbox',
			'radio'    => 'text', // Blocks doesn't have radio type, use text
		);

		return $mapping[ $field_type ] ?? 'text';
	}

	/**
	 * Validate field configuration
	 *
	 * Validates the structure and content of a checkout field configuration.
	 *
	 * @param array $field Field configuration array.
	 *
	 * @return bool True if valid, false otherwise
	 */
	private function validate_field_config( array $field ): bool {
		// Check required fields
		if ( empty( $field['id'] ) || empty( $field['label'] ) || ! isset( $field['type'] ) ) {
			return false;
		}

		// Validate field type
		$valid_types = array( 'text', 'email', 'number', 'textarea', 'select', 'checkbox', 'radio' );
		if ( ! in_array( $field['type'], $valid_types, true ) ) {
			return false;
		}

		// Validate select options
		if ( 'select' === $field['type'] && ! empty( $field['options'] ) && ! is_array( $field['options'] ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Validate field value
	 *
	 * Validates a field value against field configuration requirements.
	 *
	 * @param mixed $field_value The value to validate.
	 * @param array $field       Field configuration array.
	 *
	 * @return WP_Error|true WP_Error on validation failure, true on success.
	 */
	private function validate_field_value( $field_value, $field ) {
		// Check required fields
		if ( $field['required'] && empty( $field_value ) ) {
			return new WP_Error(
				'field_required',
				/* translators: %s: field label */
				sprintf( __( '%s is a required field.', 'warranty-cart' ), $field['label'] )
			);
		}

		// Validate email fields
		if ( 'email' === $field['type'] && ! empty( $field_value ) && ! is_email( $field_value ) ) {
			return new WP_Error(
				'invalid_email',
				/* translators: %s: field label */
				sprintf( __( '%s must be a valid email address.', 'warranty-cart' ), $field['label'] )
			);
		}

		// Validate number fields
		if ( 'number' === $field['type'] && ! empty( $field_value ) && ! is_numeric( $field_value ) ) {
			return new WP_Error(
				'invalid_number',
				/* translators: %s: field label */
				sprintf( __( '%s must be a number.', 'warranty-cart' ), $field['label'] )
			);
		}

		return true;
	}

	/**
	 * Get checkout fields
	 *
	 * Retrieves configured checkout fields from database or returns defaults.
	 *
	 * @return array Array of checkout field configurations.
	 */
	private function get_checkout_fields(): array {
		$fields = get_option( 'warranty_checkout_fields', array() );

		// Filter enabled fields and sort by order
		$enabled_fields = array_filter(
			$fields,
			function ( $field ) {
				return $field['enabled'];
			}
		);

		usort(
			$enabled_fields,
			function ( $a, $b ) {
				return $a['order'] <=> $b['order'];
			}
		);

		/**
		 * Filter checkout fields configuration.
		 *
		 * @param array $enabled_fields Enabled and sorted checkout fields.
		 * @param array $fields         Raw fields from database.
		 */
		return apply_filters( 'warranty_cart_checkout_fields_config', $enabled_fields, $fields );
	}

	/**
	 * Check if cart contains warranty products
	 *
	 * Determines whether the current cart contains any warranty products.
	 *
	 * @return bool True if cart contains warranty products, false otherwise.
	 */
	public function cart_has_warranty_products(): bool {
		if ( ! WC()->cart ) {
			return false;
		}

		foreach ( WC()->cart->get_cart() as $cart_item ) {
			$product = $cart_item['data'];
			if ( $product && $product->get_meta( '_warranty_product_type', true ) ) {
				return true;
			}
		}

		return false;
	}
}
