<?php
/**
 * Credit Card Payments with Northmill
 *
 * @package flo-checkout
 *
 * @noinspection PhpUnused Fields are referenced dynamically.
 * @noinspection PhpMissingFieldTypeInspection
 */

namespace Flo_Checkout\Gateways\NMI;

use Exception;
use WP_Error;

/**
 * Class NMI_Hash_Input
 */
class NMI_Hash_Input {
	public const ORDER_TYPE            = 'order_type';
	public const SUCCESS               = 'success';
	public const EKASHU_REFERENCE      = 'ekashu_reference';
	public const EKASHU_TRANSACTION_ID = 'ekashu_transaction_id';

	/**
	 * Validates the hash code.
	 *
	 * @param array  $data     The data to validate.
	 * @param string $endpoint The endpoint to validate against.
	 *
	 * @return true|WP_Error
	 */
	public static function validate_hash( array $data, string $endpoint ): true|WP_Error {
		$post_data = null;

		$required_keys = array(
			'ekashu_hash_code',
			'ekashu_hash_code_format',
			'ekashu_hash_code_result',
			'ekashu_hash_code_result_format',
			'ekashu_hash_code_result_type',
			'ekashu_hash_code_result_version',
			'ekashu_hash_code_type',
			'ekashu_hash_code_version',
		);

		foreach ( $required_keys as $key ) {
			if ( ! isset( $data[ $key ] ) ) {
				return new WP_Error(
					'ekashu_hash_code_error',
					'Hash code error',
					array(
						'response_body' => 'Missing required key: ' . $key,
					)
				);
			}
		}

		foreach ( $data as $name => $value ) {
			if ( 1 === preg_match( '/ekashu_/', $name ) ) {
				// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions
				$post_data .= urlencode( $name ) . '=' . urlencode( $value );
				$post_data .= '&';
			}
		}

		$post_data = substr( $post_data, 0, - 1 );

		$response = wp_remote_post(
			$endpoint . '/validate_hash_code.php',
			array(
				'body' => $post_data,
			)
		);

		if ( is_wp_error( $response ) ) {
			return $response;
		}

		$response_code = wp_remote_retrieve_response_code( $response );

		if ( 200 === $response_code ) {
			return true;
		}

		return new WP_Error(
			'ekashu_hash_code_error',
			'Hash code error',
			array(
				'response_code' => $response_code,
				'response_body' => wp_remote_retrieve_body( $response ),
			)
		);
	}

	/**
	 * Constructor.
	 *
	 * @param array $data The data to use.
	 *
	 * @throws Exception If the data is invalid.
	 */
	public function __construct( array $data = array() ) {
		$required_keys = array(
			'ekashu_amount',
			'ekashu_currency',
			'ekashu_reference',
			'ekashu_seller_id',
			'ekashu_seller_key',
		);
		if ( empty( $data ) || ! $this->array_has_all_keys( $required_keys, $data ) ) {
			throw new Exception( 'Bad Nmi hash generation', 1 );
		}

		foreach ( $data as $key => $value ) {
			$this->{$key} = $value;
		}
	}

	/**
	 * Gets the hash.
	 *
	 * @param string $hash_key The hash key to use.
	 *
	 * @return string
	 */
	public function get_hash( string $hash_key ): string {
		$hash_code_input = (array) $this;
		ksort( $hash_code_input );

		$hash_code = null;
		foreach ( $hash_code_input as $value ) {
			$hash_code .= trim( $value ?? '' );
			$hash_code .= '&';
		}

		$hash_code = substr( $hash_code, 0, - 1 );

		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions -- Allow base64
		return base64_encode( hash_hmac( 'sha256', $hash_code, $hash_key, true ) );
	}

	/**
	 * Gets the form data.
	 *
	 * @return array
	 */
	public function get_form_data(): array {
		$hash_code_input = (array) $this;
		ksort( $hash_code_input );

		return $hash_code_input;
	}

	/**
	 * Checks if an array has all the keys.
	 *
	 * @param array $keys The keys to check for.
	 * @param array $arr  The array to check.
	 *
	 * @return bool
	 */
	private function array_has_all_keys( array $keys, array $arr ): bool {
		if ( empty( $keys ) ) {
			return true;
		}

		foreach ( $keys as $key ) {
			if ( ! isset( $arr[ $key ] ) ) {
				return false;
			}
		}

		return true;
	}

	// phpcs:disable Squiz.Commenting.VariableComment.Missing
	public $ekashu_3d_secure_verify                 = null;
	public $ekashu_amount                           = null;
	public $ekashu_amount_format                    = null;
	public $ekashu_auto_confirm                     = null;
	public $ekashu_callback_failure_url             = null;
	public $ekashu_callback_include_post            = null;
	public $ekashu_callback_success_url             = null;
	public $ekashu_card_address_editable            = null;
	public $ekashu_card_address_required            = null;
	public $ekashu_card_address_verify              = null;
	public $ekashu_card_email_address_mandatory     = null;
	public $ekashu_card_phone_number_mandatory      = null;
	public $ekashu_card_title_mandatory             = null;
	public $ekashu_card_zip_code_verify             = null;
	public $ekashu_currency                         = null;
	public $ekashu_delivery_address_editable        = null;
	public $ekashu_delivery_address_required        = null;
	public $ekashu_delivery_email_address_mandatory = null;
	public $ekashu_delivery_phone_number_mandatory  = null;
	public $ekashu_delivery_title_mandatory         = null;
	public $ekashu_description                      = null;
	public $ekashu_device                           = null;
	public $ekashu_duplicate_check                  = null;
	public $ekashu_duplicate_minutes                = null;
	public $ekashu_failure_return_text              = null;
	public $ekashu_failure_url                      = null;
	public $ekashu_hash_code_format                 = null;
	public $ekashu_hash_code_type                   = 'SHA256HMAC';
	public $ekashu_hash_code_version                = '2.0.0';
	public $ekashu_include_post                     = null;
	public $ekashu_invoice_address_editable         = null;
	public $ekashu_invoice_address_required         = null;
	public $ekashu_invoice_email_address_mandatory  = null;
	public $ekashu_invoice_phone_number_mandatory   = null;
	public $ekashu_invoice_title_mandatory          = null;
	public $ekashu_locale                           = null;
	public $ekashu_payment_methods                  = null;
	public $ekashu_reference                        = null;
	public $ekashu_request_type                     = null;
	public $ekashu_return_text                      = null;
	public $ekashu_seller_address                   = null;
	public $ekashu_seller_email_address             = null;
	public $ekashu_seller_id                        = null;
	public $ekashu_seller_key                       = null;
	public $ekashu_seller_name                      = null;
	public $ekashu_shortcut_icon                    = null;
	public $ekashu_title                            = null;
	public $ekashu_style_sheet                      = null;
	public $ekashu_success_url                      = null;
	public $ekashu_verification_value_mask          = null;
	public $ekashu_verification_value_verify        = null;
	public $ekashu_viewport                         = null;
	// phpcs:enable Squiz.Commenting.VariableComment.Missing
}
