<?php

/**
 * Vvveb
 *
 * Copyright (C) 2022  Ziadin Givan
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */

namespace Vvveb\Plugins\Omnipay\Controller;

use Omnipay\Omnipay;
use function Vvveb\__;
use Vvveb\Controller\Base;
use function Vvveb\getSetting;
use Vvveb\System\Cart\Order;
use Vvveb\System\Sites;
use function Vvveb\url;
use function Vvveb\isSecure;

include __DIR__ . '/../../vendor/autoload.php';

class Index extends Base {
	protected $namespace = 'omnipay';

	protected $gateway;

	protected $order;

	protected $orderData;

	protected $settings;

	protected $successUrl;

	protected $cancelUrl;

	protected $notifyUrl;

	private function errorMessage($message) {
		echo $message;
		//$this->response->setType('text');
		//$this->response->output($message);

		die(0);
	}

	public function init(): string {
		$gateway = $this->request->get['gateway'];
		$index   = $this->request->get['index'];
		$userKey = $this->request->get['key'];
		$orderId = $this->request->get['order_id'];
		$key     = \Vvveb\getConfig('app.key');

		if ($userKey != $key) {
			$this->errorMessage(__('Invalid key!'));
		}

		$this->order     = Order::getInstance();
		$this->orderData = $this->order->get($orderId)['order'] ?? [];

		if (! $this->orderData) {
			$this->errorMessage(__('Invalid order!'));
		}

		if (isset($this->orderData['payment_status_id']) && $this->orderData['payment_status_id'] > 1) {
			//$this->errorMessage(__('Order payment status already set!'));
		}

		$this->settings = getSetting($this->namespace, null, []);
		$options        = $this->settings[$index] ?? false;

		if (! $options) {
			$this->errorMessage(__('Invalid gateway settings!'));
		}

		$this->settings = $options;
		$this->gateway  = Omnipay::create($gateway);
		$parameters     = [];

		foreach ($this->gateway->getDefaultParameters() as $param => $value) {
			if (isset($options[$param])) {
				$parameters[$param] = $options[$param];
			}
		}
		
		$this->gateway->setApiKey($parameters['apiKey'] ?? '');
		$this->gateway->initialize($parameters);
		$site = Sites::getSiteData(SITE_ID);

		$scheme     = isSecure() ? 'https' : 'http';
		$urlParams  = ['host' => $site['host'] ?? false, 'gateway' => $gateway, 'index' => $index, 'key' => $key, 'scheme' => $scheme, 'order_id' => $orderId];
		$successUrl = url('plugins/omnipay/index/success', $urlParams);
		$cancelUrl  = url('plugins/omnipay/index/cancel', $urlParams);
		$notifyUrl  = url('plugins/omnipay/index/notify', $urlParams);
//error_log($urlParams);
//error_log($successUrl);
//error_log($cancelUrl);
//error_log($notifyUrl);

		$this->gatewayName  = $gateway;
		$this->successUrl   = $successUrl;
		$this->cancelUrl    = $cancelUrl;
		$this->notifyUrl    = $notifyUrl;
		$this->paymentClass = str_replace('Controller', '', __NAMESPACE__) . 'Payment';
		
		return '';
	}

	public function notify() {
		$notification = $this->gateway->acceptNotification();

		$transactionReference = $notification->getTransactionReference(); // A reference provided by the gateway to represent this transaction
		$transactionStatus    = $notification->getTransactionStatus(); // Current status of the transaction, one of NotificationInterface::STATUS_*
		$message              = $notification->getMessage(); // Additional message, if any, provided by the gateway

		$orderId     = $this->request->get['order_id'] ?? false;
		$order       = Order::getInstance();
		$orderData   = $order->get($orderId)['order'] ?? [];
		$paymentData = json_decode($orderData['payment_data'] ?? '[]', true) ?: [];
		$paymentData += ['gateway' => $this->gatewayName, 'transaction_reference' => $transactionReference, 'transaction_status' => $transactionStatus, 'class' => $this->paymentClass];

		if ($transactionReference) {
			$paymentData['transaction_reference'] = $transactionReference;
		}

		$status = match ($transactionStatus) {
			'completed'                       => $this->settings['success_payment_status_id'] ?? 4,
			'pending'                         => $this->settings['pending_payment_status_id'] ?? 2,
			'failed', 'cancelled', 'expired'  => $this->settings['error_payment_status_id'] ?? 10,
			default                           => false,
		};

		if ($status) {
			$paymentData['notification'] = $transactionStatus;
			$order->edit(['payment_status_id' => $status, 'payment_data' => json_encode($paymentData)], $orderId);
		}

		if ($message) {
			error_log('Omnipay notify: ' . $message);
		}

		//always reply 200 to the gateway so it doesn't retry
		return true;
	}
	
	public function success() {
		$this->init();

		$orderId     = $this->request->get['order_id'];
		$order       = Order::getInstance();
		$orderData   = $order->get($orderId)['order'] ?? [];
		$paymentData = json_decode($orderData['payment_data'] ?? '[]', true);
		$transactionReference = $paymentData['transaction_reference'] ?? $_POST['id'] ?? false; 

		$parameters = [
			'amount'    => round(floatval($this->orderData['total']), 2),
			'currency'  => $this->orderData['currency'],
			'notifyUrl' => $this->notifyUrl,
			'returnUrl' => $this->successUrl,
			'cancelUrl' => $this->cancelUrl,
		];
		
		if ($transactionReference) {
			$parameters['transactionReference'] = $transactionReference;
		}
		
		$response = $this->gateway->completePurchase($parameters)->send();
		$transactionReference = $response->getTransactionReference();
		$transactionId        = $response->getTransactionId();
		
		$paymentData += ['gateway' => $this->gatewayName, 'transaction_staus' => 'pending', 'class' => $this->paymentClass];
		
			if ($transactionReference) {
				$paymentData['transaction_reference'] = $transactionReference;
			}
			
			if ($transactionId) {
				$paymentData['transaction_id'] = $transactionId;
			}		
//error_log(print_r($response, 1));
		if ($response->isSuccessful()) {
			// Payment successful
			$paymentData['transaction_staus'] = 'completed';
			$order->edit(['payment_status_id' => $this->settings['success_payment_status_id'], 'payment_data' => json_encode($paymentData)], $orderId);
			return $this->redirect('checkout/confirm/index');
		} else {
			// Payment failed
			$paymentData['error'] = $response->getMessage();
			$paymentData['transaction_staus'] = 'failed';
			$order->edit(['payment_status_id' => $this->settings['error_payment_status_id'], 'payment_data' => json_encode($paymentData)], $orderId);
			error_log($paymentData['error']);
			return $this->redirect('checkout/confirm/fail');
		}
	}

	public function cancel()  {
		$this->init();
		$transactionReference = $_POST['id'] ?? false; 

		$orderId = $this->request->get['order_id'];
		$order   = Order::getInstance();
		$order->edit(['payment_status_id' => $this->settings['error_payment_status_id']], $orderId);
	}

	public function index() {
	}
}
