<?php
/**
  * Ahead WebSoft Technologies Pvt Ltd.
  * @copyright  Copyright 2006-2026 Ahead WebSoft Technologies Pvt Ltd.
  * @license    https://www.socialengine.com/policies
*/

include_once APPLICATION_PATH . "/application/libraries/Engine/Service/Authorize/autoload.php";

use net\authorize\api\contract\v1 as AnetAPI;
use net\authorize\api\controller as AnetController;

class Payment_Plugin_Gateway_Verification_Authorize extends Engine_Payment_Plugin_Abstract
{

	protected $_gatewayInfo;
	protected $_gateway;
  
  // General

	/**
	 * Constructor
	 */
	public function __construct(Zend_Db_Table_Row_Abstract $gatewayInfo)
	{
		$this->_gatewayInfo = $gatewayInfo;
	}

	/**
	 * Get the service API
	 *
	 * @return Engine_Service_PayPal
	 */
	public function getService()
	{
		return $this->getGateway()->getService();
	}

	/**
	 * Get the gateway object
	 *
	 * @return Engine_Payment_Gateway
	 */
	public function getGateway()
	{
		// var_dump((array) $this->_gatewayInfo);die;
		if (null === $this->_gateway) {
			$class = 'Engine_Payment_Gateway_Authorizepmnt';
			Engine_Loader::loadClass($class);
			$gateway = new $class(array(
				'config' => (array) $this->_gatewayInfo->config,
				'testMode' => $this->_gatewayInfo->test_mode,
				'currency' => Engine_Api::_()->getApi('settings', 'core')->getSetting('payment.currency', 'USD'),
			));
			if (!($gateway instanceof Engine_Payment_Gateway)) {
				throw new Engine_Exception('Plugin class not instance of Engine_Payment_Gateway');
			}
			$this->_gateway = $gateway;
		}

		return $this->_gateway;
	}

  // Actions
	/**
	 * Create a transaction object from specified parameters
	 *
	 * @return Engine_Payment_Transaction
	 */
	public function createTransaction(array $params)
	{
		$transaction = new Engine_Payment_Transaction($params);
		$transaction->process($this->getGateway());
		return $transaction;
	}

	/**
	 * Create an ipn object from specified parameters
	 *
	 * @return Engine_Payment_Ipn
	 */
	public function createIpn(array $params)
	{
		$ipn = new Engine_Payment_Ipn($params);
		$ipn->process($this->getGateway());
		return $ipn;
	}

  // SEv4 Specific

	/**
	 * Create a transaction for a subscription
	 *
	 * @param User_Model_User $user
	 * @param Zend_Db_Table_Row_Abstract $subscription
	 * @param Zend_Db_Table_Row_Abstract $package
	 * @param array $params
	 * @return Engine_Payment_Gateway_Transaction
	 */
	public function createSubscriptionTransaction(User_Model_User $user, Zend_Db_Table_Row_Abstract $subscription, Payment_Model_Package $package, array $params = array()) {}

	/**
	 * Process return of subscription transaction
	 *
	 * @param Payment_Model_Order $order
	 * @param array $params
	 */
	public function onSubscriptionTransactionReturn(
		Payment_Model_Order $order,
		array $params = array()
	) {}

