<?php
/**
 * @package    JBusinessDirectory
 *
 * @author     CMSJunkie http://www.cmsjunkie.com
 * @copyright  Copyright (C) 2007 - 2021 CMSJunkie. All rights reserved.
 * @license    https://www.gnu.org/licenses/agpl-3.0.en.html
 */

defined('_JEXEC') or die('Restricted access');

class PayFast extends IPaymentProcessor {
	public $type;
	public $name;

	public $merchant_id;
	public $merchant_key;
	public $mode;
	public $paymentUrlTest = 'https://sandbox.payfast.co.za/eng/process';
	public $paymentUrl = 'https://www.payfast.co.za/eng/process';

	public $passphrase;

	public $notifyUrl;
	public $returnUrl;
	public $cancelUrl;

	public $currencyCode;
	public $amount;
	public $itemNumber;
	public $itemName;


	public function initialize($data) {
		$this->type         = $data->type;
		$this->name         = $data->name;
		$this->mode         = $data->mode;
		if ($this->mode=='test') {
			$this->merchant_id  = $data->test_merchant_id;
			$this->merchant_key = $data->test_merchant_key;
			$this->passphrase   = isset($data->test_passphrase) ? $data->test_passphrase : '';
		} else {
			$this->passphrase   = isset($data->passphrase) ? $data->passphrase : '';
			$this->merchant_id  = $data->merchant_id;
			$this->merchant_key = $data->merchant_key;
		}
	}

	public function getPaymentGatewayUrl() {
		if ($this->mode == "test") {
			return $this->paymentUrlTest;
		} else {
			return $this->paymentUrl;
		}
	}

	public function getPaymentProcessorHtml($data = null) {
		$html = "<ul id=\"payment_form_$this->type\" style=\"display:none\" class=\"form-list\">
		<li>
		" . JText::_('LNG_PROCESSOR_PAYFAST_INFO', true) . "
		</li>
		</ul>";

		return $html;
	}

	public function getHtmlFields() {
		$data = array(
			// Merchant details
			'merchant_id'      => $this->merchant_id,
			'merchant_key'     => $this->merchant_key,
			'return_url'       => $this->returnUrl,
			'cancel_url'       => $this->cancelUrl,
			'notify_url'       => $this->notifyUrl,
			// Buyer details
			'name_first'       => $this->billingDetails->first_name,
			'name_last'        => $this->billingDetails->last_name,
			'email_address'    => $this->billingDetails->email,
			// Transaction details
			'm_payment_id'     => $this->itemNumber, //Unique payment ID to pass through to notify_url
			'amount'           => number_format(sprintf("%.2f", $this->amount), 2, '.', ''), //Amount in ZAR
			'item_name'        => $this->itemName,
			'item_description' => ''
		);

		// Create GET string
		$pfOutput = '';
		foreach ($data as $key => $val) {
			if (!empty($val)) {
				$pfOutput .= $key . '=' . urlencode(trim($val)) . '&';
			}
		}
		// Remove last ampersand
		$getString = substr($pfOutput, 0, -1);
		if (!empty($this->passphrase)) {
			$getString .= '&passphrase=' . urlencode(trim($this->passphrase));
		}
		$data['signature'] = md5($getString);

		$htmlForm = '';
		foreach ($data as $name => $value) {
			$htmlForm .= '<input name="' . $name . '" type="hidden" value="' . $value . '" />';
		}
		return $htmlForm;
	}

