<?php
defined( 'ABSPATH' ) || exit;

class Formulate_Pricing_Ajax {

	public static function init() {
		// Frontend
		add_action( 'wp_ajax_formulate_pricing_submit_form', array( __CLASS__, 'handle_submit' ) );
		add_action( 'wp_ajax_nopriv_formulate_pricing_submit_form', array( __CLASS__, 'handle_submit' ) );

		// Admin – form builder
		add_action( 'wp_ajax_formulate_pricing_save_form', array( __CLASS__, 'save_form' ) );
		add_action( 'wp_ajax_formulate_pricing_duplicate_form', array( __CLASS__, 'duplicate_form' ) );
		add_action( 'wp_ajax_formulate_pricing_delete_form', array( __CLASS__, 'delete_form' ) );

		// Admin – entries
		add_action( 'wp_ajax_formulate_pricing_get_entry', array( __CLASS__, 'get_entry' ) );
		add_action( 'wp_ajax_formulate_pricing_delete_entry', array( __CLASS__, 'delete_entry' ) );
		add_action( 'wp_ajax_formulate_pricing_update_entry_status', array( __CLASS__, 'update_entry_status' ) );
		add_action( 'wp_ajax_formulate_pricing_bulk_entry_action', array( __CLASS__, 'bulk_entry_action' ) );

		// Export CSV
		add_action( 'admin_post_formulate_pricing_export_entries', array( __CLASS__, 'export_entries_csv' ) );

		// Form preview (admin only — requires valid nonce).
		add_action( 'wp_ajax_formulate_pricing_preview_form', array( __CLASS__, 'preview_form' ) );

		// Create a hidden-from-catalog WooCommerce product for a form
		add_action( 'wp_ajax_formulate_pricing_create_product_ajax', array( __CLASS__, 'create_form_product' ) );
	}

	// -------------------------------------------------------------------------
	// Frontend submission
	// -------------------------------------------------------------------------