	/**
	 * Process return of subscription transaction
	 *
	 * @param Payment_Model_Order $order
	 * @param array $params
	 */
	public function onVerificationTransactionReturn(Payment_Model_Order $order, array $params = array())
	{
		// Check that gateways match
		if ($order->gateway_id != $this->_gatewayInfo->gateway_id) {
			throw new Engine_Payment_Plugin_Exception('Gateways do not match');
		}

		// Get related info
		$user = $order->getUser();
		$subscription = Engine_Api::_()->getItem('payment_subscription', $params['subscription_id']);
		$package = $order->getSource();

		$recurrence = $package->recurrence;
		$recurrence_type = $package->recurrence_type;
		$price = $package->price;

		$currencyChangeRate = 1;
		$current_currency = Engine_Api::_()->payment()->getCurrentCurrency();
		$defaultCurrency = Engine_Api::_()->payment()->defaultCurrency();
		if ($current_currency != $defaultCurrency) {
			$currencyData = Engine_Api::_()->getDbTable('currencies', 'payment')->getCurrency($current_currency);
			$currencyChangeRate = $currencyData->change_rate;
		}
		$price = @round(($price * $currencyChangeRate), 2);

		// description
		$desc = $package->getPackageDescription();

		// expiration_date
		$expiration_date = date('Y-m-d H:i:s', $package->getExpirationDate());
		if ($expiration_date == '1970-01-01 00:00:00') {
			$expiration_date = '2099-12-30 00:00:00';
		}

		// Check for cancel state - the user cancelled the transaction
		if ($params['state'] == 'cancel') {
			// Cancel order and subscription?
			$order->onCancel();
			$subscription->onPaymentFailure();
			// Error
			throw new Payment_Model_Exception('Your payment has been cancelled and ' .
				'not been charged. If this is not correct, please try again later.');
		}

		$view = Zend_Registry::isRegistered('Zend_View') ? Zend_Registry::get('Zend_View') : null;

		// validate data
		if (empty($_POST['card_number']) || empty($_POST['card_exp_month']) || empty($_POST['card_exp_year']) || empty($_POST['card_cvc']) || (empty($user->email) && empty($_POST["card_email"]))) {
			echo json_encode(array("status" => 0, "message" => $view->translate("Please provide all field values.")));
			die;
		}

		$itemName = $desc;
		$itemNumber = $_POST["order_id"];
		$itemPrice = $_POST["amount"];
		$currency = Engine_Api::_()->payment()->getCurrentCurrency();

		$name = $user->getTitle();
		$email = $user->email ? $user->email : $_POST["email"];
		$card_number = preg_replace('/\s+/', '', $_POST['card_number']);
		$card_exp_month = $_POST['card_exp_month'];
		$card_exp_year = $_POST['card_exp_year'];
		$card_exp_year_month = $card_exp_year . '-' . $card_exp_month;
		$card_cvc = $_POST['card_cvc'];

		$refID = 'REF' . time();
		$config = (array) $this->_gatewayInfo->config;
		$merchantAuthentication = new AnetAPI\MerchantAuthenticationType();
		$merchantAuthentication->setName($config["login_id"]);
		$merchantAuthentication->setTransactionKey($config["transaction_key"]);


		// Create the payment data for a credit card 
		$creditCard = new AnetAPI\CreditCardType();
		$creditCard->setCardNumber($card_number);
		$creditCard->setExpirationDate($card_exp_year_month);
		$creditCard->setCardCode($card_cvc);

		// Add the payment data to a paymentType object 
		$paymentOne = new AnetAPI\PaymentType();
		$paymentOne->setCreditCard($creditCard);

		// Create order information 
		$orderAuthorize = new AnetAPI\OrderType();
		$orderAuthorize->setInvoiceNumber($order->getIdentity());
		$orderAuthorize->setDescription($itemName);

		// Set the customer's identifying information 
		$customerData = new AnetAPI\CustomerDataType();
		$customerData->setType("individual");
		$customerData->setId($user->getIdentity());
		$customerData->setEmail($email);


		// Create a transaction 
		$transactionRequestType = new AnetAPI\TransactionRequestType();
		$transactionRequestType->setTransactionType("authCaptureTransaction");
		$transactionRequestType->setAmount($itemPrice);
		$transactionRequestType->setOrder($orderAuthorize);
		$transactionRequestType->setPayment($paymentOne);
		$transactionRequestType->setCustomer($customerData);
		$request = new AnetAPI\CreateTransactionRequest();
		$request->setMerchantAuthentication($merchantAuthentication);
		$request->setRefId($refID);
		$request->setTransactionRequest($transactionRequestType);
		$controller = new AnetController\CreateTransactionController($request);
		if ($this->_gatewayInfo->test_mode) {
			$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::SANDBOX);
		} else {
			$response = $controller->executeWithApiResponse(\net\authorize\api\constants\ANetEnvironment::PRODUCTION);
		}

