<?php

namespace Prodigy\Includes\Content;

use Prodigy\admin\Prodigy_Admin_Setup_Wizard;
use Prodigy\Includes\Helpers\Prodigy_Cookies;
use Prodigy\Includes\Helpers\Prodigy_Logger;
use Prodigy\Includes\Helpers\Prodigy_Page;
use Prodigy\Includes\Helpers\Prodigy_Url_Helper;
use Prodigy\includes\models\Prodigy_Order;
use Prodigy\Includes\Prodigy_Cache;
use Prodigy\Includes\Prodigy_User;

defined( 'ABSPATH' ) || exit;

/**
 * Prodigy request maker class
 *
 * @version    3.2.0
 * @package    Prodigy
 * @subpackage Prodigy/includes
 */
class Prodigy_Request_Maker {

	/**
	 * Single object of class
	 *
	 * @var object
	 */
	public static $instance;

	/**
	 * Result of plugin products
	 *
	 * @var array|null
	 */
	private ?array $products_result = array();

	/**
	 * Result of plugin categories
	 *
	 * @var array|null
	 */
	private ?array $categories_result = null;

	/**
	 * @var array|null
	 */
	private ?array $product_result = null;

	/**
	 * @var int|null
	 */
	private ?int $last_product_id = null;

	/**
	 * @var array|null
	 */
	private ?array $related_products = null;

	/**
	 * @var array|null
	 */
	private ?array $catalog_filter_result = array();

	/**
	 * @var array|null
	 */
	private ?array $order_result = null;

	/**
	 * @var array|null
	 */
	private ?array $init_order_result = null;

	/**
	 * @var array|null
	 */
	private ?array $settings_result = array();


	/**
	 * @var array|null
	 */
	private ?array $user_info = array();


	/**
	 * @var array|null
	 */
	private ?array $user_result = null;

	/**
	 * @var array|null
	 */
	private ?array $brands_result = null;


	/**
	 * @var array|null
	 */
	private ?array $brands_list_result = null;

	/**
	 * @var array|null
	 */
	private ?array $redemption_rules_result = null;

	/**
	 * @var array|null
	 */
	private ?array $order_data_result = null;

	/**
	 * @var array|null
	 */
	private ?array $external_checkout_result = null;

	/**
	 * @var array|null
	 */
	private ?array $connection_result = null;

	/**
	 * @var array|null
	 */
	private ?array $disconnection_result = null;


	/**
	 * @var array|null
	 */
	private ?array $check_connection_result = null;


	/**
	 * @var Prodigy_Api_Client
	 */
	public Prodigy_Api_Client $api_client;

	/**
	 * @var object Prodigy_Cache
	 */
	public $cache;

	/** @var string|false|mixed|null  */
	public string $store_key;

	/** @var string|false|mixed|null  */
	public string $access_token;

	/**
	 * Optional callback for sending external cXML payloads.
	 *
	 * @var callable|null
	 */
	public $external_cxml_sender = null;

	/**
	 * Deny allow clone
	 */
	protected function __clone() {}

	/**
	 * @return mixed
	 * @throws \Exception
	 */
	public function __wakeup() {
		throw new \RuntimeException( 'Cannot unserialize a Prodigy_Request_Maker object.' );
	}

	/**
	 * Create single object
	 *
	 * @return self
	 */
	public static function get_instance(): self {
		if ( self::$instance === null ) {
			self::$instance = new self();
		}

		return self::$instance;
	}

	/**
	 * @return void
	 */
	public function __construct() {
		$this->cache        = new Prodigy_Cache();
		$this->api_client   = new Prodigy_Api_Client();
		$this->access_token = Prodigy_Cookies::get_cookie( Prodigy_User::ACCESS_COOKIE_NAME );
		$this->store_key    = get_option( Prodigy_Admin_Setup_Wizard::OPTION_STORE_KEY );
	}

