<?php

namespace Sibs\Sibs\Controller\Payment;

use Sibs\Sibs\DB\SibsDB;
use Sibs\Sibs\Model\SibsConstants;
use Sibs\Sibs\Model\SibsOrder;
use Sibs\Sibs\Utils\SibsException;
use Sibs\Sibs\Utils\SibsLog;
use Sibs\Sibs\Utils\SibsUtils;

class SibsCallback extends \Magento\Framework\App\Action\Action
{
    protected $_sibsOrder;

    /**
     * @var \Magento\Framework\App\Action\Context
     */
    protected $_context;

    /**
     * @var \Magento\Checkout\Model\Session
     */
    protected $_checkoutSession;

    /**
     * @var \Sibs\Sibs\Helper\DataHelper
     */
    protected $_helper;

    /**
     * @var \Magento\Sales\Model\Order\Email\Sender\OrderSender
     */
    protected $_ordersender;

    /**
     * @var \Magento\Backend\Model\UrlInterface
     */
    protected $_backendUrl;

    /**
     * @var \Magento\Framework\App\Request\Http
     */
    protected $_request;

    /**
     * @var \Magento\Framework\Mail\Template\TransportBuilder
     */
    protected $_transportBuilder;

    /**
     * @var \Magento\Store\Model\StoreManagerInterface
     */
    protected $_storeManager;

    /**
     * @var \Magento\Framework\Event\ManagerInterface
     */
    protected $_eventManager;

    /**
     * @var \Magento\Framework\Message\ManagerInterface
     */
    protected $_messageManager;

    public function __construct(
        \Magento\Framework\App\Action\Context $context,
        \Magento\Checkout\Model\Session $checkoutSession,
        \Sibs\Sibs\Helper\DataHelper $helper,
        \Magento\Sales\Model\Order\Email\Sender\OrderSender $_ordersender,
        \Magento\Backend\Model\UrlInterface $backendUrl,
        \Magento\Framework\App\Request\Http $request,
        \Magento\Framework\Mail\Template\TransportBuilder $transportBuilder,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Event\ManagerInterface $eventManager
    ) {
        parent::__construct($context);
        $this->_context          = $context;
        $this->_checkoutSession  = $checkoutSession;
        $this->_helper           = $helper;
        $this->_ordersender      = $_ordersender;
        $this->_backendUrl       = $backendUrl;
        $this->_request          = $request;
        $this->_transportBuilder = $transportBuilder;
        $this->_storeManager     = $storeManager;
        $this->_eventManager     = $eventManager;
        $this->_messageManager   = $context->getMessageManager();
    }

    /**
     * Execute Callback
     *
     * @return ResponseInterface
     */
    public function execute()
    {
        $checkoutId       = $this->getCallbackTransactionID();
        $orderId          = $this->_checkoutSession->getLastRealOrder()->getId();
        $this->_sibsOrder = new SibsOrder($orderId);

        try {
            $orderPaymentMethod = $this->_sibsOrder->getPaymentMethodCode();
            SibsLog::info("CALLBACK - orderPaymentMethod: $orderPaymentMethod");

            if (! in_array($orderPaymentMethod, SibsConstants::SIBS_PAYMENTS)) {
                throw new SibsException('Payment Method is not from SIBS');
            }

            list($statusCode, $paymentType, $paymentStatus, $transactionID, $amountValue, $amountCurrency) = $this->callbackPaymentInquiry($checkoutId);
            list($orderState, $orderStatus) = $this->_helper->sibs_get_order_state_and_status($paymentStatus, $paymentType);

            SibsLog::info("CALLBACK - Order (State, Status) after inquiry: (State: $orderState, Statys: $orderStatus)");

            $this->_sibsOrder->makeOrder(
                $orderPaymentMethod,
                $statusCode,
                $paymentType,
                $orderState,
                $orderStatus,
                $transactionID,
                $amountValue,
                $amountCurrency
            );

            SibsLog::info('CALLBACK - Order Saved');

            $this->deleteCart();
            $this->sendMail();

            $this->_messageManager->addSuccessMessage(__('Your order was successfully created'));

            return $this->_redirect('checkout/onepage/success');
        } catch(SibsException $e) {
            $this->remakeCart();

            SibsLog::err('CALLBACK - Error: ' . $e->getMessage());

            $this->_messageManager->addErrorMessage(__('Error in payment'));

            // return $this->_redirect('checkout', ['_fragment' => 'payment']);
            // return $this->_redirect('checkout/cart');

            // OR

            return $this->_redirect('sibs/checkout/failed');
        }
    }