	public static function handle_submit() {
		// Nonce verified below after form_id is read
		$form_id = intval( $_POST['formulate_pricing_form_id'] ?? $_POST['form_id'] ?? 0 );
		if ( ! $form_id ) {
			wp_send_json_error( array( 'message' => __( 'Invalid form ID.', 'formulate-pricing' ) ) );
		}

		$nonce = sanitize_text_field( isset( $_POST['formulate_pricing_nonce'] ) ? wp_unslash( $_POST['formulate_pricing_nonce'] ) : '' );
		if ( ! wp_verify_nonce( $nonce, 'formulate_pricing_submit_' . $form_id ) ) {
			wp_send_json_error( array( 'message' => __( 'Security check failed.', 'formulate-pricing' ) ) );
		}

		$form = Formulate_Pricing_Form::get( $form_id );
		if ( ! $form ) {
			wp_send_json_error( array( 'message' => __( 'Form not found.', 'formulate-pricing' ) ) );
		}

		$config     = $form->form_config;
		$settings   = isset( $config['settings'] ) ? $config['settings'] : array();
		$all_fields = Formulate_Pricing_Form::get_all_fields( $config );

		// Sanitize & validate
		$fields_post = isset( $_POST['formulate_pricing_fields'] ) ? wp_unslash( $_POST['formulate_pricing_fields'] ) : array(); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
		$entry_data  = array();
		$errors      = array();
		$layout_types = array( 'heading', 'paragraph', 'divider', 'spacer', 'hidden' );

		foreach ( $all_fields as $field ) {
			$field_id   = isset( $field['id'] ) ? $field['id'] : '';
			$field_type = isset( $field['type'] ) ? $field['type'] : 'text';
			$required   = ! empty( $field['required'] );
			$label      = isset( $field['label'] ) ? $field['label'] : $field_id;

			if ( in_array( $field_type, $layout_types, true ) ) {
				continue;
			}

			$raw_value = isset( $fields_post[ $field_id ] ) ? $fields_post[ $field_id ] : null;

			switch ( $field_type ) {
				case 'email':
					$value = sanitize_email( $raw_value ?? '' );
					break;
				case 'url':
					$value = esc_url_raw( $raw_value ?? '' );
					break;
				case 'textarea':
					$value = sanitize_textarea_field( $raw_value ?? '' );
					break;
				case 'number':
					$value = is_numeric( $raw_value ) ? floatval( $raw_value ) : '';
					break;
				case 'checkbox':
					$value = Formulate_Pricing_Form::normalize_multi_value( $raw_value );
					break;
				case 'card_choice':
					if ( ! empty( $field['multi_select'] ) ) {
						$value = Formulate_Pricing_Form::normalize_multi_value( $raw_value );
					} else {
						$value = sanitize_text_field( $raw_value ?? '' );
					}
					break;
				default:
					$value = sanitize_text_field( $raw_value ?? '' );
			}

			if ( $required && ( '' === $value || array() === $value || null === $value ) ) {
				/* translators: %s: field label */
				$errors[ $field_id ] = sprintf( esc_html__( '%s is required.', 'formulate-pricing' ), esc_html( $label ) );
			}

			if ( 'email' === $field_type && $value && ! is_email( $value ) ) {
				$errors[ $field_id ] = esc_html__( 'Please enter a valid email address.', 'formulate-pricing' );
			}

			$entry_data[ $field_id ]             = $value;
			$entry_data[ '_label_' . $field_id ] = $label;
		}

		if ( ! empty( $errors ) ) {
			wp_send_json_error( array( 'message' => __( 'Please fix the errors below.', 'formulate-pricing' ), 'errors' => $errors ) );
		}

		// WooCommerce path
		if ( ! empty( $settings['wc_enabled'] ) ) {
			$result = self::handle_wc_submit( $form_id, $entry_data, $config );
			if ( is_wp_error( $result ) ) {
				wp_send_json_error( array( 'message' => $result->get_error_message() ) );
			}

			self::send_notifications( $form, $config, $entry_data, $all_fields );
			wp_send_json_success(
				array(
					'redirect'  => $result['redirect'],
					'entry_id'  => $result['entry_id'],
					'type'      => 'woocommerce',
				)
			);
		}

		// Standard save
		$entry_id = Formulate_Pricing_Entry::create( $form_id, $entry_data );
		self::send_notifications( $form, $config, $entry_data, $all_fields );

		$response = array(
			'entry_id'        => $entry_id,
			'success_message' => wp_kses_post( isset( $settings['success_message'] ) ? $settings['success_message'] : 'Thank you!' ),
			'type'            => 'standard',
		);

		if ( ! empty( $settings['redirect_url'] ) ) {
			$response['redirect'] = esc_url( $settings['redirect_url'] );
		}

		wp_send_json_success( $response );
	}

	// -------------------------------------------------------------------------
	// Email notifications
	// -------------------------------------------------------------------------

