<?php
/**
 * @package     CMGiftCard
 * @subpackage  plg_cmgiftcard_eway
 * @copyright   Copyright (C) 2016-2024 CMExension
 * @license     GNU General Public License version 2 or later
 */

defined('_JEXEC') or die;

require_once JPATH_ROOT . '/administrator/components/com_cmgiftcard/helpers/plugin/cmgiftcard.php';

use Joomla\CMS\Factory;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\MVC\Model\BaseDatabaseModel;

/**
 * Eway payment method for CMGiftCard.
 *
 * @package     CMGiftCard
 * @subpackage  plg_cmgiftcard_eway
 * @since       1.2.0
 */
class PlgCMGiftCardEway extends CMGiftCardPlugin
{
	/**
	 * Constructor
	 *
	 * @param   object  &$subject  The object to observe
	 * @param   array   $config    An optional associative array of configuration settings.
	 *                             Recognized key values include 'name', 'group', 'params', 'language'
	 *                             (this list is not meant to be comprehensive).
	 *
	 * @since   1.2.0
	 */
	public function __construct(&$subject, $config = array())
	{
		$this->gatewayId = 'eway';
		$this->gatewayName = 'PLG_CMGIFTCARD_EWAY_NAME';

		parent::__construct($subject, $config);
	}

	/**
	 * Method to get payment form.
	 *
	 * @param   array  $data  Billing data.
	 *
	 * @return  array
	 *
	 * @since   1.2.0
	 */
	public function onCMGCGetPaymentForm($data)
	{
		require_once dirname(__FILE__) . '/eway/include_eway.php';

		$gatewayId = isset($data['billing']['payment_method']) ? $data['billing']['payment_method'] : '';

		if ($gatewayId != $this->gatewayId)
			return false;

		$gatewayName = $this->params->get('name', Text::_($this->gatewayName));
		$apiKey = $this->params->get('api_key');
		$apiPassword = $this->params->get('api_password');
		$currencyCode = $this->params->get('currency_code', 'USD');
		$environment = $this->params->get('environment', 'production');
		$secondsToWait = (int) $this->params->get('seconds_to_wait', 5);

		$clickHereLink = '<a href="#" onClick="document.checkOutForm.submit(); return false;">' . Text::_('COM_CMGIFTCARD_CLICK_HERE') . '</a>';
		$checkoutMessage = Text::sprintf('COM_CMGIFTCARD_CHECKOUT_MESSAGE', $gatewayName, $secondsToWait, $clickHereLink);

		if ($environment == 'production')
		{
			$apiEndpoint = \Eway\Rapid\Client::MODE_PRODUCTION;
		}
		else
		{
			$apiEndpoint = \Eway\Rapid\Client::MODE_SANDBOX;
		}

		//$returnUrl = Uri::root() . 'index.php?option=com_cmgiftcard&view=checkout&layout=success';
		$cancelUrl = str_replace(Uri::root(true), '', substr(Uri::root(), 0, -1)) . CMGiftCardHelper::prepareRoute('index.php?option=com_cmgiftcard&view=checkout') . '?layout=cancel';
		$returnUrl = Uri::root() . 'index.php?option=com_cmgiftcard&task=callback&gateway=' . $this->gatewayId;

		$client = \Eway\Rapid::createClient($apiKey, $apiPassword, $apiEndpoint);

		$firstName = $data['billing']['first_name'];
		$lastName = $data['billing']['last_name'];
		$street1 = isset($data['billing']['address_1']) ? $data['billing']['address_1'] : '';
		$street2 = isset($data['billing']['address_2']) ? $data['billing']['address_2'] : '';
		$city = isset($data['billing']['city']) ? $data['billing']['city'] : '';
		$state = isset($data['billing']['state']) ? $data['billing']['state'] : '';
		$postalCode = isset($data['billing']['postal_code']) ? $data['billing']['postal_code'] : '';
		$country = isset($data['billing']['country']) ? $data['billing']['country'] : '';
		$email = $data['billing']['email'];
		$totalAmount = $data['total'] * 100;
		$invoiceReference = $data['billing']['order_number'];

		$country = $this->convertCountryCode($country);

		$transaction = [
			'Customer' => [
				'FirstName' => $firstName,
				'LastName' => $lastName,
				'Street1' => $street1,
				'Street2' => $street2,
				'City' => $city,
				'State' => $state,
				'PostalCode' => $postalCode,
				'Country' => $country,
				'Email' => $email,
			],
			'Payment' => [
				'TotalAmount' => $totalAmount,
				'CurrencyCode' => $currencyCode,
				'InvoiceReference' => $invoiceReference,
			],
			'CustomerReadOnly' => true,
			'RedirectUrl' => $returnUrl,
			'CancelUrl' => $cancelUrl,
			'TransactionType' => \Eway\Rapid\Enum\TransactionType::PURCHASE,
			'Capture' => true,
			'Items' => [],
		];

		foreach ($data['items'] as $n => $item)
		{
			$transaction['Items'][] = [
				'Description' => $item['design_title'],
				'Quantity' => 1,
				'UnitCost' => $item['amount'] * 100,
			];
		}

		$response = $client->createTransaction(\Eway\Rapid\Enum\ApiMethod::RESPONSIVE_SHARED, $transaction);

		if (!$response->getErrors())
		{
			$sharedPaymentUrl = $response->SharedPaymentUrl;
		}
		else
		{
			$app = Factory::getApplication();

			foreach ($response->getErrors() as $error)
			{
				$app->enqueueMessage(\Eway\Rapid::getMessage($error), 'error');
			}

			$app->redirect(CMGiftCardHelper::prepareRoute('index.php?option=com_cmgiftcard&view=cart'));
		}

		@ob_start();
		include dirname(__FILE__) . '/form.php';
		$html = @ob_get_clean();

		return $html;
	}