    /**
     * Get Callback Transaction ID
     *
     * @return string
     */
    private function getCallbackTransactionID()
    {
        if (empty($_GET['id'])) {
            throw new SibsException('Missing ID');
        }

        return $_GET['id'];
    }

    /**
     * Callback Payment Inquiry with SIBS
     *
     * @return array
     */
    private function callbackPaymentInquiry($checkoutId, $qtyAttempts = 5)
    {
        $url       = $this->_helper->getUrlStatus($checkoutId);
        $token     = $this->_helper->getToken();
        $client_id = $this->_helper->getClientID();

        for ($i = 1; $i <= $qtyAttempts; $i++) {
            SibsLog::info("CALLBACK - Inquiry Attempt $i");
            $responseArray = $this->_helper->get_payment_result($url, $token, $client_id);

            try {
                return $this->getAndValidateResponse($responseArray);
            } catch (SibsException $e) {
                SibsLog::warn("CALLBACK - Attempt $i Failed: " . $e->getMessage());
            }
        }

        throw new SibsException('No attempt was successful.');
    }

    /**
     * Get and Validate Response
     *
     * @return array
     */
    private function getAndValidateResponse($response)
    {
        SibsLog::info('CALLBACK - Response: ' . SibsLog::prettify($response));

        if (empty($response['returnStatus']['statusCode'])) {
            throw new SibsException('Missing [returnStatus][statusCode]');
        } elseif (SibsUtils::getTransactionResult($response['returnStatus']['statusCode']) == SibsConstants::SIBS_NOK) {
            throw new SibsException('Attempt Request NOK');
        }

        if (empty($response['paymentMethod'])) {
            throw new SibsException('Missing [paymentMethod]');
        }

        if (empty($response['paymentType'])) {
            throw new SibsException('Missing [paymentType]');
        }

        if (empty($response['paymentStatus'])) {
            throw new SibsException('Missing [paymentStatus]');
        }

        if (empty($response['transactionID'])) {
            throw new SibsException('Missing [transactionID]');
        }

        if (empty($response['amount']['value'])) {
            throw new SibsException('Missing [amount][value]');
        }

        if (empty($response['amount']['currency'])) {
            throw new SibsException('Missing [amount][currency]');
        }

        return [
            $response['returnStatus']['statusCode'],
            // $response['paymentMethod'],
            $response['paymentType'],
            $response['paymentStatus'],
            $response['transactionID'],
            $response['amount']['value'],
            $response['amount']['currency'],
        ];
    }

    /**
     * Delete Cart
     */
    private function deleteCart()
    {
        SibsLog::info('CALLBACK - Delete Cart');

        $registry = SibsDB::get('Magento\Framework\Registry');
        $registry->register('isSecureArea', 'true');

        $order = $this->_sibsOrder->get();

        $objectManager = \Magento\Framework\App\ObjectManager::getInstance();
        $quote         = $objectManager->create('Magento\Quote\Model\QuoteFactory')->create()->load($order->getQuoteId());

        $quote->setIsActive(false);
        $quote->save();

        // replace the quote to the checkout session (I guess this is the better way)
        $this->_checkoutSession->replaceQuote($quote);

        $this->_checkoutSession->setLastSuccessQuoteId($order->getQuoteId());
        $this->_checkoutSession->setLastQuoteId($order->getQuoteId());
        $this->_checkoutSession->setLastOrderId($order->getEntityId());

        $registry->unregister('isSecureArea');

        SibsLog::info('CALLBACK - Cart Deleted');
    }

    /**
     * Remake Cart
     */
    private function remakeCart()
    {
        SibsLog::info('CALLBACK - Remake Cart');

        $registry = SibsDB::get('Magento\Framework\Registry');
        $registry->register('isSecureArea', 'true');

        $this->_checkoutSession->restoreQuote();

        $registry->unregister('isSecureArea');

        SibsLog::info('CALLBACK - Cart Remade');
    }

    /**
     * Send Mail
     */
    private function sendMail()
    {
        $emailSended = $this->_ordersender->send($this->_sibsOrder->get());

        if ($emailSended) {
            SibsLog::info('CALLBACK - Email Sended');
        } else {
            SibsLog::warn('CALLBACK - Email Not Sended');
        }
    }
}