		if ($response != null) {
			if ($response->getMessages()->getResultCode() == "Ok") {
				$tresponse = $response->getTransactionResponse();
				if ($tresponse != null && $tresponse->getMessages() != null) {
					$transaction_gateway_id = $tresponse->getTransId();
					if ($tresponse->getAuthCode() == "000000") {
						$transaction_gateway_id = $refID;
					}
				}
			}
		}
		if (empty($transaction_gateway_id)) {
			if (!empty($tresponse)) {
				$error = "Transaction Failed!";
				if ($tresponse->getErrors() != null) {
					$error = $tresponse->getErrors()[0]->getErrorText();
				}
				echo json_encode(array("status" => 0, "message" => $view->translate($error)));
				die;
			} else if (!empty($response)) {
				$tresponse = $response->getTransactionResponse();
				if ($tresponse != null && $tresponse->getErrors() != null) {
					$error = $tresponse->getErrors()[0]->getErrorText();
				} else {
					$error = $response->getMessages()->getMessage()[0]->getText();
				}
				echo json_encode(array("status" => 0, "message" => $view->translate($error)));
				die;
			} else {
				echo json_encode(array("status" => 0, "message" => $view->translate("Transaction Failed! No response returned")));
				die;
			}
		}

		//Check subscription state
		$paymentStatus = 'okay';
		$orderStatus = 'complete';

		$transactionsTable = Engine_Api::_()->getDbtable('transactions', 'payment');