	private static function send_notifications( $form, $config, $entry_data, $all_fields ) {
		$notif = isset( $config['notifications'] ) ? $config['notifications'] : array();
		if ( empty( $notif ) ) {
			return;
		}

		$form_title = $form->title;

		// Build a readable summary of the submission
		$summary_rows = '';
		foreach ( $all_fields as $field ) {
			$fid   = isset( $field['id'] ) ? $field['id'] : '';
			$label = isset( $field['label'] ) ? $field['label'] : $fid;
			if ( ! isset( $entry_data[ $fid ] ) ) {
				continue;
			}
			$val = $entry_data[ $fid ];
			if ( is_array( $val ) ) {
				$val = implode( ', ', $val );
			}
			if ( '' === (string) $val ) {
				continue;
			}
			$summary_rows .= $label . ': ' . $val . "\n";
		}

		// Helper: replace {form_title} and {field_label} placeholders
		$replace = function ( $text ) use ( $form_title, $entry_data, $all_fields ) {
			$text = str_replace( '{form_title}', $form_title, $text );
			foreach ( $all_fields as $field ) {
				$fid   = isset( $field['id'] ) ? $field['id'] : '';
				$label = isset( $field['label'] ) ? $field['label'] : $fid;
				if ( isset( $entry_data[ $fid ] ) ) {
					$val = is_array( $entry_data[ $fid ] ) ? implode( ', ', $entry_data[ $fid ] ) : $entry_data[ $fid ];
					$text = str_replace( '{' . $label . '}', $val, $text );
				}
			}
			return $text;
		};

		$headers = array( 'Content-Type: text/plain; charset=UTF-8' );

		// ── Admin notification ──────────────────────────────────────────────────
		if ( ! empty( $notif['admin_enabled'] ) ) {
			$to = get_option( 'admin_email' );
			if ( ! empty( $notif['admin_to'] ) ) {
				$candidate = sanitize_email( $notif['admin_to'] );
				if ( is_email( $candidate ) ) {
					$to = $candidate;
				}
			}
			$subject = ! empty( $notif['admin_subject'] ) ? $notif['admin_subject'] : 'New submission: ' . $form_title;
			$subject = $replace( $subject );
			$body    = "New submission for form: " . $form_title . "\n\n" . $summary_rows;

			// Reply-To
			$reply_field = isset( $notif['admin_reply_to'] ) ? $notif['admin_reply_to'] : '';
			if ( $reply_field && isset( $entry_data[ $reply_field ] ) && is_email( $entry_data[ $reply_field ] ) ) {
				$headers[] = 'Reply-To: ' . sanitize_email( $entry_data[ $reply_field ] );
			}

			wp_mail( $to, $subject, $body, $headers );
		}

		// ── Submitter notification ──────────────────────────────────────────────
		if ( ! empty( $notif['user_enabled'] ) ) {
			$email_field = isset( $notif['user_email_field'] ) ? $notif['user_email_field'] : '';
			$user_email  = isset( $entry_data[ $email_field ] ) ? $entry_data[ $email_field ] : '';

			if ( $user_email && is_email( $user_email ) ) {
				$subject = ! empty( $notif['user_subject'] ) ? $notif['user_subject'] : 'Thank you for your submission';
				$subject = $replace( $subject );
				$message = ! empty( $notif['user_message'] ) ? $notif['user_message'] : "Hi,\n\nWe have received your submission and will be in touch soon.\n\nThank you!";
				$message = $replace( $message );

				wp_mail( $user_email, $subject, $message, $headers );
			}
		}
	}

	private static function handle_wc_submit( $form_id, $entry_data, $config ) {
		$settings = isset( $config['settings'] ) ? $config['settings'] : array();

		$product_id = intval( isset( $settings['wc_product_id'] ) ? $settings['wc_product_id'] : 0 );
		if ( ! $product_id ) {
			$product_id = intval( get_option( 'formulate_pricing_product_id', 0 ) );
		}
		if ( ! $product_id ) {
			return new WP_Error( 'no_product', esc_html__( 'WooCommerce product not configured.', 'formulate-pricing' ) );
		}

		$total = Formulate_Pricing_Form::calculate_priced_total( $config, $entry_data );
		if ( $total < 0 ) {
			$total = 0.0;
		}

		$entry_id = Formulate_Pricing_Entry::create(
			$form_id,
			$entry_data,
			array(
				'payment_status' => 'pending',
			)
		);

		if ( ! $entry_id ) {
			return new WP_Error( 'entry_failed', esc_html__( 'Could not save your submission.', 'formulate-pricing' ) );
		}

		WC()->cart->empty_cart();
		WC()->cart->add_to_cart(
			$product_id,
			1,
			0,
			array(),
			array(
				'formulate_pricing' => array(
					'custom_price' => $total,
					'form_id'      => $form_id,
					'entry_id'     => $entry_id,
					'entry_data'   => $entry_data,
				),
			)
		);

		return array(
			'redirect' => wc_get_checkout_url(),
			'entry_id' => $entry_id,
		);
	}

	// -------------------------------------------------------------------------
	// Admin – forms
	// -------------------------------------------------------------------------