	/**
	 * Method to get validate Eway callback.
	 *
	 * @return  boolean
	 *
	 * @since   1.2.0
	 */
	public function onCMGCValidateCallback()
	{
		require_once dirname(__FILE__) . '/eway/include_eway.php';
		require_once JPATH_ROOT . '/components/com_cmgiftcard/models/order.php';

		$app = Factory::getApplication();
		$jinput = $app->input;
		$gatewayId = $jinput->get('gateway', '');
		$data = $jinput->get->getArray();

		if ($gatewayId != $this->gatewayId || empty($data))
		{
			$app->redirect('index.php');
		}

		if (!isset($data['AccessCode']))
		{
			$data['failure_reason'] = "AccessCode not available";
			$this->logNotification($data, false);

			$app->redirect('index.php');
		}

		$apiKey = $this->params->get('api_key');
		$apiPassword = $this->params->get('api_password');
		$currencyCode = $this->params->get('currency_code', 'USD');
		$environment = $this->params->get('environment', 'production');

		if ($environment == 'production')
		{
			$apiEndpoint = \Eway\Rapid\Client::MODE_PRODUCTION;
		}
		else
		{
			$apiEndpoint = \Eway\Rapid\Client::MODE_SANDBOX;
		}

		$client = \Eway\Rapid::createClient($apiKey, $apiPassword, $apiEndpoint);

		$response = $client->queryTransaction($data['AccessCode']);
		$transactionResponse = $response->Transactions[0];

		if ($transactionResponse->TransactionStatus)
		{
			$orderId = (int) $transactionResponse->InvoiceReference;

			$db = Factory::getDbo();
			$query = $db->getQuery(true)
				->select('*')
				->from($db->qn('#__cmgiftcard_orders'))
				->where($db->qn('order_number') . ' = ' . $db->q($orderId));
			$db->setQuery($query);
			$order = $db->loadObject();

			if (!isset($order->id))
			{
				$data['failure_reason'] = "Order number $orderId didn't exist";
				$this->logNotification($data, false);

				$app->enqueueMessage(Text::_('PLG_CMGIFTCARD_EWAY_ORDER_NOT_FOUND'), 'error');
				$app->redirect('index.php');
			}
		}
		else
		{
			$errors = split(',', $transactionResponse->ResponseMessage);
			$reasons = [];

			foreach ($errors as $error)
			{
				$e = \Eway\Rapid::getMessage(trim($error));
				$reasons[] = $e;
				$app->enqueueMessage($e, 'error');
			}

			$data['failure_reason'] = implode(' / ', $reasons);
			$this->logNotification($data, false);


			$app->redirect('index.php');
		}

		if (isset($order->order_status) && $order->order_status == 'paid')
		{
			$data['failure_reason'] = "Order number $orderId was already paid.";
			$this->logNotification($data, false);
			$app->enqueueMessage(Text::_('PLG_CMGIFTCARD_EWAY_ORDER_PAID'), 'error');

			$app->redirect('index.php');
		}

		if (isset($order->order_status) && $order->order_status == 'refunded')
		{
			$data['failure_reason'] = "Order number $orderId was already refunded.";
			$this->logNotification($data, false);
			$app->enqueueMessage(Text::_('PLG_CMGIFTCARD_EWAY_ORDER_REFUNDED'), 'error');

			$app->redirect('index.php');
		}

		$query->clear()
			->select('*')
			->from($db->qn('#__cmgiftcard_cards'))
			->where($db->qn('order_id') . ' = ' . $db->quote($order->id));
		$db->setQuery($query);
		$cards = $db->loadObjectList();

		if (count($cards))
		{
			$amount = 0;

			foreach ($cards as $card)
			{
				$amount += $card->amount;
			}

			$amount = $amount * 100;
			$totalAmount = $transactionResponse->TotalAmount;
			$isValid = ($totalAmount == $amount);

			if (!$isValid)
			{
				$data['failure_reason'] = "Invalid paid amount, expected $amount, got $totalAmount";
				$this->logNotification($data, false);
				$app->enqueueMessage(Text::_('PLG_CMGIFTCARD_EWAY_ORDER_INVALID'), 'error');

				$app->redirect('index.php');
			}
		}
		else
		{
			$data['failure_reason'] = "No gift cards found";
			$this->logNotification($data, false);
			$app->enqueueMessage(Text::_('PLG_CMGIFTCARD_EWAY_ORDER_INVALID'), 'error');

			$app->redirect('index.php');
		}

		$orderModel = BaseDatabaseModel::getInstance('Order', 'CMGiftCardModel');
		$result = $orderModel->updatePaidOrder($order->id, $transactionResponse->TransactionID);

		$this->logNotification($data, true);

		if ($result)
		{
			CMGiftCardHelper::sendOrderEmail($order->id);
			CMGiftCardHelper::sendElectronicCardEmail($order->id);
			CMGiftCardHelper::sendPhysicalCardEmail($order->id);

			$app->redirect(CMGiftCardHelper::prepareRoute('index.php?option=com_cmgiftcard&view=checkout') . '?layout=success');
		}
		else
		{
			$app->enqueueMessage(Text::_('PLG_CMGIFTCARD_EWAY_INTERNAL_ERROR'), 'error');

			$app->redirect('index.php');
		}

		return [];
	}