		// One-time
		if (Engine_Api::_()->payment()->isOneTime($recurrence)) {

			// Update order with profile info and complete status?
			$order->state = $orderStatus;
			$order->gateway_transaction_id = $transaction_gateway_id;
			$order->save();

			$params['gateway_transaction_id'] = $transaction_gateway_id;
			$params['state'] = $paymentStatus;
			$params['type'] = "payment verification";
			$params['expiration_date'] = $expiration_date;
			$params['currency'] = Engine_Api::_()->payment()->defaultCurrency(); //this is default currency set by admin
			$params['amount'] = $price; // @todo use this or gross (-fee)?
			$params['change_rate'] = $currencyChangeRate; //currency change rate according to default currency
			$params['current_currency'] = $current_currency; //$rdata['PAYMENTINFO'][0]['CURRENCYCODE']; //currency which is user paid

			// Insert transaction
			$transaction_id = $transactionsTable->createTransaction($order, $subscription, $user, $params);
			$transaction = Engine_Api::_()->getItem('payment_transaction', $transaction_id);

			// Get benefit setting
			$giveBenefit = Engine_Api::_()->getDbtable('transactions', 'payment')
				->getBenefitStatus($user);

			// Check payment status
			if (
				$paymentStatus == 'okay' ||
				($paymentStatus == 'pending' && $giveBenefit)
			) {

				// Payment success
				$package->onPaymentSuccess($transaction_id);

				$transaction->subscription_id = $subscription->getIdentity();
				$transaction->save();

				// Update subscription info
				$subscription->status = 'active';
				$subscription->active = 1;
				$subscription->expiration_date = $expiration_date;
				$subscription->gateway_profile_id = $params['gateway_transaction_id'];
				$subscription->order_id = $order->order_id;
				$subscription->resource_type = $order->source_type;
				$subscription->resource_id = $order->source_id;
				$subscription->save();

				// send notification
				//if( $subscription->didStatusChange() ) {
				Engine_Api::_()->getApi('mail', 'core')->sendSystem($user, 'payment_verification_active', array(
					'subscription_terms' => $desc,
					'object_link' => 'https://' . $_SERVER['HTTP_HOST'] . Zend_Controller_Front::getInstance()->getRouter()->assemble(array("module" => 'payment', 'controller' => "settings", "action" => "verification"), 'default', true),
				));
				//}
				return 'active';
			} else if ($paymentStatus == 'pending') {
				// Payment pending
				$package->onPaymentPending($transaction);

				// send notification
				//if( $subscription->didStatusChange() ) {
				Engine_Api::_()->getApi('mail', 'core')->sendSystem($user, 'payment_verification_pending', array(
					'subscription_terms' => $desc,
					'object_link' => 'https://' . $_SERVER['HTTP_HOST'] . Zend_Controller_Front::getInstance()->getRouter()->assemble(array("module" => 'payment', 'controller' => "settings", "action" => "verification"), 'default', true),
				));
				//}

				return 'pending';
			} else if ($paymentStatus == 'failed') {
				// Cancel order and subscription?
				$order->onFailure();
				$subscription->onPaymentFailure();
				// Payment failed
				throw new Payment_Model_Exception('Your payment could not be ' .
					'completed. Please ensure there are sufficient available funds ' .
					'in your account.');
			} else {
				// This is a sanity error and cannot produce information a user could use
				// to correct the problem.
				throw new Payment_Model_Exception('There was an error processing your ' .
					'transaction. Please try again later.');
			}
		}
	}

	/**
	 * Process ipn of subscription transaction
	 *
	 * @param Payment_Model_Order $order
	 * @param Engine_Payment_Ipn $ipn
	 */
	public function onSubscriptionTransactionIpn(
		Payment_Model_Order $order,
		Engine_Payment_Ipn $ipn
	) {}


	/**
	 * Cancel a subscription (i.e. disable the recurring payment profile)
	 *
	 * @params $transactionId
	 * @return Engine_Payment_Plugin_Abstract
	 */
	public function cancelSubscription($transactionId, $note = null)
	{
		return $this;
	}

	/**
	 * Generate href to a page detailing the order
	 *
	 * @param string $transactionId
	 * @return string
	 */
	public function getOrderDetailLink($orderId)
	{
		return 'https://www.authorizepmnt.net/index.php?cmd=acct_pmt_details&id=' . $orderId;
	}

	/**
	 * Generate href to a page detailing the transaction
	 *
	 * @param string $transactionId
	 * @return string
	 */
	public function getTransactionDetailLink($transactionId)
	{

		return 'https://www.authorizepmnt.net/index.php?cmd=acct_pmt_details&id=' . $transactionId;
	}

	/**
	 * Get raw data about an order or recurring payment profile
	 *
	 * @param string $orderId
	 * @return array
	 */
	public function getOrderDetails($orderId)
	{
		try {
			return $this->getService()->detailRecurringPaymentsProfile($orderId);
		} catch (Exception $e) {
			echo $e;
		}

		try {
			return $this->getTransactionDetails($orderId);
		} catch (Exception $e) {
			echo $e;
		}

		return false;
	}

	/**
	 * Get raw data about a transaction
	 *
	 * @param $transactionId
	 * @return array
	 */
	public function getTransactionDetails($transactionId)
	{
		return $this->getService()->detailTransaction($transactionId);
	}
  
  // Forms

	/**
	 * Get the admin form for editing the gateway info
	 *
	 * @return Engine_Form
	 */
	public function getAdminGatewayForm()
	{
		return new Authorizepmnt_Form_Admin_Gateway_Authorize();
	}

	public function processAdminGatewayForm(array $values)
	{
		return $values;
	}
  
  // IPN
	/**
	 * Process an IPN
	 *
	 * @param Engine_Payment_Ipn $ipn
	 * @return Engine_Payment_Plugin_Abstract
	 */
	public function onIpn(Engine_Payment_Ipn $ipn) {}
  
  
  // IPN
	/**
	 * Process an IPN
	 *
	 * @param Payment_Model_Order $order
	 * @return Engine_Payment_Plugin_Abstract
	 */
	public function onTransactionIpn(Payment_Model_Order $order,  $rawData) {}

	function setConfig($params) {}

	function test() {}
}
