<?php

if (!defined('IN_SITE')) {
    die('The Request Not Found');
}

class NowPaymentsAPI {
	private $session, $token;

	const API_BASE = 'https://api.nowpayments.io/v1/';

	function __construct(string $token) {
		if(empty($token)) {
			throw new Exception('API key is not specified');
		} else {
			$this->token = $token;
		}

		$ch = curl_init();
		curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
		curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 1);
		curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2);

		$this->session = $ch;
	}
	
	private function getJWToken(){
		$CMSNT = new DB;
		$curl = curl_init();
		curl_setopt_array($curl, array(
		CURLOPT_URL => self::API_BASE.'auth',
		CURLOPT_RETURNTRANSFER => true,
		CURLOPT_ENCODING => '',
		CURLOPT_MAXREDIRS => 10,
		CURLOPT_TIMEOUT => 0,
		CURLOPT_FOLLOWLOCATION => true,
		CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
		CURLOPT_CUSTOMREQUEST => 'POST',
		CURLOPT_POSTFIELDS =>'{
			"email": "'.$CMSNT->site('email_nowpayments').'",
			"password": "'.$CMSNT->site('password_nowpayments').'"
		}',
		CURLOPT_HTTPHEADER => array(
			'Content-Type: application/json'
		  ),
		));
		$response = curl_exec($curl);
		curl_close($curl);
		$response = json_decode($response, true);
		return $response['token'];
	}

	private function Call($method, $endpoint, $data = []) {
		$ch = $this->session;

		switch ($method) {
			case 'GET':
				curl_setopt($ch, CURLOPT_HTTPHEADER, [
					'X-API-KEY: '.$this->token,
					'Authorization: Bearer '.$this->getJWToken()
				]);
				if(!empty($data)) {
					if(is_array($data)) {
						$parameters = http_build_query($data);
						curl_setopt($ch, CURLOPT_URL, self::API_BASE.$endpoint.'?'.$parameters);
					} else {
						if($endpoint == 'payment') curl_setopt($ch, CURLOPT_URL, self::API_BASE.$endpoint.'/'.$data);
					}
				} else {
					curl_setopt($ch, CURLOPT_URL, self::API_BASE.$endpoint);
				}
				break;
			
			case 'POST':
				$data = json_encode($data);
				curl_setopt($ch, CURLOPT_HTTPHEADER, ['X-API-KEY: '.$this->token, 'Content-Type: application/json']);
				curl_setopt($ch, CURLOPT_POST, true);
				curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
				curl_setopt($ch, CURLOPT_URL, self::API_BASE.$endpoint);
				break;

			default:
				break;
		}

		$response = curl_exec($ch);

		return $response;
	}

	public function status() {
		return $this->Call('GET', 'status');
	}

	public function getCurrencies() {
		return $this->Call('GET', 'currencies');
	}

	/**
	* @param array $params Array of options
	*    $params = [
	*      'amount'				=> (int|float) Required.
	*      'currency_from'		=> (string) Required.
	*      'currency_to'		=> (string) Required.
	*    ]
	*/
	public function getEstimatePrice(array $params) {
		return $this->Call('GET', 'estimate', $params);
	}

	/**
	* @param array $params Array of options
	*    $params = [
	*      'price_amount'			=> (int|float) Required. The fiat equivalent of the price to be paid in crypto.
	*      'price_currency'			=> (string) Required. The fiat currency in which the price_amount is specified (usd, eur, etc)
	*      'pay_currency'			=> (string) Required. The crypto currency in which the pay_amount is specified (btc, eth, etc)
	*      'pay_amount'				=> (int|float) Optional. The amount that users have to pay for the order stated in crypto
	*      'ipn_callback_url'		=> (string) Optional. URL to receive callbacks, should contain "http" or "https", eg. "https://nowpayments.io"
	*      'order_id'				=> (string) Optional. Inner store order ID, e.g. "RGDBP-21314"
	*      'order_description'		=> (string) Optional. Inner store order description, e.g. "Apple Macbook Pro 2019 x 1" 
	*      'purchase_id'			=> (string) Optional. ID of purchase for which you want to create aother payment, only used for several payments for one order
	*      'payout_address'			=> (string) Optional. Usually the funds will go to the address you specify in your Personal account
	*      'payout_currency'		=> (string) Optional. Currency of your external payout_address, required when payout_adress is specified
	*      'payout_extra_id'		=> (string) Optional. Extra ID or memo or tag for external payout_address
	*      'fixed_rate'				=> (bool) Optional. Required for fixed-rate exchanges
	*    ]
	*/
	public function createPayment(array $params) {
		return $this->Call('POST', 'payment', $params);
	}

	/**
	* @param int $paymentID Required. ID of created payment
	*/
	public function getPaymentStatus(int $paymentID) {
		return $this->Call('GET', 'payment', $paymentID);
	}

	/**
	* @param array $params Array of options
	*    $params = [
	*      'currency_from'		=> (string) Required.
	*      'currency_to'		=> (string) Required.
	*    ]
	*/
	public function getMinimumPaymentAmount(array $params) {
		return $this->Call('GET', 'min-amount', $params);
	}

	/**
	* @param array $params Array of options, all values are optional
	*    $params = [
	*      'limit'			=> (int|string) number of records in one page. (possible values: from 1 to 500)
	*      'page'			=> (int|string) the page number you want to get (possible values: from 0 to page count - 1)
	*      'sortBy'			=> (string) sort the received list by a paramenter. Set to created_at by default (possible values: payment_id, payment_status, pay_address, price_amount, price_currency, pay_amount, actually_paid, pay_currency, order_id, order_description, purchase_id, outcome_amount, outcome_currency)
	*      'orderBy'		=> (string) display the list in ascending or descending order. Set to asc by default (possible values: asc, desc)
	*      'dateFrom'		=> (string) select the displayed period start date (date format: YYYY-MM-DD or yy-MM-ddTHH:mm:ss.SSSZ)
	*      'dateTo'			=> (string) select the displayed period end date (date format: YYYY-MM-DD or yy-MM-ddTHH:mm:ss.SSSZ)
	*    ]
	*/
	public function getListPayments(array $params = []) {
		return $this->Call('GET', 'payment', $params);
	}

	/**
	* @param array $params Array of options
	*    $params = [
	*      'price_amount'			=> (int|float) Required. The fiat equivalent of the price to be paid in crypto.
	*      'price_currency'			=> (string) Required. The fiat currency in which the price_amount is specified (usd, eur, etc)
	*      'pay_currency'			=> (string) Required. The crypto currency in which the pay_amount is specified (btc, eth, etc)
	*      'ipn_callback_url'		=> (string) Optional. URL to receive callbacks, should contain "http" or "https", eg. "https://nowpayments.io"
	*      'order_id'				=> (string) Optional. Inner store order ID, e.g. "RGDBP-21314"
	*      'order_description'		=> (string) Optional. Inner store order description, e.g. "Apple Macbook Pro 2019 x 1" 
	*      'success_url'			=> (string) Optional. URL where the customer will be redirected after successful payment
	*      'cancel_url'				=> (string) Optional. URL where the customer will be redirected after failed payment
	*    ]
	*/
	public function createInvoice(array $params) {
		return $this->Call('POST', 'invoice', $params);
	}


	public function check_ipn_request_is_valid($ipn_secret){
        $request_data = null;
		if (isset($_SERVER['HTTP_X_NOWPAYMENTS_SIG']) && !empty($_SERVER['HTTP_X_NOWPAYMENTS_SIG'])) {
			$recived_hmac = $_SERVER['HTTP_X_NOWPAYMENTS_SIG'];
			$request_json = file_get_contents('php://input');
			$request_data = json_decode($request_json, true);
			ksort($request_data);
			$sorted_request_json = json_encode($request_data, JSON_UNESCAPED_SLASHES);
			if ($request_json !== false && !empty($request_json)) {
				$hmac = hash_hmac("sha512", $sorted_request_json, trim($ipn_secret));
				if ($hmac == $recived_hmac) {
					return true;
				} else {
					return false;
				}
			} else {
				return false;
			}
		} else {
			return false;
		}
	}

	function __destruct() {
		curl_close($this->session);
	}
	
}

