<?php
/**
 * Forminator Square Hosted Checkout integration.
 *
 * @package SHC4WC
 */

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

class SHC4WC_Forminator {

	const FIELD_TYPE = 'shc4wc_square';

	/** @var self|null */
	private static $instance = null;

	/** @var bool */
	private static $injecting_payment = false;

	public static function instance() {
		if ( null === self::$instance ) {
			self::$instance = new self();
		}
		return self::$instance;
	}

	private function __construct() {
		add_filter( 'forminator_fields', array( $this, 'register_field' ) );
		add_filter( 'forminator_handle_specific_field_types', array( $this, 'handle_specific_field_type' ), 10, 3 );
		add_action( 'forminator_custom-forms_before_save_entry', array( $this, 'maybe_intercept_before_save' ), 5 );
		add_action( 'forminator_custom_forms_enqueue_scripts', array( $this, 'enqueue_front_styles' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_success_styles' ), 20 );
		add_filter( 'forminator_custom_form_thankyou_message', array( $this, 'maybe_filter_thankyou_message' ), 5, 2 );
	}

	/**
	 * @param array $fields Field objects.
	 * @return array
	 */
	public function register_field( $fields ) {
		if ( ! SHC4WC_Plugin::is_connected() ) {
			return $fields;
		}

		require_once SHC4WC_PLUGIN_DIR . 'includes/class-shc4wc-forminator-field.php';
		if ( class_exists( 'SHC4WC_Forminator_Field' ) ) {
			$fields[] = new SHC4WC_Forminator_Field();
		}

		return $fields;
	}

	/**
	 * @param array  $field_data      Field data.
	 * @param object $form_field_obj  Field object.
	 * @param array  $field_array     Field settings.
	 * @return array
	 */
	public function handle_specific_field_type( $field_data, $form_field_obj, $field_array ) {
		if ( ! is_object( $form_field_obj ) || self::FIELD_TYPE !== ( $form_field_obj->type ?? '' ) ) {
			return $field_data;
		}

		$element_id = Forminator_Field::get_property( 'element_id', $field_array );
		$txn_id     = '';

		if ( class_exists( 'Forminator_CForm_Front_Action' ) && ! empty( Forminator_CForm_Front_Action::$prepared_data['payment_transaction_id'] ) ) {
			$txn_id = sanitize_text_field( (string) Forminator_CForm_Front_Action::$prepared_data['payment_transaction_id'] );
		}

		if ( '' === $txn_id ) {
			return array(
				'return' => true,
				'name'   => $element_id,
				'value'  => '',
			);
		}

		$entry_data = $form_field_obj->process_to_entry_data( $field_array );
		if ( ! empty( $entry_data['error'] ) ) {
			if ( class_exists( 'Forminator_CForm_Front_Action' ) ) {
				Forminator_CForm_Front_Action::$submit_errors[] = array( $element_id => $entry_data['error'] );
			}
			return array(
				'return' => true,
				'name'   => $element_id,
				'value'  => $entry_data,
			);
		}

		return array(
			'return' => true,
			'name'   => $element_id,
			'value'  => $entry_data,
		);
	}

	/**
	 * @param int $form_id Form id.
	 * @return void
	 */
	public function maybe_intercept_before_save( $form_id ) {
		if ( self::$injecting_payment ) {
			return;
		}

		if ( ! class_exists( 'Forminator_CForm_Front_Action' ) || ! class_exists( 'Forminator_Base_Form_Model' ) ) {
			return;
		}

		if ( ! empty( Forminator_CForm_Front_Action::$is_draft ) || ! empty( Forminator_CForm_Front_Action::$is_abandoned ) ) {
			return;
		}

		$form = Forminator_Base_Form_Model::get_model( (int) $form_id );
		if ( ! $form ) {
			return;
		}

		$square_field = self::get_square_field_from_model( $form );
		if ( ! $square_field ) {
			return;
		}

		require_once SHC4WC_PLUGIN_DIR . 'includes/class-shc4wc-forminator-field.php';
		if ( ! class_exists( 'SHC4WC_Forminator_Field' ) ) {
			return;
		}

		$element_id = Forminator_Field::get_property( 'element_id', $square_field );
		$prepared   = Forminator_CForm_Front_Action::$prepared_data;

		if ( ! empty( $prepared['payment_transaction_id'] ) ) {
			return;
		}

		$field_object = new SHC4WC_Forminator_Field();
		$amount       = $field_object->get_payment_amount( $square_field );
		if ( $amount <= 0 ) {
			wp_send_json_error(
				array(
					'success' => false,
					'message' => esc_html__( 'Enter a valid payment amount.', 'payments-connect-square' ),
					'errors'  => array(),
					'form_id' => (int) $form_id,
				)
			);
		}

		$title = ! empty( $form->name ) ? (string) $form->name : sprintf( __( 'Forminator form %d', 'payments-connect-square' ), (int) $form_id );

		$started = SHC4WC_Hosted_Checkout_Flow::start_one_time_payment(
			array(
				'type'        => 'forminator',
				'amount'      => $amount,
				'currency'    => self::get_property( 'currency', $square_field, SHC4WC_Hosted_Checkout_Flow::default_currency() ),
				'description' => sprintf( __( 'Forminator: %s', 'payments-connect-square' ), $title ),
				'line_name'   => $title,
				'customer'    => self::extract_buyer_from_prepared( $prepared ),
				'payload'     => array(
					'form_id'      => (int) $form_id,
					'post_data'    => self::capture_post_data(),
					'square_field' => $square_field,
					'element_id'   => $element_id,
					'return_url'   => self::resolve_return_url( $form ),
				),
			)
		);

		if ( is_wp_error( $started ) ) {
			wp_send_json_error(
				array(
					'success' => false,
					'message' => $started->get_error_message(),
					'errors'  => array(),
					'form_id' => (int) $form_id,
				)
			);
		}

		wp_send_json_error(
			array(
				'success'         => false,
				'message'         => esc_html__( 'Redirecting to Square…', 'payments-connect-square' ),
				'redirect_to_url' => esc_url_raw( $started['redirect'] ),
				'errors'          => array(),
				'form_id'         => (int) $form_id,
			)
		);
	}

	/**
	 * @param string $ref Reference id.
	 * @param string $key Return key.
	 * @return void
	 */
	public static function handle_return( $ref, $key ) {
		$stored = SHC4WC_Hosted_Checkout_Flow::pull_pending( 'forminator', $ref, $key );
		if ( ! is_array( $stored ) || empty( $stored['post_data'] ) || ! is_array( $stored['post_data'] ) ) {
			wp_safe_redirect( home_url( '/' ) );
			exit;
		}

		$square_payment_id = '';
		if ( class_exists( 'SHC4WC_Plugin' ) && ! empty( $stored['square_order_id'] ) ) {
			$square_payment_id = SHC4WC_Plugin::instance()->retrieve_square_payment_id_for_hosted_checkout(
				(string) $stored['square_order_id'],
				(string) ( $stored['link_id'] ?? '' ),
				'',
				time()
			);
		}

		$element_id = ! empty( $stored['element_id'] ) ? (string) $stored['element_id'] : '';
		$txn_id     = $square_payment_id ? $square_payment_id : (string) $ref;

		$post_data = $stored['post_data'];
		if ( $element_id ) {
			$post_data[ $element_id ]              = $txn_id;
			$post_data['payment_transaction_id']   = $txn_id;
		}

		$_POST    = array_merge( $_POST, $post_data );
		$_REQUEST = array_merge( $_REQUEST, $post_data );

		if ( ! class_exists( 'SHC4WC_Forminator_Submitter' ) ) {
			require_once SHC4WC_PLUGIN_DIR . 'includes/class-shc4wc-forminator-submitter.php';
		}

		self::$injecting_payment = true;
		$submitter               = new SHC4WC_Forminator_Submitter();
		$response                = $submitter->submit_from_request();
		self::$injecting_payment = false;

		$url = ! empty( $stored['return_url'] ) ? (string) $stored['return_url'] : home_url( '/' );

		if ( is_array( $response ) && ! empty( $response['success'] ) ) {
			if ( ! empty( $response['url'] ) ) {
				$url = (string) $response['url'];
			}
			$url = SHC4WC_Hosted_Checkout_Flow::add_paid_query_arg( $url, 'shc4wc_forminator_paid' );
			wp_safe_redirect( $url );
			exit;
		}

		wp_safe_redirect( home_url( '/' ) );
		exit;
	}

	/**
	 * @return void
	 */
	public function enqueue_front_styles() {
		if ( ! SHC4WC_Plugin::is_connected() ) {
			return;
		}
		wp_register_style( 'shc4wc-forminator-payment', false, array(), SHC4WC_VERSION );
		wp_enqueue_style( 'shc4wc-forminator-payment' );
		wp_add_inline_style(
			'shc4wc-forminator-payment',
			'.shc4wc-forminator-payment-note{margin:0 0 1em;padding:.75em 1em;border:1px solid #c3c4c7;background:#f6f7f7;border-radius:4px;}'
		);
	}

	/**
	 * @return void
	 */
	public function maybe_enqueue_success_styles() {
		if ( empty( $_GET['shc4wc_forminator_paid'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return;
		}
		SHC4WC_Hosted_Checkout_Flow::enqueue_success_styles();
	}

	/**
	 * @param string $message     Message.
	 * @param object $custom_form Form model.
	 * @return string
	 */
	public function maybe_filter_thankyou_message( $message, $custom_form ) {
		unset( $custom_form );
		if ( empty( $_GET['shc4wc_forminator_paid'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			return $message;
		}

		$paid = esc_html__( 'Thank you — your Square payment was received and your form was submitted.', 'payments-connect-square' );
		return '' !== $message ? $message . '<br><br>' . $paid : $paid;
	}

	/**
	 * @param object $form Form model.
	 * @return array|null
	 */
	private static function get_square_field_from_model( $form ) {
		if ( ! is_object( $form ) || ! method_exists( $form, 'get_fields' ) ) {
			return null;
		}

		foreach ( $form->get_fields() as $field ) {
			if ( ! is_object( $field ) || ! method_exists( $field, 'to_formatted_array' ) ) {
				continue;
			}
			$field_array = $field->to_formatted_array();
			if ( ! empty( $field_array['type'] ) && self::FIELD_TYPE === $field_array['type'] ) {
				return $field_array;
			}
		}

		return null;
	}

	/**
	 * @param array  $field    Field settings.
	 * @param string $property Property name.
	 * @param mixed  $default  Default value.
	 * @return mixed
	 */
	private static function get_property( $property, $field, $default = '' ) {
		if ( class_exists( 'Forminator_Field' ) ) {
			return Forminator_Field::get_property( $property, $field, $default );
		}
		return isset( $field[ $property ] ) ? $field[ $property ] : $default;
	}

	/**
	 * @return array
	 */
	private static function capture_post_data() {
		$data = array();
		foreach ( $_POST as $key => $value ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
			$data[ sanitize_text_field( (string) $key ) ] = is_array( $value ) ? wp_unslash( $value ) : wp_unslash( (string) $value );
		}
		return $data;
	}

	/**
	 * @param object $form Form model.
	 * @return string
	 */
	private static function resolve_return_url( $form ) {
		if ( is_object( $form ) && ! empty( $form->settings['form-location'] ) && 'custom' === $form->settings['form-location'] && ! empty( $form->settings['custom-form-location'] ) ) {
			return esc_url_raw( (string) $form->settings['custom-form-location'] );
		}

		$referer = wp_get_referer();
		return $referer ? $referer : home_url( '/' );
	}

	/**
	 * @param array $prepared Prepared submission data.
	 * @return array
	 */
	private static function extract_buyer_from_prepared( $prepared ) {
		$customer = array(
			'email'       => '',
			'given_name'  => '',
			'family_name' => '',
			'phone'       => '',
			'wp_user_id'  => get_current_user_id(),
		);

		foreach ( (array) $prepared as $key => $value ) {
			if ( ! is_scalar( $value ) ) {
				continue;
			}
			$key   = (string) $key;
			$value = (string) $value;
			if ( '' === $customer['email'] && false !== stripos( $key, 'email' ) && is_email( $value ) ) {
				$customer['email'] = sanitize_email( $value );
			}
			if ( '' === $customer['phone'] && false !== stripos( $key, 'phone' ) ) {
				$customer['phone'] = sanitize_text_field( $value );
			}
			if ( '' === $customer['given_name'] && false !== stripos( $key, 'name' ) && false === stripos( $key, 'last' ) ) {
				$customer['given_name'] = sanitize_text_field( $value );
			}
			if ( '' === $customer['family_name'] && false !== stripos( $key, 'last' ) ) {
				$customer['family_name'] = sanitize_text_field( $value );
			}
		}

		return $customer;
	}
}
