<?php
/**
 * PeachPay Authorize.net REST client.
 *
 * @package PeachPay
 */

defined( 'PEACHPAY_ABSPATH' ) || exit;

/**
 * Thin REST client for Authorize.net JSON API endpoints used by PeachPay.
 */
final class PeachPay_Authnet_REST_Client {

	/**
	 * Authorize.net JSON API endpoint — test/sandbox.
	 */
	const ENDPOINT_TEST = 'https://apitest.authorize.net/xml/v1/request.api';

	/**
	 * Authorize.net JSON API endpoint — live/production.
	 */
	const ENDPOINT_LIVE = 'https://api.authorize.net/xml/v1/request.api';

	/**
	 * Authorize.net mode.
	 *
	 * @var string
	 */
	private $mode;

	/**
	 * Constructor.
	 *
	 * @param string $mode 'test' or 'live'.
	 */
	public function __construct( $mode ) {
		$this->mode = 'test' === $mode ? 'test' : 'live';
	}

	/**
	 * Issue a JSON request to the selected Authorize.net API endpoint.
	 *
	 * @param array $body Request body.
	 * @return array|WP_Error Decoded response array, or WP_Error on transport/decode failure.
	 */
	public function request( $body ) {
		$response = wp_remote_post(
			$this->endpoint(),
			array(
				'headers' => array( 'Content-Type' => 'application/json; charset=utf-8' ),
				'body'    => wp_json_encode( $body ),
				'timeout' => 30,
			)
		);

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

		$raw = wp_remote_retrieve_body( $response );
		$raw = ltrim( $raw, "\xEF\xBB\xBF" );

		$decoded = json_decode( $raw, true );

		if ( null === $decoded && '' !== $raw ) {
			$status = function_exists( 'wp_remote_retrieve_response_code' ) ? wp_remote_retrieve_response_code( $response ) : 0;

			return new WP_Error(
				'authnet_invalid_json',
				__( 'Authorize.net returned malformed JSON.', 'peachpay-for-woocommerce' ),
				array(
					'status' => intval( $status ),
					'body'   => $raw,
				)
			);
		}

		return is_array( $decoded ) ? $decoded : array();
	}

	/**
	 * Authenticate credentials.
	 *
	 * @param array $merchant_authentication Merchant authentication block.
	 * @return array|WP_Error
	 */
	public function authenticate( $merchant_authentication ) {
		return $this->request(
			array(
				'authenticateTestRequest' => array(
					'merchantAuthentication' => $merchant_authentication,
					'refId'                  => 'validate',
				),
			)
		);
	}

	/**
	 * Get merchant details.
	 *
	 * @param array $merchant_authentication Merchant authentication block.
	 * @return array|WP_Error
	 */
	public function get_merchant_details( $merchant_authentication ) {
		return $this->request(
			array(
				'getMerchantDetailsRequest' => array(
					'merchantAuthentication' => $merchant_authentication,
				),
			)
		);
	}

	/**
	 * Get transaction details.
	 *
	 * @param array  $merchant_authentication Merchant authentication block.
	 * @param string $authnet_transaction_id Authorize.net transaction ID.
	 * @return array|WP_Error
	 */
	public function get_transaction_details( $merchant_authentication, $authnet_transaction_id ) {
		return $this->request(
			array(
				'getTransactionDetailsRequest' => array(
					'merchantAuthentication' => $merchant_authentication,
					'transId'                => $authnet_transaction_id,
				),
			)
		);
	}

	/**
	 * Create an Authorize.net transaction.
	 *
	 * @param array $merchant_authentication Merchant authentication block.
	 * @param array $transaction_request Authorize.net transactionRequest payload.
	 * @return array|WP_Error
	 */
	public function create_transaction( $merchant_authentication, $transaction_request ) {
		return $this->request(
			array(
				'createTransactionRequest' => array(
					'merchantAuthentication' => $merchant_authentication,
					'transactionRequest'     => $transaction_request,
				),
			)
		);
	}

	/**
	 * Create customer profile.
	 *
	 * @param array $merchant_authentication Merchant authentication block.
	 * @param array $profile Profile payload.
	 * @return array|WP_Error
	 */
	public function create_customer_profile( $merchant_authentication, $profile ) {
		return $this->request(
			array(
				'createCustomerProfileRequest' => array(
					'merchantAuthentication' => $merchant_authentication,
					'profile'                => $profile,
				),
			)
		);
	}

	/**
	 * Create customer payment profile.
	 *
	 * @param array  $merchant_authentication Merchant authentication block.
	 * @param string $customer_profile_id Customer profile ID.
	 * @param array  $payment_profile Payment profile payload.
	 * @param string $validation_mode Validation mode.
	 * @return array|WP_Error
	 */
	public function create_customer_payment_profile( $merchant_authentication, $customer_profile_id, $payment_profile, $validation_mode = 'none' ) {
		return $this->request(
			array(
				'createCustomerPaymentProfileRequest' => array(
					'merchantAuthentication' => $merchant_authentication,
					'customerProfileId'      => $customer_profile_id,
					'paymentProfile'         => $payment_profile,
					'validationMode'         => $validation_mode,
				),
			)
		);
	}

	/**
	 * Get customer profile.
	 *
	 * @param array  $merchant_authentication Merchant authentication block.
	 * @param string $customer_profile_id Customer profile ID.
	 * @return array|WP_Error
	 */
	public function get_customer_profile( $merchant_authentication, $customer_profile_id ) {
		return $this->request(
			array(
				'getCustomerProfileRequest' => array(
					'merchantAuthentication' => $merchant_authentication,
					'customerProfileId'      => $customer_profile_id,
					'includeIssuerInfo'      => 'false',
				),
			)
		);
	}

	/**
	 * Selected API endpoint.
	 *
	 * @return string
	 */
	private function endpoint() {
		return 'test' === $this->mode ? self::ENDPOINT_TEST : self::ENDPOINT_LIVE;
	}
}