	public static function save_form() {
		check_ajax_referer( 'formulate_pricing_builder_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Unauthorized.', 'formulate-pricing' ) ) );
		}

		$form_id     = intval( $_POST['formulate_pricing_form_id'] ?? $_POST['form_id'] ?? 0 );
		$title       = sanitize_text_field( isset( $_POST['title'] ) ? wp_unslash( $_POST['title'] ) : 'New Form' );
		$form_config = isset( $_POST['form_config'] ) ? wp_unslash( $_POST['form_config'] ) : ''; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized

		if ( is_string( $form_config ) ) {
			$form_config = json_decode( $form_config, true );
		}
		if ( ! is_array( $form_config ) ) {
			wp_send_json_error( array( 'message' => __( 'Invalid form configuration.', 'formulate-pricing' ) ) );
		}

		$form_config = self::sanitize_form_config( $form_config );

		if ( $form_id ) {
			Formulate_Pricing_Form::update( $form_id, array( 'title' => $title, 'form_config' => $form_config ) );
			wp_send_json_success(
				array(
					'form_id'       => $form_id,
					'preview_nonce' => wp_create_nonce( 'formulate_pricing_preview_' . $form_id ),
					'message'       => __( 'Form saved.', 'formulate-pricing' ),
				)
			);
		} else {
			$new_id = Formulate_Pricing_Form::create( array( 'title' => $title, 'form_config' => $form_config ) );
			if ( $new_id ) {
				wp_send_json_success(
					array(
						'form_id'       => $new_id,
						'preview_nonce' => wp_create_nonce( 'formulate_pricing_preview_' . $new_id ),
						'message'       => __( 'Form created.', 'formulate-pricing' ),
					)
				);
			} else {
				wp_send_json_error( array( 'message' => __( 'Failed to create form.', 'formulate-pricing' ) ) );
			}
		}
	}

	public static function duplicate_form() {
		check_ajax_referer( 'formulate_pricing_admin_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error();
		}
		$form_id = intval( $_POST['formulate_pricing_form_id'] ?? $_POST['form_id'] ?? 0 );
		$new_id  = Formulate_Pricing_Form::duplicate( $form_id );
		if ( $new_id ) {
			wp_send_json_success( array( 'new_id' => $new_id ) );
		} else {
			wp_send_json_error( array( 'message' => __( 'Failed to duplicate form.', 'formulate-pricing' ) ) );
		}
	}

	public static function delete_form() {
		check_ajax_referer( 'formulate_pricing_admin_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error();
		}
		$form_id = intval( $_POST['formulate_pricing_form_id'] ?? $_POST['form_id'] ?? 0 );
		if ( Formulate_Pricing_Form::delete( $form_id ) !== false ) {
			wp_send_json_success();
		} else {
			wp_send_json_error( array( 'message' => __( 'Failed to delete form.', 'formulate-pricing' ) ) );
		}
	}

	// -------------------------------------------------------------------------
	// Admin – entries
	// -------------------------------------------------------------------------

	public static function get_entry() {
		check_ajax_referer( 'formulate_pricing_admin_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error();
		}
		$entry_id = intval( isset( $_POST['entry_id'] ) ? $_POST['entry_id'] : 0 );
		$entry    = Formulate_Pricing_Entry::get( $entry_id );
		if ( $entry ) {
			Formulate_Pricing_Entry::update_status( $entry_id, 'read' );
			wp_send_json_success( Formulate_Pricing_Entry::format_for_admin( $entry ) );
		} else {
			wp_send_json_error( array( 'message' => __( 'Entry not found.', 'formulate-pricing' ) ) );
		}
	}

	public static function delete_entry() {
		check_ajax_referer( 'formulate_pricing_admin_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error();
		}
		$entry_id = intval( isset( $_POST['entry_id'] ) ? $_POST['entry_id'] : 0 );
		Formulate_Pricing_Entry::delete( $entry_id );
		wp_send_json_success();
	}

	public static function update_entry_status() {
		check_ajax_referer( 'formulate_pricing_admin_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error();
		}
		$entry_id = intval( isset( $_POST['entry_id'] ) ? $_POST['entry_id'] : 0 );
		$status   = sanitize_text_field( isset( $_POST['status'] ) ? wp_unslash( $_POST['status'] ) : '' );
		Formulate_Pricing_Entry::update_status( $entry_id, $status );
		wp_send_json_success();
	}

	public static function bulk_entry_action() {
		check_ajax_referer( 'formulate_pricing_admin_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error();
		}
		$action = sanitize_text_field( isset( $_POST['bulk_action'] ) ? wp_unslash( $_POST['bulk_action'] ) : '' );
		$ids    = array_map( 'intval', isset( $_POST['ids'] ) ? (array) $_POST['ids'] : array() );

		if ( empty( $ids ) ) {
			wp_send_json_error( array( 'message' => __( 'No entries selected.', 'formulate-pricing' ) ) );
		}

		if ( 'delete' === $action ) {
			Formulate_Pricing_Entry::bulk_delete( $ids );
			wp_send_json_success(
				array(
					/* translators: %d: number of entries deleted */
					'message' => sprintf( __( '%d entries deleted.', 'formulate-pricing' ), count( $ids ) ),
				)
			);
		} elseif ( in_array( $action, array( 'read', 'unread', 'starred', 'trash' ), true ) ) {
			foreach ( $ids as $id ) {
				Formulate_Pricing_Entry::update_status( $id, $action );
			}
			wp_send_json_success(
				array(
					/* translators: %d: number of entries updated */
					'message' => sprintf( __( '%d entries updated.', 'formulate-pricing' ), count( $ids ) ),
				)
			);
		}

		wp_send_json_error( array( 'message' => __( 'Unknown action.', 'formulate-pricing' ) ) );
	}

	public static function export_entries_csv() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'formulate-pricing' ) );
		}
		check_admin_referer( 'formulate_pricing_export_entries' );

		$form_id = isset( $_GET['form_id'] ) ? absint( $_GET['form_id'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- capability + referer checked above.
		$csv     = Formulate_Pricing_Entry::export_csv( array( 'form_id' => $form_id ) );

		$filename = 'entries' . ( $form_id ? '-form-' . $form_id : '' ) . '-' . gmdate( 'Y-m-d' ) . '.csv';
		header( 'Content-Type: text/csv; charset=utf-8' );
		header( 'Content-Disposition: attachment; filename="' . $filename . '"' );
		header( 'Pragma: no-cache' );
		echo $csv; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		exit;
	}

	// -------------------------------------------------------------------------
	// Preview
	// -------------------------------------------------------------------------

	public static function preview_form() {
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_die( esc_html__( 'Unauthorized.', 'formulate-pricing' ) );
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified below.
		$form_id = intval( isset( $_GET['form_id'] ) ? $_GET['form_id'] : 0 );
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- nonce verified below.
		$nonce   = sanitize_text_field( isset( $_GET['nonce'] ) ? wp_unslash( $_GET['nonce'] ) : '' );

		if ( ! $form_id ) {
			wp_die( esc_html__( 'Invalid form.', 'formulate-pricing' ) );
		}

		if ( wp_verify_nonce( $nonce, 'formulate_pricing_preview_' . $form_id ) ) {
			// Per-form preview nonce accepted.
		} elseif ( wp_verify_nonce( $nonce, 'formulate_pricing_builder_nonce' ) ) {
			// Builder session nonce accepted for admins already verified above.
		} else {
			wp_die( esc_html__( 'Security check failed.', 'formulate-pricing' ) );
		}

		$form = Formulate_Pricing_Form::get( $form_id );
		if ( ! $form ) {
			wp_die( esc_html__( 'Form not found.', 'formulate-pricing' ) );
		}

		if ( ! defined( 'FORMULATE_PRICING_PREVIEW_MODE' ) ) {
			define( 'FORMULATE_PRICING_PREVIEW_MODE', true );
		}

		$form_html = Formulate_Pricing_Renderer::render( $form_id, true );

		// Collect enqueueable assets
		ob_start();
		wp_add_inline_style(
			'formulate-pricing-form',
			'*,*::before,*::after{box-sizing:border-box}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Inter","Segoe UI",sans-serif;background:#f1f3f8;min-height:100vh}.bfp-body{padding:40px 20px;}.bfp-wrap{max-width:700px;margin:0 auto;}'
		);
		wp_print_styles( 'formulate-pricing-form' );
		$styles = ob_get_clean();

		ob_start();
		wp_print_scripts( 'jquery' );
		wp_print_scripts( 'formulate-pricing-form' );
		$scripts = ob_get_clean();

		?><!DOCTYPE html>
<html <?php language_attributes(); ?>>
<head>
<meta charset="<?php bloginfo( 'charset' ); ?>">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title><?php echo esc_html( $form->title ); ?> — Preview</title>
<?php echo $styles; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</head>
<body>

<div class="bfp-body">
	<div class="bfp-wrap">
		<?php echo wp_kses( $form_html, Formulate_Pricing_Renderer::get_form_markup_allowed_html() ); ?>
	</div>
</div>

		<?php echo $scripts; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
</body>
</html>
		<?php
		exit;
	}

	// -------------------------------------------------------------------------
	// Create a hidden-from-catalog WooCommerce product for a form
	// -------------------------------------------------------------------------

	public static function create_form_product() {
		check_ajax_referer( 'formulate_pricing_builder_nonce', 'nonce' );
		if ( ! current_user_can( 'manage_options' ) ) {
			wp_send_json_error( array( 'message' => __( 'Unauthorized.', 'formulate-pricing' ) ) );
		}
		if ( ! class_exists( 'WC_Product_Simple' ) ) {
			wp_send_json_error( array( 'message' => __( 'WooCommerce is not available.', 'formulate-pricing' ) ) );
		}

		$form_title = sanitize_text_field( wp_unslash( isset( $_POST['form_title'] ) ? $_POST['form_title'] : __( 'Formulate Pricing Form Product', 'formulate-pricing' ) ) );

		$product = new WC_Product_Simple();
		$product->set_name( $form_title );
		$product->set_status( 'publish' );
		$product->set_catalog_visibility( 'hidden' ); // excluded from shop & search
		$product->set_virtual( true );
		$product->set_regular_price( '0' );
		$product->set_description( sprintf(
			/* translators: %s form title */
			__( 'Auto-created product for the "%s" form. Do not list this product manually.', 'formulate-pricing' ),
			$form_title
		) );

		$product_id = $product->save();

		if ( ! $product_id ) {
			wp_send_json_error( array( 'message' => __( 'Could not create product.', 'formulate-pricing' ) ) );
		}

		wp_send_json_success( array(
			'product_id'  => $product_id,
			'name'        => $product->get_name(),
			'edit_url'    => get_edit_post_link( $product_id, 'raw' ),
		) );
	}

	// -------------------------------------------------------------------------
	// Helpers
	// -------------------------------------------------------------------------

	/**
	 * Sanitize a CSS color value (hex, transparent, rgb, or rgba).
	 *
	 * @param string $value Raw color.
	 * @return string Sanitized color or empty string if invalid.
	 */
	private static function sanitize_css_color( $value ) {
		$value = trim( (string) $value );
		if ( '' === $value ) {
			return '';
		}

		$hex = sanitize_hex_color( $value );
		if ( $hex ) {
			return $hex;
		}

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

		if ( preg_match( '/^rgba?\(\s*\d{1,3}\s*,\s*\d{1,3}\s*,\s*\d{1,3}(\s*,\s*(0|1|0?\.\d+))?\s*\)$/i', $value ) ) {
			return $value;
		}

		return '';
	}

	/**
	 * Sanitize decoded form configuration before storage.
	 *
	 * @param array $config Raw config from JSON decode.
	 * @return array
	 */
	private static function sanitize_form_config( $config ) {
		if ( ! is_array( $config ) ) {
			return Formulate_Pricing_Form::default_config();
		}

		$defaults = Formulate_Pricing_Form::default_config();

		return array(
			'settings'      => self::sanitize_form_settings( isset( $config['settings'] ) ? $config['settings'] : array(), $defaults['settings'] ),
			'styling'       => self::sanitize_form_styling( isset( $config['styling'] ) ? $config['styling'] : array(), $defaults['styling'] ),
			'steps'         => self::sanitize_form_steps( isset( $config['steps'] ) ? $config['steps'] : array() ),
			'notifications' => self::sanitize_form_notifications( isset( $config['notifications'] ) ? $config['notifications'] : array(), $defaults['notifications'] ),
		);
	}

	/**
	 * @param array $settings Raw settings.
	 * @param array $defaults Default settings.
	 * @return array
	 */
	private static function sanitize_form_settings( $settings, $defaults ) {
		if ( ! is_array( $settings ) ) {
			return $defaults;
		}

		$out = $defaults;
		foreach ( array( 'submit_text', 'next_text', 'prev_text' ) as $key ) {
			if ( isset( $settings[ $key ] ) ) {
				$out[ $key ] = sanitize_text_field( $settings[ $key ] );
			}
		}
		if ( isset( $settings['success_message'] ) ) {
			$out['success_message'] = wp_kses_post( $settings['success_message'] );
		}
		if ( isset( $settings['redirect_url'] ) ) {
			$out['redirect_url'] = esc_url_raw( $settings['redirect_url'] );
		}
		$out['multi_step']    = ! empty( $settings['multi_step'] );
		$out['show_progress'] = ! empty( $settings['show_progress'] );
		$out['wc_enabled']    = ! empty( $settings['wc_enabled'] );
		$out['wc_product_id'] = isset( $settings['wc_product_id'] ) ? absint( $settings['wc_product_id'] ) : 0;

		return $out;
	}

	/**
	 * @param array $styling Raw styling.
	 * @param array $defaults Default styling.
	 * @return array
	 */
	private static function sanitize_form_styling( $styling, $defaults ) {
		if ( ! is_array( $styling ) ) {
			return $defaults;
		}

		$out = $defaults;
		$color_keys = array(
			'primary_color',
			'bg_color',
			'text_color',
			'label_color',
			'input_bg',
			'input_border',
			'button_bg',
			'button_text_color',
			'card_bg',
			'card_border',
			'card_selected_bg',
			'card_selected_border',
			'step_track',
			'step_text',
		);
		foreach ( $color_keys as $key ) {
			if ( ! isset( $styling[ $key ] ) ) {
				continue;
			}
			$color = self::sanitize_css_color( $styling[ $key ] );
			if ( $color ) {
				$out[ $key ] = $color;
			} elseif ( isset( $defaults[ $key ] ) ) {
				$out[ $key ] = $defaults[ $key ];
			}
		}

		$int_keys = array( 'border_radius', 'font_size', 'button_border_radius', 'form_width', 'form_padding', 'field_gap', 'input_border_width' );
		foreach ( $int_keys as $key ) {
			if ( isset( $styling[ $key ] ) ) {
				$out[ $key ] = (string) max( 0, absint( $styling[ $key ] ) );
			}
		}

		foreach ( array( 'active_preset', 'bg_context' ) as $key ) {
			if ( isset( $styling[ $key ] ) ) {
				$out[ $key ] = sanitize_key( $styling[ $key ] );
			}
		}

		return $out;
	}

	/**
	 * @param array $notifications Raw notifications.
	 * @param array $defaults Default notifications.
	 * @return array
	 */
	private static function sanitize_form_notifications( $notifications, $defaults ) {
		if ( ! is_array( $notifications ) ) {
			return $defaults;
		}

		$out = $defaults;
		$out['admin_enabled']    = ! empty( $notifications['admin_enabled'] );
		$out['user_enabled']     = ! empty( $notifications['user_enabled'] );
		$out['admin_reply_to']   = isset( $notifications['admin_reply_to'] ) ? sanitize_key( $notifications['admin_reply_to'] ) : '';
		$out['user_email_field'] = isset( $notifications['user_email_field'] ) ? sanitize_key( $notifications['user_email_field'] ) : '';

		if ( isset( $notifications['admin_to'] ) ) {
			$out['admin_to'] = sanitize_email( $notifications['admin_to'] );
		}
		foreach ( array( 'admin_subject', 'user_subject' ) as $key ) {
			if ( isset( $notifications[ $key ] ) ) {
				$out[ $key ] = sanitize_text_field( $notifications[ $key ] );
			}
		}
		if ( isset( $notifications['user_message'] ) ) {
			$out['user_message'] = sanitize_textarea_field( $notifications['user_message'] );
		}

		return $out;
	}

	/**
	 * @param array $steps Raw steps.
	 * @return array
	 */
	private static function sanitize_form_steps( $steps ) {
		if ( ! is_array( $steps ) ) {
			return array();
		}

		$sanitized = array();
		foreach ( $steps as $step ) {
			if ( ! is_array( $step ) ) {
				continue;
			}
			$sanitized[] = array(
				'id'     => isset( $step['id'] ) ? sanitize_key( $step['id'] ) : '',
				'title'  => isset( $step['title'] ) ? sanitize_text_field( $step['title'] ) : '',
				'fields' => self::sanitize_form_fields( isset( $step['fields'] ) ? $step['fields'] : array() ),
			);
		}

		return $sanitized;
	}

	/**
	 * @param array $fields Raw fields.
	 * @return array
	 */
	private static function sanitize_form_fields( $fields ) {
		if ( ! is_array( $fields ) ) {
			return array();
		}

		$allowed_types = array(
			'text',
			'email',
			'phone',
			'number',
			'textarea',
			'url',
			'date',
			'time',
			'hidden',
			'radio',
			'checkbox',
			'select',
			'card_choice',
			'heading',
			'paragraph',
			'divider',
			'spacer',
			'booking_date',
			'booking_timeslot',
			'booking_postcode',
		);

		$sanitized = array();
		foreach ( $fields as $field ) {
			if ( ! is_array( $field ) ) {
				continue;
			}

			$type = isset( $field['type'] ) ? sanitize_key( $field['type'] ) : 'text';
			if ( ! in_array( $type, $allowed_types, true ) ) {
				$type = 'text';
			}

			$clean = array(
				'id'       => isset( $field['id'] ) ? sanitize_key( $field['id'] ) : '',
				'type'     => $type,
				'label'    => isset( $field['label'] ) ? sanitize_text_field( $field['label'] ) : '',
				'required' => ! empty( $field['required'] ),
			);

			if ( isset( $field['placeholder'] ) ) {
				$clean['placeholder'] = sanitize_text_field( $field['placeholder'] );
			}
			if ( isset( $field['help_text'] ) ) {
				$clean['help_text'] = sanitize_text_field( $field['help_text'] );
			}
			if ( isset( $field['width'] ) ) {
				$clean['width'] = in_array( (string) $field['width'], array( '50', '100' ), true ) ? (string) $field['width'] : '100';
			}
			if ( isset( $field['default_value'] ) ) {
				$clean['default_value'] = sanitize_text_field( $field['default_value'] );
			}
			if ( isset( $field['content'] ) ) {
				$clean['content'] = wp_kses_post( $field['content'] );
			}
			if ( isset( $field['heading_level'] ) ) {
				$level = sanitize_key( $field['heading_level'] );
				$clean['heading_level'] = in_array( $level, array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6' ), true ) ? $level : 'h3';
			}
			if ( ! empty( $field['multi_select'] ) ) {
				$clean['multi_select'] = true;
			}
			if ( isset( $field['options'] ) && is_array( $field['options'] ) ) {
				$clean['options'] = self::sanitize_field_options( $field['options'] );
			}

			$sanitized[] = $clean;
		}

		return $sanitized;
	}

	/**
	 * @param array $options Raw field options.
	 * @return array
	 */
	private static function sanitize_field_options( $options ) {
		$sanitized = array();
		$allowed_desc_html = array(
			'b'      => array(),
			'strong' => array(),
			'em'     => array(),
			'i'      => array(),
			'u'      => array(),
			'br'     => array(),
			'span'   => array( 'style' => array(), 'class' => array() ),
			'a'      => array( 'href' => array(), 'target' => array(), 'rel' => array() ),
			'small'  => array(),
		);

		foreach ( $options as $opt ) {
			if ( ! is_array( $opt ) ) {
				$sanitized[] = array(
					'label' => sanitize_text_field( (string) $opt ),
					'value' => sanitize_text_field( (string) $opt ),
				);
				continue;
			}

			$label = isset( $opt['label'] ) ? sanitize_text_field( $opt['label'] ) : '';
			$clean = array(
				'label' => $label,
				'value' => isset( $opt['value'] ) ? sanitize_text_field( $opt['value'] ) : $label,
			);
			if ( isset( $opt['price'] ) && is_numeric( $opt['price'] ) ) {
				$clean['price'] = (string) floatval( $opt['price'] );
			}
			if ( isset( $opt['icon'] ) ) {
				$clean['icon'] = sanitize_text_field( $opt['icon'] );
			}
			if ( isset( $opt['description'] ) ) {
				$clean['description'] = wp_kses( $opt['description'], $allowed_desc_html );
			}

			$sanitized[] = $clean;
		}

		return $sanitized;
	}
}