	/**
	 * @param   array|\WP_Error $query_response
	 * @param   string          $query_url
	 *
	 * @return array
	 */
	private function do_process_response( $query_response, string $query_url ) {
		$http_code = wp_remote_retrieve_response_code( $query_response );
		$body      = is_wp_error( $query_response ) ? '' : wp_remote_retrieve_body( $query_response );
		$response  = ( $body === '' ) ? array() : json_decode( $body, true );

		if (
			! is_wp_error( $query_response ) &&
			( ( $http_code === \WP_Http::NO_CONTENT ) || ( $http_code === \WP_Http::OK ) )
		) {
			if ( json_last_error() !== JSON_ERROR_NONE ) {
				if ( PRODIGY_DEBUG_MODE ) {
					Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, json_last_error_msg(), $query_url, '' );
				}
				$response = array();
			}
		} else {
			if ( is_wp_error( $query_response ) ) {
				$error_message = $query_response->get_error_message();
				if ( ! empty( $error_message ) ) {
					$response['error'] = $error_message;
				}
			} elseif ( isset( $response['errors'][0]['detail'] ) ) {
				$response['error'] = $response['errors'][0]['detail'];
			} elseif ( isset( $query_response['response']['message'] ) ) {
				$response['error'] = $query_response['response']['message'];
			} else {
				$response['error'] = 'Unexpected response format.';
			}

			if ( isset( $response['errors'][0]['detail'] ) && PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_ERROR, $response['errors'][0]['detail'], $query_url );
			}
		}

		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'RESPONSE: ', $query_url, $body );
		}

		$response['code'] = $http_code ?: \WP_Http::INTERNAL_SERVER_ERROR;

		return $response;
	}

	/**
	 * @param   int $product_id
	 * @param   int $rating
	 *
	 * @return array
	 */
	public function do_update_product_rating_request( int $product_id, int $rating ): array {
		$rating_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::SEND_RATING_URL;
		$url        = str_replace( ':product_id', $product_id, $rating_url );
		$params     = array( 'rating' => $rating );
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url, wp_json_encode( $params ) );
		}
		$response = $this->api_client->put_remote_content( $url, $params );

		return $this->do_process_response( $response, $url );
	}

	/**
	 * @param string $user_auth_hash
	 *
	 * @return array
	 */
	public function do_user_info_request( string $user_auth_hash ): array {
		if ( ! empty( $this->user_info ) ) {
			return $this->user_info;
		}

		$user_info = $this->cache->get_user_info( $user_auth_hash );
		if ( ! $user_info || empty( $user_info['data'] ) ) {
			$url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_CUSTOMER_MAIN_INFO_URL;
			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url );
			}
			$response  = $this->api_client->get_remote_content( $url );
			$user_info = $this->do_process_response( $response, $url );
			if ( ! empty( $user_info ) ) {
				$this->cache->set_user_info( $user_info, $user_auth_hash );
				$this->user_info = $user_info;
			}
		} else {
			$this->user_info = $user_info;
		}

		return $this->user_info;
	}

	/**
	 * @param  string $refresh_key
	 *
	 * @return array
	 */
	public function do_user_logout( string $refresh_key ): array {
		$url     = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_LOGOUT_URL;
		$headers = array( 'X-Refresh-Token' => $refresh_key );
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url, wp_json_encode( $headers ) );
		}
		$response = $this->api_client->delete_remote_content( $url, $headers );

		return $this->do_process_response( $response, $url );
	}


	/**
	 * @param string $refresh_key
	 * @param int    $impersonation_id
	 *
	 * @return array
	 */
	public function do_delete_impersonation_user( string $refresh_key, int $impersonation_id ): array {
		$request_url = sprintf( '%s%s%s/%d', Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, Prodigy_Api_Client::HS_USER_IMPERSONATION_URL, $impersonation_id );

		$headers = array( 'X-Refresh-Token' => $refresh_key );
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url, wp_json_encode( $headers ) );
		}
		$response = $this->api_client->delete_remote_content( $request_url, $headers );

		return $this->do_process_response( $response, $request_url );
	}

	/**
	 * @param  string $process_url
	 *
	 * @return array
	 */
	public function do_sync_process_request( string $process_url ): array {
		$url    = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $process_url;
		$params = array(
			'with_existed_entities' => true,
		);
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url, wp_json_encode( $params ) );
		}
		$response = $this->api_client->post_remote_content( $url, $params );

		return $this->do_process_response( $response, $url );
	}

	/**
	 * @param  array $params
	 *
	 * @return array
	 */
	public function do_admin_products_properties_request( array $params ): array {
		$api_url     = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::PRODUCTS_PROPERTIES_ADMIN_URL;
		$request_url = add_query_arg( $params, $api_url );
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url );
		}
		$response_attributes = $this->api_client->get_remote_content( $request_url );

		return $this->do_process_response( $response_attributes, $request_url );
	}

	/**
	 * @param string $query
	 *
	 * @return array
	 */
	public function do_catalog_filters_request( string $query = '' ): array {
		$cache_key = md5( $query );

		if ( isset( $this->catalog_filter_result[ $cache_key ] ) ) {
			return $this->catalog_filter_result[ $cache_key ];
		}

		$cached_filters = $this->cache->get_catalog_filters( $query );
		if ( isset( $cached_filters ) && ! empty( $cached_filters['data'] ) ) {
			$this->catalog_filter_result[ $cache_key ] = $cached_filters;
			return $this->catalog_filter_result[ $cache_key ];
		}

		$relations_query = 'categories.children,categories.parent,tags,properties.options';
		$enhanced_query  = '?include=' . $relations_query . '&' . $query;
		$filter_result   = $this->cache->get_catalog_filters( $enhanced_query );

		if ( ! $filter_result ) {
			$catalog_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::CATALOG_URL . $enhanced_query;

			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $catalog_url );
			}
			$response      = $this->api_client->get_remote_content( $catalog_url );
			$filter_result = $this->do_process_response( $response, $catalog_url );

			if ( isset( $filter_result ) && ! empty( $filter_result['data'] ) ) {
				$this->cache->set_catalog_filters( $filter_result, $enhanced_query );
			}
		}

		$this->catalog_filter_result[ $cache_key ] = $filter_result;
		return $this->catalog_filter_result[ $cache_key ];
	}

	/**
	 * @param string $query
	 *
	 * @return array
	 */
	public function do_admin_catalog_filters_request( string $query = '' ): array {
		$catalog_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::CATALOG_ADMIN_URL . '?' . $query;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $catalog_url );
		}
		$response = $this->api_client->get_remote_content( $catalog_url );

		return $this->do_process_response( $response, $catalog_url );
	}

	/**
	 * @param   int|null    $id_remote_product
	 * @param   array       $params
	 * @param   string|null $includes
	 *
	 * @return array
	 */
	public function do_product_request( ?int $id_remote_product = null, array $params = array(), ?string $includes = null ): array {
		if ( $this->product_result !== null && $this->last_product_id === $id_remote_product ) {
			return $this->product_result;
		}

		if ( $id_remote_product === null ) {
			return array();
		}

		$url         = Prodigy_Page::prodigy_is_frontend() ? Prodigy_Api_Client::PRODUCTS_URL : Prodigy_Api_Client::PRODUCTS_ADMIN_URL;
		$product_url = sprintf( '%s%s%s/%d', Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, $url, $id_remote_product );

		$cache_key = $id_remote_product;
		if ( ! empty( $params ) ) {
			$product_url = add_query_arg( $params, $product_url );
			$cache_key   = $id_remote_product . '_' . md5( http_build_query( $params ) );
		}

		$product_result = $this->cache->get_product( $cache_key );
		if ( ! $product_result ) {
			$includes = $includes ?? $this->get_default_product_includes();
			$params   = array( 'include' => $includes );

			if ( ! Prodigy_Page::prodigy_is_frontend() ) {
				$params['admin'] = true;
			}

			$request_url = add_query_arg( $params, $product_url );

			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url );
			}

			$product_obj_response = $this->api_client->get_remote_content( $request_url );

			$http_code = wp_remote_retrieve_response_code( $product_obj_response );

			if ( $http_code === \WP_Http::NOT_FOUND ) {
				Prodigy_Url_Helper::redirect_to_404();
			}

			$product_result = $this->do_process_response( $product_obj_response, $request_url );

			if ( ! empty( $product_result ) ) {
				$this->cache->set_product( $cache_key, $product_result );
			}

			$this->last_product_id = $id_remote_product;
			$this->product_result  = $product_result;
		}

		return $product_result;
	}

	/**
	 * @return string
	 */
	private function get_default_product_includes(): string {
		return implode(
			',',
			array(
				'tags',
				'categories',
				'tax-information',
				'master-variant.dimension',
				'master-variant.inventory',
				'variants.dimension',
				'variants.inventory',
				'cross-sell-products',
				'up-sell-products',
				'descriptive-attributes.options.images',
				'variant-attributes.options.images',
				'images',
				'master-variant.subscription-plan.subscription-conditions',
				'variants.subscription-plan.subscription-conditions',
				'quantity-price-breaks',
				'logos',
				'logo-locations',
				'logo-options',
				'personalization.personalization-fields',
				'multiple-logo-charge-settings',
			)
		);
	}

	/**
	 * @param   string $query
	 * @param   string $includes
	 *
	 * @return array
	 */
	public function do_products_request( string $query, string $includes = '' ): array {
		$hash = md5( $query );
		if ( ! isset( $this->products_result[ $hash ] ) ) {
			$products = $this->cache->get_products_shortcode( $query );
			if ( ! empty( $products ) && ! empty( $products['data'] ) ) {
				$this->products_result[ $hash ] = $products;
			} else {
				$includes    = $this->get_default_product_includes();
				$request_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::PRODUCTS_URL . '?' . $query . '&include=' . $includes;

				if ( PRODIGY_DEBUG_MODE ) {
					Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url );
				}

				$product_response = $this->api_client->get_remote_content( $request_url );
				if ( ! is_wp_error( $product_response ) ) {
					$this->products_result[ $hash ] = $this->do_process_response( $product_response, $request_url );
					if ( isset( $this->products_result[ $hash ]['data'] ) && ! empty( $this->products_result[ $hash ]['data'] ) ) {
						$this->cache->set_products_shortcode( $this->products_result[ $hash ], $query );
					}
				}
			}
		}

		return $this->products_result[ $hash ] ?? array();
	}

	/**
	 * @param   string $query
	 *
	 * @return array
	 */
	public function do_admin_products_request( string $query = '' ): array {
		$includes = $this->get_default_product_includes();
		$api_url  = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::PRODUCTS_ADMIN_URL . '?' . $query . '&include=' . $includes;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url );
		}
		$product_response = $this->api_client->get_remote_content( $api_url );

		return $this->do_process_response( $product_response, $api_url );
	}

	/**
	 * @param string $query
	 * @param string $key
	 *
	 * @return array
	 */
	public function do_related_products_request( string $query, string $key ): array {
		if ( $this->related_products !== null ) {
			return $this->related_products;
		}
		$related_products_result = $this->cache->get_related_product( $key );
		if ( ! $related_products_result ) {
			$url      = Prodigy_Page::prodigy_is_frontend() ? Prodigy_Api_Client::RELATED_PRODUCTS_URL : Prodigy_Api_Client::RELATED_PRODUCTS_ADMIN_URL;
			$includes = $this->get_default_product_includes();
			$api_url  = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $url . '?' . $query . '&include=' . $includes;
			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url );
			}
			$product_obj_remote      = $this->api_client->get_remote_content( $api_url );
			$related_products_result = $this->do_process_response( $product_obj_remote, $api_url );
			if ( ! empty( $related_products_result ) ) {
				$this->cache->set_related_product( $key, $related_products_result );
			}
		}
		$this->related_products = $related_products_result;
		return $this->related_products;
	}

	/**
	 * @param string $order_token
	 *
	 * @return mixed
	 */
	public function do_order_request( string $order_token ): array {
		if ( empty( $order_token ) ) {
			return array();
		}

		$order_url = Prodigy_Page::prodigy_is_frontend() ? Prodigy_Api_Client::ORDER_URL : Prodigy_Api_Client::ORDER_ADMIN_URL;
		$api_url   = sprintf( '%s%s%s/%s', Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, $order_url, $order_token );

		$request_url = add_query_arg(
			array(
				'include' => 'line-items.subscription-condition,cross-sell-products,up-sell-products,line-items.logo-options.logo,line-items.logo-options.logo-location,line-items.personalization-fields',
			),
			$api_url
		);
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url );
		}
		$response = $this->api_client->get_remote_content( $request_url );

		return $this->do_process_response( $response, $request_url );
	}

	/**
	 * @param string $order_token
	 *
	 * @return void
	 */
	public function invalidate_order_cache( string $order_token ): void {
		$this->order_result = null;
		$this->cache->delete_order( $order_token );
	}

	/**
	 * @param  string  $order_token
	 * @param  string  $external_checkout_id
	 *
	 * @return array
	 * @throws \Exception
	 */
	public function do_external_checkout_request( string $order_token, string $external_checkout_id ): ?array {
		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::ORDER_URL . $order_token . '/external_checkouts';
		$params  = array(
			'external_checkout_id' => $external_checkout_id,
		);

		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $params ) );
		}

		$response = $this->api_client->post_remote_content( $api_url, $params );
		if ( is_wp_error( $response ) || $response instanceof \WP_Error ) {
			$this->external_checkout_result = array(
				'code'  => \WP_Http::INTERNAL_SERVER_ERROR,
				'error' => $response->get_error_message(),
			);

			return $this->external_checkout_result;
		}

		$this->external_checkout_result = $this->do_process_response( $response, $api_url );

		$http_code = wp_remote_retrieve_response_code( $response );
		if ( $http_code === \WP_Http::OK ) {
			( new Prodigy_User() )->logout();
		}

		if ( empty( $this->external_checkout_result['error'] ) ) {
			$attributes    = $this->external_checkout_result ?? array();
			$external_cxml = $this->external_checkout_result['cxml'] ?? $attributes['cxml'] ?? $attributes['cXML'] ?? null;
			$external_url  = $this->external_checkout_result['url'] ?? $attributes['url'] ?? null;

			if ( is_string( $external_cxml ) && $external_cxml !== '' && is_string( $external_url ) && $external_url !== '' ) {
				$xml_payload_result = $this->prepare_external_checkout_xml_payload(
					$api_url,
					$order_token,
					$external_checkout_id,
					$external_url,
					$external_cxml
				);

				if ( ! empty( $xml_payload_result['error'] ) ) {
					$this->external_checkout_result['code']  = \WP_Http::INTERNAL_SERVER_ERROR;
					$this->external_checkout_result['error'] = $xml_payload_result['error'];
					return $this->external_checkout_result;
				}

				$this->external_checkout_result['checkout_url'] = $xml_payload_result['checkout_url'];
			} elseif ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record(
					Prodigy_Logger::TYPE_ERROR,
					'External checkout response missing cXML or BrowserFormPost URL',
					$api_url,
					wp_json_encode(
						array(
							'external_checkout_id' => $external_checkout_id,
							'order_token'          => $order_token,
							'attributes_keys'      => is_array( $attributes ) ? array_keys( $attributes ) : array(),
						)
					)
				);
			}
		}

		return $this->external_checkout_result;
	}

	/**
	 * Prepare and store XML payload for external checkout return.
	 *
	 * @param string $api_url
	 * @param string $order_token
	 * @param string $external_checkout_id
	 * @param string $external_url
	 * @param string $external_cxml
	 *
	 * @return array
	 */
	private function prepare_external_checkout_xml_payload(
		string $api_url,
		string $order_token,
		string $external_checkout_id,
		string $external_url,
		string $external_cxml
	): array {
		$return_key = md5( $order_token . '|' . $external_checkout_id . '|' . $external_url . '|' . $external_cxml );

		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record(
				Prodigy_Logger::TYPE_INFO,
				'External checkout payload prepared',
				$api_url,
				wp_json_encode(
					array(
						'external_checkout_id' => $external_checkout_id,
						'order_token'          => $order_token,
						'browser_form_post'    => $external_url,
						'payload_type'         => 'cxml-base64',
						'return_key'           => $return_key,
					)
				)
			);
		}

		$cxml_encoded   = base64_encode( $external_cxml );
		$field_name     = 'cxml-base64';
		$transient_name = 'prodigy_punchout_return_' . $return_key;

		$ttl_seconds = 5 * 60;
		$stored      = set_transient(
			$transient_name,
			array(
				'browser_form_post_url' => $external_url,
				'field_name'            => $field_name,
				'payload'               => $cxml_encoded,
			),
			$ttl_seconds
		);

		if ( $stored === false ) {
			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record(
					Prodigy_Logger::TYPE_ERROR,
					'External checkout transient save failed',
					$api_url,
					wp_json_encode(
						array(
							'transient_name'       => $transient_name,
							'external_checkout_id' => $external_checkout_id,
							'order_token'          => $order_token,
						)
					)
				);
			}

			return array( 'error' => 'Unable to prepare PunchOut return payload.' );
		}

		$nonce        = wp_create_nonce( 'prodigy-punchout-return' );
		$checkout_url = home_url(
			'/punchout-return/?return_key=' . rawurlencode( $return_key ) . '&_wpnonce=' . rawurlencode( (string) $nonce )
		);

		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record(
				Prodigy_Logger::TYPE_INFO,
				'External checkout return URL generated',
				$api_url,
				wp_json_encode(
					array(
						'checkout_url'         => $checkout_url,
						'external_checkout_id' => $external_checkout_id,
						'order_token'          => $order_token,
					)
				)
			);
		}

		return array( 'checkout_url' => $checkout_url );
	}

	/**
	 * @param array $request
	 * @param bool  $is_retry_after_external_checkout_clear Internal: avoid infinite retry.
	 *
	 * @return array
	 */
	public function do_init_order_request( array $request, bool $is_retry_after_external_checkout_clear = false ): array {
		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::CART_URL;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $request ) );
		}
		$init_order_result = $this->api_client->patch_remote_content( $api_url, $request );

		return $this->do_process_response( $init_order_result, $api_url );
	}

	/**
	 * @param string $content_url
	 * @param string $query
	 *
	 * @return array
	 */
	public function do_get_sync_type_content_request( string $content_url, string $query = '' ): array {
		$url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $content_url . $query;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url );
		}
		$response = $this->api_client->get_remote_content( $url );
		return $this->do_process_response( $response, $url );
	}

	/**
	 * @param  string|null $includes
	 *
	 * @return array
	 */
	public function do_settings_request( ?string $includes = null ): array {
		if ( ! empty( $this->settings_result ) ) {
			return $this->settings_result;
		}

		$settings_result = $this->cache->get_settings();
		if ( ! $settings_result || empty( $settings_result['data'] ) ) {
			$request_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_SETTINGS_URL;

			if ( $includes ) {
				$request_url = add_query_arg( array( 'include' => $includes ), $request_url );
			}

			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url );
			}

			$response        = $this->api_client->get_remote_content( $request_url );
			$settings_result = $this->do_process_response( $response, $request_url );

			if ( ! empty( $settings_result ) ) {
				$this->cache->set_settings( $settings_result );
				$this->settings_result = $settings_result;
			}
		} else {
			$this->settings_result = $settings_result;
		}

		return $this->settings_result;
	}

	/**
	 * @param   array $query
	 *
	 * @return array
	 */
	public function do_categories_request( array $query = array() ): array {
		$hash = md5( wp_json_encode( $query ) );
		if ( ! isset( $this->categories_result[ $hash ] ) ) {
			$this->categories_result[ $hash ] = $this->cache->get_categories_shortcode( $hash );
			if ( ! $this->categories_result[ $hash ] ) {
				$api_url      = Prodigy_Page::prodigy_is_frontend() ? Prodigy_Api_Client::CATEGORY_URL : Prodigy_Api_Client::CATEGORY_ADMIN_URL;
				$query_string = http_build_query( $query );
				$query        = urldecode( preg_replace( '/%5B(?:[0-9]|[1-9][0-9]+)%5D/', '[]', $query_string ) );
				$request_url  = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . $api_url . '?' . $query . '&include=parent,children';
				if ( PRODIGY_DEBUG_MODE ) {
					Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url );
				}
				$category_response                = $this->api_client->get_remote_content( $request_url );
				$this->categories_result[ $hash ] = $this->do_process_response( $category_response, $api_url );
				if ( ! empty( $this->categories_result[ $hash ] ) ) {
					$this->cache->set_categories_shortcode( $this->categories_result[ $hash ], $hash );
				}
			}
		}

		return $this->categories_result[ $hash ];
	}

	/**
	 * @return array
	 */
	public function do_get_platform_info(): array {
		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url );
		}
		$response = $this->api_client->get_remote_content( $api_url );

		return $this->do_process_response( $response, $api_url );
	}

	/**
	 * @param   array $params
	 *
	 * @return array
	 */
	public function do_update_plugin_info( array $params ): array {
		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $params ) );
		}
		$response = $this->api_client->put_remote_content( $api_url, $params );

		return $this->do_process_response( $response, $api_url );
	}

	/**
	 * @param   array $params
	 *
	 * @return array
	 */
	public function do_connect_request( array $params ) {

		if ( $this->connection_result !== null ) {
			return $this->connection_result;
		}

		$connection_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $connection_url, wp_json_encode( $params ) );
		}
		$response_connection     = $this->api_client->post_remote_content( $connection_url, $params );
		$this->connection_result = $this->do_process_response( $response_connection, $connection_url );

		return $this->connection_result;
	}

	/**
	 * @return array
	 */
	public function do_disconnect_store_request(): array {

		if ( $this->disconnection_result !== null ) {
			return $this->disconnection_result;
		}

		$connection_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::API_CONNECTION_URL;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $connection_url );
		}
		$request_disconnection      = $this->api_client->delete_remote_content( $connection_url );
		$this->disconnection_result = $this->do_process_response( $request_disconnection, $connection_url );

		return $this->disconnection_result;
	}

	/**
	 * @param string $paired_token
	 *
	 * @return array
	 */
	public function do_user_request( string $paired_token = '' ): array {
		if ( $this->user_result !== null ) {
			return $this->user_result;
		}

		$url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::USER_SESSION_TOKEN_URL . '/' . $paired_token;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $url );
		}
		$response = $this->api_client->get_remote_content( $url );

		$this->user_result = $this->do_process_response( $response, $url );

		return $this->user_result;
	}

	/**
	 *
	 * @param string $includes
	 *
	 * @return array
	 */
	public function do_brands_request( string $includes ): array {

		if ( $this->brands_result !== null ) {
			return $this->brands_result;
		}

		$brands_results = $this->cache->get_brands_shortcode();
		if ( ! $brands_results ) {
			$url         = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_BRANDS_URL;
			$params      = array( 'include' => $includes );
			$request_url = add_query_arg( $params, $url );
			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $request_url );
			}
			$response = $this->api_client->get_remote_content( $request_url );

			$brands_results = $this->do_process_response( $response, $request_url );
			if ( ! empty( $brands_results ) ) {
				$this->cache->set_brands_shortcode( $brands_results );
			}
			$this->brands_result = $brands_results;
		}

		return $brands_results;
	}

	/**
	 * @param string $id_remote_product
	 *
	 * @return array
	 */
	public function do_brands_list_request( string $id_remote_product ): array {

		if ( $this->brands_list_result !== null ) {
			return $this->brands_list_result;
		}

		$brands_results = $this->cache->get_brands_list( (int) $id_remote_product );
		if ( ! $brands_results ) {
			$url         = Prodigy_Page::prodigy_is_frontend() ? Prodigy_Api_Client::PRODUCTS_URL : Prodigy_Api_Client::PRODUCTS_ADMIN_URL;
			$product_url = sprintf( Prodigy_Api_Client::PRODUCT_BRANDS_PREFIX, Prodigy_Api_Client::API_PROTOCOL, PRODIGY_API_DOMAIN, $url, $id_remote_product );

			if ( PRODIGY_DEBUG_MODE ) {
				Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $product_url );
			}
			$response = $this->api_client->get_remote_content( $product_url );

			$brands_results = $this->do_process_response( $response, $product_url );
			if ( ! empty( $brands_results ) ) {
				$this->cache->set_brands_list( $brands_results, (int) $id_remote_product );
			}
			$this->brands_list_result = $brands_results;
		}

		return $brands_results;
	}

	/**
	 * @param  string $order_token
	 *
	 * @return array
	 */
	public function do_order_data_request( string $order_token ): array {

		if ( $this->order_data_result !== null ) {
			return $this->order_data_result;
		}

		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::ORDER_URL . $order_token . '?include=line-items';
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url );
		}
		$order_response = $this->api_client->get_remote_content( $api_url );

		$this->order_data_result = $this->do_process_response( $order_response, $api_url );

		return $this->order_data_result;
	}

	/**
	 * @param   int   $line_item_id
	 * @param   array $line_item_request
	 *
	 * @return array
	 */
	public function do_update_line_items_request( int $line_item_id, array $line_item_request ): array {
		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::LINE_ITEM_URL . $line_item_id;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url, wp_json_encode( $line_item_request ) );
		}
		$line_item_response = $this->api_client->patch_remote_content(
			$api_url,
			$line_item_request
		);

		return $this->do_process_response( $line_item_response, $api_url );
	}

	/**
	 * @param int    $line_item_id
	 * @param string $order_token
	 *
	 * @return array
	 */
	public function do_delete_line_item_request( int $line_item_id, string $order_token ): array {
		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::LINE_ITEM_URL . $line_item_id . '?order_token=' . $order_token;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url );
		}
		$result = $this->api_client->delete_remote_content( $api_url );

		$this->invalidate_order_cache( $order_token );

		return $result;
	}

	/**
	 * @param string $order_token
	 *
	 * @return array
	 */
	public function do_delete_order_request( string $order_token ): array {
		$api_url = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::ORDER_URL . $order_token;
		if ( PRODIGY_DEBUG_MODE ) {
			Prodigy_Logger::add_record( Prodigy_Logger::TYPE_INFO, 'REQUEST: ', $api_url );
		}
		$response = $this->api_client->delete_remote_content( $api_url );

		return $this->do_process_response( $response, $api_url );
	}

	/**
	 * @param int|null $order_id
	 *
	 * @return array
	 */
	public function do_redemption_rules_request( ?int $order_id = null ): array {
		if ( ! Prodigy_Cookies::has_cookie( Prodigy_User::USER_ID_COOKIE_NAME ) ) {
			return array();
		}

		if ( $order_id === null ) {
			$user_session = Prodigy_Cookies::get_user_cart_cookie();
			$order        = ! empty( $user_session )
				? Prodigy_Order::get_last_guest_active_order_data( $user_session )
				: null;

			if ( empty( $order ) && Prodigy_User::is_logged_in() ) {
				$user_id = Prodigy_User::get_user_session();
				if ( $user_id !== null ) {
					$order = Prodigy_Order::get_last_user_active_order_data( $user_id );
				}
			}

			if ( ! empty( $order['order_number'] ) ) {
				$order_id = (int) $order['order_number'];
			}
		}

		$cache_key = $order_id ?? 0;
		if ( isset( $this->redemption_rules_result[ $cache_key ] ) ) {
			return $this->redemption_rules_result[ $cache_key ];
		}

		$url    = Prodigy_Api_Client::API_PROTOCOL . PRODIGY_API_DOMAIN . Prodigy_Api_Client::HS_REDEMPTION_RULES_URL;
		$params = array( 'include' => 'redemption-code-categories.categories.ancestors' );
		if ( $order_id !== null ) {
			$params['order_id'] = $order_id;
		}
		$url = add_query_arg( $params, $url );

		$response = $this->api_client->get_remote_content( $url );
		$this->redemption_rules_result[ $cache_key ] = $this->do_process_response( $response, $url );

		return $this->redemption_rules_result[ $cache_key ];
	}

	/**
	 * Extracts and returns a list of error details from a remote response.
	 *
	 * @param mixed $response_remote
	 */
	public function get_list_errors( $response_remote ): array {
		$message_error = json_decode( wp_remote_retrieve_body( $response_remote ), false );

		if ( isset( $message_error->errors ) && is_array( $message_error->errors ) ) {
			return array_column( $message_error->errors, 'detail' );
		}

		return array();
	}
}
