<?php
/**
 * 2007-2021 PrestaShop
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Academic Free License (AFL 3.0)
 * that is bundled with this package in the file LICENSE.txt.
 * It is also available through the world-wide-web at this URL:
 * http://opensource.org/licenses/afl-3.0.php
 * If you did not receive a copy of the license and are unable to
 * obtain it through the world-wide-web, please send an email
 * to license@prestashop.com so we can send you a copy immediately.
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade PrestaShop to newer
 * versions in the future. If you wish to customize PrestaShop for your
 * needs please refer to http://www.prestashop.com for more information.
 *
 * @author    PrestaShop SA <contact@prestashop.com>
 * @copyright 2007-2021 PrestaShop SA
 * @license   http://opensource.org/licenses/afl-3.0.php  Academic Free License (AFL 3.0)
 *  International Registered Trademark & Property of PrestaShop SA
 */

namespace Prestashop\Module\AddonPayments\Operations;

use const _DB_PREFIX_;
use const _PS_USE_SQL_SLAVE_;
use addonpayments;
use ComerciaGlobalPayments\AddonPayments\SDK\Response\Transaction;
use Db;
use Exception;
use Prestashop\Module\AddonPayments\Helpers\SecurityTrait;
use Prestashop\Module\AddonPayments\OperationContext;
use PrestaShopLogger;
use function pSQL;
use RuntimeException;

/**
 * Implements transaction processing to be stored in the database.
 */
class ProcessTransaction
{
    use SecurityTrait;

    /**
     * @var \Prestashop\Module\AddonPayments\OperationContext
     */
    private $context;

    /**
     * @var \addonpayments
     */
    private $module;

    /**
     * ProcessTransaction constructor.
     */
    public function __construct(OperationContext $context, addonpayments $module)
    {
        $this->context = $context;
        $this->module = $module;
    }

    public function __invoke(Transaction $transaction, bool $isLastOperation)
    {
        $db = Db::getInstance(_PS_USE_SQL_SLAVE_);
        try {
            $dbPrefix = _DB_PREFIX_;
            $payfrexTxId = pSQL($transaction->getPayFrexTransactionId());
            $merchantTxId = pSQL($transaction->getMerchantTransactionId());
            $sortedOrder = $transaction->getSortedOrder();
            $exists = $db->getValue(
                "SELECT `id_transaction`
                FROM `{$dbPrefix}addonpayments_transactions`
                WHERE `payFrexTransactionId` = '$payfrexTxId'
                AND `merchantTransactionId` = '$merchantTxId'
                AND `sortedOrder` = {$sortedOrder}"
            );
            // @TODO: Refactor SDK to include a JSON serializable object for encrypted properties and other blobs
            $values = [
                'payFrexTransactionId' => $payfrexTxId,
                'merchantTransactionId' => $merchantTxId,
                'sortedOrder' => $sortedOrder,
                'EPGTransactionID' => pSQL($transaction->getEPGTransactionID()),
                'amount' => $transaction->getAmount(),
                'currency' => pSQL($transaction->getCurrency()),
                'originalPayfrexTransactionId' => pSQL($transaction->getOriginalPayFrexTransactionId()),
                'originalAmount' => $transaction->getOriginalAmount(),
                'originalCurrency' => pSQL($transaction->getOriginalCurrency()),
                'remainingAmount' => $transaction->getRemainingAmount(),
                'fee' => $transaction->getFee(),
                'details' => $this->encrypt(
                    json_encode($transaction->getDetails()),
                    $this->module->getEncryptionKey()
                ),
                'message' => pSQL($transaction->getMessage()),
                'operationType' => pSQL($transaction->getOperationType()),
                'paymentDetails' => $this->encrypt(
                    json_encode($transaction->getPaymentDetails()),
                    $this->module->getEncryptionKey()
                ),
                'optionalTransactionParams' => json_encode($transaction->getOptionalTransactionParams()),
                'paymentSolution' => pSQL($transaction->getPaymentSolution()),
                'paySolTransactionId' => pSQL($transaction->getPaySolTransactionId()),
                'respCode' => json_encode($transaction->getRespCode()),
                'status' => pSQL($transaction->getStatus()),
                'lastOp' => $isLastOperation,
                'rawData' => $this->encrypt(
                    json_encode($transaction->getRawTransactionObject()),
                    $this->module->getEncryptionKey()
                ),
                'updatedAt' => date('Y-m-d H:i:s'),
            ];

            if (!$exists) {
                $values += [
                    'id_order' => $this->context->getCartOrOrderId(),
                    'createdAt' => date('Y-m-d H:i:s'),
                ];
                $result = $db->insert('addonpayments_transactions', $values);

                if (false === $result) {
                    throw new RuntimeException('The transaction was not stored in the database');
                }

                return;
            }

            $result = $db->update('addonpayments_transactions', $values, "id_transaction = {$exists}");

            if (false === $result) {
                throw new RuntimeException('The transaction was not stored in the database');
            }
        } catch (Exception $e) {
            PrestaShopLogger::addLog($e->getMessage(), 3, $e->getCode(), __CLASS__);
        }
    }
}