	private function convertCountryCode($countryCode)
	{
		$countryCodes = array(
			"" => Text::_('COM_CMGIFTCARD_OPTION_SELECT_COUNTRY'),
			"united_states" => "US",
			"afghanistan" => "AF",
			"aland_islands" => "AX",
			"albania" => "AL",
			"algeria" => "DZ",
			"american_samoa" => "AS",
			"andorra" => "AD",
			"angola" => "AO",
			"anguilla" => "AI",
			"antigua_and_barbuda" => "AG",
			"argentina" => "AR",
			"armenia" => "AM",
			"aruba" => "AW",
			"australia" => "AU",
			"austria" => "AT",
			"azerbaijan" => "AZ",
			"bahamas" => "BS",
			"bahrain" => "BH",
			"bangladesh" => "BD",
			"barbados" => "BB",
			"belarus" => "BY",
			"belgium" => "BE",
			"belize" => "BZ",
			"benin" => "BJ",
			"bermuda" => "BM",
			"bhutan" => "BT",
			"bolivia" => "BO",
			"bosnia_and_herzegowina" => "BA",
			"botswana" => "BW",
			"bouvet_island" => "BV",
			"brazil" => "BR",
			"british_antarctic_territory" => "BQ",
			"british_indian_ocean_territory" => "IO",
			"brunei_darussalam" => "BN",
			"bulgaria" => "BG",
			"burkina_faso" => "BF",
			"burundi" => "BI",
			"cambodia" => "KH",
			"cameroon" => "CM",
			"canada" => "CA",
			"canton__enderbury_i" => "CT",
			"cape_verde" => "CV",
			"cayman_islands" => "KY",
			"central_african_republic" => "CF",
			"chad" => "TD",
			"chile" => "CL",
			"china" => "CN",
			"christmas_island" => "CX",
			"cocos_keeling_islands" => "CC",
			"colombia" => "CO",
			"comoros" => "KM",
			"congo_the_democratic_republic_of_the" => "CD",
			"cook_islands" => "CK",
			"costa_rica" => "CR",
			"cote_divoire" => "CI",
			"croatia" => "HR",
			"cyprus" => "CY",
			"czech_republic" => "CA",
			"denmark" => "DK",
			"djibouti" => "DJ",
			"dominica" => "DM",
			"dominican_republic" => "DO",
			"dronning_maud_land" => "NQ",
			"ecuador" => "EC",
			"egypt" => "EG",
			"el_salvador" => "SV",
			"equatorial_guinea" => "GQ",
			"eritrea" => "ER",
			"estonia" => "EE",
			"ethiopia" => "ET",
			"falkland_islands_malvinas" => "FK",
			"faroe_islands" => "FO",
			"fiji" => "FJ",
			"finland" => "FI",
			"france" => "FR",
			"french_guiana" => "GF",
			"french_polynesia" => "PF",
			"french_southern_territories" => "TF",
			"gabon" => "GA",
			"gambia" => "GM",
			"georgia" => "GE",
			"germany" => "DE",
			"ghana" => "GH",
			"gibraltar" => "GI",
			"gilbert_islands" => "GE",
			"greece" => "GR",
			"greenland" => "GL",
			"grenada" => "GRD",
			"guadeloupe" => "GP",
			"guam" => "GJ",
			"guatemala" => "GT",
			"guernsey" => "GG",
			"guinea" => "GN",
			"guineabissau" => "GW",
			"guyana" => "GY",
			"haiti" => "HT",
			"heard_and_mcdonald_islands" => "HM",
			"honduras" => "HN",
			"hong_kong" => "HK",
			"hungary" => "HU",
			"iceland" => "IS",
			"india" => "IN",
			"indonesia" => "ID",
			"iraq" => "IQ",
			"ireland" => "IE",
			"isle_of_man" => "IM",
			"israel" => "IL",
			"italy" => "IT",
			"jamaica" => "JM",
			"japan" => "JP",
			"jersey" => "JE",
			"johnston_island" => "UM",
			"jordan" => "JO",
			"kazakhstan" => "KZ",
			"kenya" => "KE",
			"kiribati" => "KI",
			"kuwait" => "KW",
			"kyrgyzstan" => "KQ",
			"lao_peoples_democratic_republic" => "LA",
			"latvia" => "LV",
			"lebanon" => "LB",
			"lesotho" => "LS",
			"liberia" => "LR",
			"libyan_arab_jamahiriya" => "LY",
			"liechtenstein" => "LI",
			"lithuania" => "LT",
			"luxembourg" => "LU",
			"macau" => "MO",
			"macedonia" => "MK",
			"madagascar" => "MG",
			"malawi" => "MW",
			"malaysia" => "MY",
			"maldives" => "MV",
			"mali" => "ML",
			"malta" => "MT",
			"marshall_islands" => "MH",
			"martinique" => "MQ",
			"mauritania" => "MR",
			"mauritius" => "MU",
			"mexico" => "MX",
			"micronesia" => "FM",
			"midway_islands" => "UM",
			"moldova" => "MD",
			"monaco" => "MC",
			"mongolia" => "MN",
			"montenegro" => "ME",
			"montserrat" => "MS",
			"morocco" => "MA",
			"mozambique" => "MZ",
			"namibia" => "NA",
			"nauru" => "NR",
			"nepal" => "NP",
			"netherlands" => "NL",
			"netherlands_antilles" => "AN",
			"new_caledonia" => "NC",
			"new_hebrides" => "NH",
			"new_zealand" => "NZ",
			"nicaragua" => "NI",
			"niger" => "NE",
			"nigeria" => "NG",
			"norfolk_island" => "NF",
			"northern_mariana_islands" => "MP",
			"norway" => "NO",
			"oman" => "OM",
			"pakistan" => "PK",
			"palau" => "PW",
			"palestinian_territory_occupied" => "PS",
			"panama" => "PA",
			"papua_new_guinea" => "PG",
			"paraguay" => "PY",
			"peru" => "PE",
			"philippines" => "PH",
			"pitcairn" => "PN",
			"poland" => "PL",
			"portugal" => "PT",
			"puerto_rico" => "PR",
			"qatar" => "QA",
			"reunion" => "RE",
			"romania" => "RO",
			"russia" => "RU",
			"rwanda" => "RW",
			"saint_barthelemy" => "BL",
			"saint_kitts_and_nevis" => "KN",
			"saint_lucia" => "LC",
			"saint_martin_french_portion" => "MF",
			"saint_vincent_and_the_grenadines" => "VC",
			"saipan" => "MP",
			"samoa" => "WS",
			"san_marino" => "SM",
			"sao_tome_and_principe" => "ST",
			"saudi_arabia" => "SA",
			"scotland" => "GB",
			"senegal" => "SN",
			"serbia_republic_of_serbia" => "RS",
			"seychelles" => "SC",
			"sierra_leone" => "SL",
			"singapore" => "SG",
			"slovakia" => "SK",
			"slovenia" => "SI",
			"solomon_islands" => "SB",
			"somalia" => "SO",
			"south_africa" => "ZA",
			"south_georgia_and_the_south_sandwich_islands" => "GS",
			"south_korea" => "KR",
			"southern_rhodesia" => "RH",
			"spain" => "ES",
			"sri_lanka" => "LK",
			"st_helena" => "SH",
			"st_pierre_and_miquelon" => "FX",
			"suriname" => "SR",
			"svalbard_and_jan_mayen_islands" => "SJ",
			"swaziland" => "SZ",
			"switzerland" => "CH",
			"taiwan" => "TW",
			"tajikistan" => "TJ",
			"tanzania_united_republic" => "TZ",
			"thailand" => "TH",
			"timorleste" => "TL",
			"togo" => "TG",
			"tokelau" => "TK",
			"tonga" => "TO",
			"trinidad_and_tobago" => "TT",
			"tunisia" => "TN",
			"turkey" => "TR",
			"turkmenistan" => "TM",
			"turks_and_caicos_islands" => "TC",
			"tuvalu" => "TV",
			"uganda" => "UG",
			"ukraine" => "UA",
			"united_arab_emirates" => "AE",
			"united_kingdom" => "GB",
			"uruguay" => "UY",
			"uzbekistan" => "UZ",
			"vanuatu" => "VU",
			"venezuela" => "VE",
			"vietnam" => "VN",
			"virgin_islands_british" => "VG",
			"wake_island" => "UM",
			"wallis_and_futuna_islands" => "WF",
			"west_indies" => "AI",
			"western_sahara" => "EH",
			"yemen" => "YE",
			"yugoslavia" => "YU",
			"zaire" => "ZR",
			"zambia" => "ZM",
			"zimbabwe" => "ZW",
		);

		return isset($countryCodes[$countryCode]) ? $countryCodes[$countryCode] : $countryCode;
	}
}