	public function processTransaction($data, $controller = "payment") {
		$this->returnUrl = JBusinessUtil::getWebsiteURL().urldecode(JRoute::_("index.php?option=com_jbusinessdirectory&task=$controller.processResponse&processor=payfast&orderId=" . $data->id, false, 0));
		$this->notifyUrl = JBusinessUtil::getWebsiteURL().urldecode(JRoute::_("index.php?option=com_jbusinessdirectory&task=$controller.processAutomaticResponse&processor=payfast", false, 0));
		$this->cancelUrl = JBusinessUtil::getWebsiteURL().urldecode(JRoute::_("index.php?option=com_jbusinessdirectory&task=$controller.processCancelResponse", false, 0));
		$this->amount    = $data->amount;
		$this->itemName  = $data->service . " " . $data->description;
		;
		$this->itemNumber   = $data->id;
		$this->currencyCode = $data->currency;

		if (!isset($data->billingDetails) && isset($data->first_name)) {
			$data->billingDetails             = new stdClass();
			$data->billingDetails->first_name = $data->first_name;
			$data->billingDetails->last_name  = $data->last_name;
			$data->billingDetails->email      = $data->email;
		}

		$this->billingDetails = $data->billingDetails;

		$result                 = new stdClass();
		$result->transaction_id = 0;
		$result->amount         = $data->amount;
		$result->payment_date   = date("Y-m-d");
		$result->response_code  = 0;
		$result->order_id       = $data->id;
		$result->currency       = $data->currency;
		$result->processor_type = $this->type;
		$result->status         = PAYMENT_REDIRECT;
		$result->payment_status = PAYMENT_STATUS_PENDING;

		return $result;
	}

	public function processResponse($data) {
		$result = new stdClass();

		if (isset($data["m_payment_id"])) {
			$result->order_id         = $data["m_payment_id"];
			$result->transaction_id   = $data["pf_payment_id"];
			$result->amount           = $data["amount_gross"];
			$result->transactionTime  = date("Y-m-d", strtotime($data["payment_date"]));
			$result->response_code    = 0;
			$result->response_message = $data['payment_status'];
		} else {
			$result->order_id = $data["orderId"];
		}

		$result->processor_type = $this->type;
		$result->payment_method = "";

		$status = $data['payment_status'];

		if ($this->checkTransactionValidity()) {
			switch ($status) {
				case 'COMPLETE':
					$result->status         = PAYMENT_SUCCESS;
					$result->payment_status = PAYMENT_STATUS_PAID;
					break;
				case 'FAILED':
					$result->status         = PAYMENT_ERROR;
					$result->payment_status = PAYMENT_STATUS_FAILURE;
					break;
				case 'PENDING':
					$result->status         = PAYMENT_WAITING;
					$result->payment_status = PAYMENT_STATUS_PENDING;
					// The transaction is pending, please contact a member of PayFast's support team for further assistance
					break;
				default:
					// If unknown status, do nothing (safest course of action)
					break;
			}
		} else {
			$result->status         = PAYMENT_ERROR;
			$result->payment_status = PAYMENT_STATUS_FAILURE;
		}

		if (!isset($data['m_payment_id'])) {
			$result->status         = PAYMENT_WAITING;
			$result->payment_status = PAYMENT_STATUS_PENDING;
		}

		return $result;
	}

	public function getPaymentDetails($paymentDetails) {
		return JText::_('LNG_PROCESSOR_PAYFAST', true);
	}

	public function checkTransactionValidity() {
		$validHosts = array(
			'www.payfast.co.za',
			'sandbox.payfast.co.za',
			'w1w.payfast.co.za',
			'w2w.payfast.co.za',
		);

		$validIps = array();
		foreach ($validHosts as $pfHostname) {
			$ips = gethostbynamel($pfHostname);

			if ($ips !== false) {
				$validIps = array_merge($validIps, $ips);
			}
		}

		$ipAddress = $_SERVER['REMOTE_ADDR'];
		if (array_key_exists('HTTP_X_FORWARDED_FOR', $_SERVER)) {
			$ipAddress = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
		}

		$validIps = array_unique($validIps);
		if (!in_array($_SERVER['REMOTE_ADDR'], $validIps)) {
			if (!in_array($ipAddress, $validIps)) {
				return false;
			}
		}

		return true;
	}
}
