<?php
/**
 * @package     CMGiftCard
 * @subpackage  plg_cmgiftcard_mercadopago
 * @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;

/**
 * MercadoPago payment method for CMGiftCard.
 *
 * @package     CMGiftCard
 * @subpackage  plg_cmgiftcard_mercadopago
 * @since       1.2.1
 */
class PlgCMGiftCardMercadoPago 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.1
	 */
	public function __construct(&$subject, $config = array())
	{
		$this->gatewayId = 'mercadopago';
		$this->gatewayName = 'PLG_CMGIFTCARD_MERCADOPAGO_NAME';

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

	/**
	 * Method to get payment form.
	 *
	 * @param   array  $data  Billing data.
	 *
	 * @return  array
	 *
	 * @since   1.2.1
	 */
	public function onCMGCGetPaymentForm($data)
	{
		$gatewayId = isset($data['billing']['payment_method']) ? $data['billing']['payment_method'] : '';

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

		require_once dirname(__FILE__) . '/lib/mercadopago.php';

		$gatewayName = $this->params->get('name', Text::_($this->gatewayName));
		$clientId = $this->params->get('client_id');
		$clientSecret = $this->params->get('client_secret');
		$currencyId = $this->params->get('currency_id', 'USD');
		$environment = $this->params->get('environment', 'live');
		$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);

		$mp = new MP($clientId, $clientSecret);

		$siteUrl = str_replace(Uri::root(true), '', substr(Uri::root(), 0, -1));
		$backUrls = new StdClass;
		$backUrls->success = $siteUrl . CMGiftCardHelper::prepareRoute('index.php?option=com_cmgiftcard&view=checkout') . '?layout=success';
		$backUrls->pending =  $siteUrl . CMGiftCardHelper::prepareRoute('index.php?option=com_cmgiftcard&view=checkout') . '?layout=success';
		$backUrls->failure =  $siteUrl . CMGiftCardHelper::prepareRoute('index.php?option=com_cmgiftcard&view=checkout') . '?layout=cancel';

		$address = new StdClass;
		$address->zip_code = isset($data['billing']['postal_code']) ? $data['billing']['postal_code'] : '';
		$address->street_name = isset($data['billing']['address_1']) ? $data['billing']['address_1'] : '';
		$address->street_name .= isset($data['billing']['city']) ? ', ' . $data['billing']['city'] : '';
		$address->street_name .= isset($data['billing']['state']) ? ', ' . $data['billing']['state'] : '';

		$payer = new StdClass;
		$payer->name = $data['billing']['first_name'];
		$payer->surname = $data['billing']['last_name'];
		$payer->email = $data['billing']['email'];
		$payer->address = $address;

		$items = array();

		foreach ($data['items'] as $n => $item)
		{
			$items[] = array(
				"title" => $item['design_title'],
				"quantity" => 1,
				"currency_id" => $currencyId,
				"unit_price" => (float) $item['amount'],
			);
		}

		$preferenceData = array(
			"items" => $items,
			"payer" => $payer,
			"back_urls" => $backUrls,
			"notification_url" => Uri::root() . 'index.php?option=com_cmgiftcard&task=callback&gateway=' . $this->gatewayId,
			"external_reference" => $data['billing']['order_number'],
		);

		$preference = $mp->create_preference($preferenceData);

		if ($environment == 'live')
		{
			$url = $preference['response']['init_point'];
		}
		else
		{
			$url = $preference['response']['sandbox_init_point'];
		}

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

		return $html;
	}

	/**
	 * Method to get validate MercadoPago callback.
	 *
	 * @return  boolean
	 *
	 * @since   1.2.1
	 */
	public function onCMGCValidateCallback()
	{
		$jinput = Factory::getApplication()->input;
		$gatewayId = $jinput->get('gateway', '');
		$data = $_GET;
		$dataId = isset($data['id']) ? $data['id'] : 0;

		$result = array(
			'validation'		=> false,
			'gateway_id'		=> '',
			'transaction_info'	=> '',
			'order_id'			=> ''
		);

		if ($gatewayId != $this->gatewayId)
		{
			$this->logNotification($data, false);

			return $result;
		}

		if ($dataId == 0)
		{
			$data['failure_reason'] = "No ID not found";
			$this->logNotification($data, false);

			return $result;
		}

		require_once dirname(__FILE__) . '/lib/mercadopago.php';

		$clientId = $this->params->get('client_id');
		$clientSecret = $this->params->get('client_secret');
		$reason = '';
		$orderId = 0;
		$orderNumber = 0;

		$mp = new MP($clientId, $clientSecret);

		if ($_GET["topic"] == 'payment')
		{
			$payment_info = $mp->get("/collections/notifications/" . $dataId);
			$merchant_order_info = $mp->get("/merchant_orders/" . $payment_info["response"]["collection"]["merchant_order_id"]);
		}
		else
		{
			$merchant_order_info = $mp->get("/merchant_orders/" . $dataId);
		}

		$data['merchant_order_info'] = json_encode($merchant_order_info);

		if (isset($merchant_order_info["response"]['external_reference']))
		{
			$orderNumber = (int) $merchant_order_info["response"]['external_reference'];
		}

		if ($orderNumber == 0)
		{
			$data['failure_reason'] = "Order number not found";
			$this->logNotification($data, false);

			return $result;
		}

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

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

			return $result;
		}
		elseif (isset($order->order_status) && $order->order_status == 'paid')
		{
			$data['failure_reason'] = "Order number $orderNumber was already paid.";
			$this->logNotification($data, false);

			return $result;
		}
		elseif (isset($order->order_status) && $order->order_status == 'refunded')
		{
			$data['failure_reason'] = "Order number $orderNumber was already refunded.";
			$this->logNotification($data, false);

			return $result;
		}

		$orderId = $order->id;
		$paid_amount = 0;

		if ($merchant_order_info["status"] == 200)
		{
			foreach ($merchant_order_info["response"]["payments"] as  $payment)
			{
				if ($payment['status'] == 'approved')
				{
					$paid_amount += $payment['transaction_amount'];
				}
			}

			if ($paid_amount >= $merchant_order_info["response"]["total_amount"])
			{
				if (count($merchant_order_info["response"]["shipments"]) > 0)
				{
					if ($merchant_order_info["response"]["shipments"][0]["status"] != "ready_to_ship")
					{
						$data['failure_reason'] = 'Not ready to ship';
						$this->logNotification($data, false);

						return $result;
					}
				}
			}
			else
			{
				$data['failure_reason'] = "Paid amount was $paid_amount, but total amount was " . $merchant_order_info["response"]["total_amount"];
				$this->logNotification($data, false);

				return $result;
			}
		}
		else
		{
			$data['failure_reason'] = 'Connection error';
			$this->logNotification($data, false);

			return $result;
		}

		$isValid = true;

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

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

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

			$isValid = ($amount == $paid_amount);

			if (!$isValid)
			{
				$reason = "Invalid paid amount, expected $amount, got $paid_amount";
			}
		}
		else
		{
			$isValid = false;
			$reason = "No gift cards found";
		}

		$result['valid'] = $isValid;

		if ($isValid)
		{
			$result['gateway_id'] = $this->gatewayId;
			$result['order_id'] = $orderId;
			$result['transaction_id'] = $dataId;
		}
		else
		{
			$data['failure_reason'] = $reason;
		}

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

		return $result;
	}
}
