<?php
/**
 * Created by Magenest JSC.
 * Author: Jacob
 * Date: 10/01/2019
 * Time: 9:41
 */

namespace Magenest\StripePayment\Model;

use Magenest\StripePayment\Exception\StripePaymentException;
use Magenest\StripePayment\Helper\Config;
use Magenest\StripePayment\Helper\Constant;
use Magento\Framework\Exception\LocalizedException;
use Magento\Payment\Model\Method\AbstractMethod;
use Stripe;

class Sofort extends AbstractMethod
{
    const CODE = 'magenest_stripe_sofort';
    protected $_code = self::CODE;

    protected $_isGateway = true;
    protected $_canAuthorize = true;
    protected $_canCapture = true;
    protected $_canCapturePartial = false;
    protected $_canCaptureOnce = true;
    protected $_canVoid = true;
    protected $_canUseInternal = false;
    protected $_canUseCheckout = true;
    protected $_canRefund = true;
    protected $_canRefundInvoicePartial = true;

    protected $_chargeFactory;
    protected $_helper;

    protected $_isInitializeNeeded = true;

    protected $stripeLogger;
    protected $_messageManager;
    protected $storeManagerInterface;
    protected $stripeConfig;
    protected $request;

    public function __construct(
        \Magenest\StripePayment\Helper\Config $stripeConfig,
        \Magenest\StripePayment\Helper\Data $dataHelper,
        \Magento\Framework\Message\ManagerInterface $messageManager,
        \Magenest\StripePayment\Helper\Logger $stripeLogger,
        \Magento\Store\Model\StoreManagerInterface $storeManagerInterface,
        \Magento\Framework\App\RequestInterface $request,
        \Magento\Framework\Model\Context $context,
        \Magento\Framework\Registry $registry,
        \Magento\Framework\Api\ExtensionAttributesFactory $extensionFactory,
        \Magento\Framework\Api\AttributeValueFactory $customAttributeFactory,
        \Magento\Payment\Helper\Data $paymentData,
        \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig,
        \Magento\Payment\Model\Method\Logger $logger,
        \Magento\Framework\Model\ResourceModel\AbstractResource $resource = null,
        \Magento\Framework\Data\Collection\AbstractDb $resourceCollection = null,
        array $data = []
    ) {
        $this->_helper = $dataHelper;
        $this->stripeLogger = $stripeLogger;
        $this->_messageManager = $messageManager;
        $this->storeManagerInterface = $storeManagerInterface;
        $this->stripeConfig = $stripeConfig;
        $this->request = $request;
        parent::__construct(
            $context,
            $registry,
            $extensionFactory,
            $customAttributeFactory,
            $paymentData,
            $scopeConfig,
            $logger,
            $resource,
            $resourceCollection,
            $data
        );
    }

    public function initialize($paymentAction, $stateObject)
    {
        try {
            Stripe\Stripe::setApiKey($this->stripeConfig->getSecretKey());
            $payment = $this->getInfoInstance();
            $order = $payment->getOrder();
            $sourceId = $payment->getAdditionalInformation("stripe_source_id");
            $amount = $order->getBaseGrandTotal();
            $chargeRequest = $this->_helper->createChargeRequest($order, $amount, $sourceId);
            $charge = Stripe\Charge::create($chargeRequest);
            $this->_debug($charge->getLastResponse()->json);
            $chargeId = $charge->id;
            $payment->setAdditionalInformation("stripe_charge_id", $chargeId);
            $chargeStatus = $charge->status;
            $totalDue = $order->getTotalDue();
            $baseTotalDue = $order->getBaseTotalDue();
            $stateObject->setData('state', \Magento\Sales\Model\Order::STATE_PROCESSING);
            if ($chargeStatus == 'pending') {
                $payment->setTransactionId($chargeId);
                $payment->setAmountAuthorized($totalDue);
                $payment->authorize(true, $baseTotalDue);
                $order->setCanSendNewEmailFlag(false);
            }
            if ($chargeStatus == 'succeeded') {
                $transactionId = $charge->balance_transaction;
                $payment->setTransactionId($transactionId)
                    ->setLastTransId($transactionId);
                $payment->setAmountAuthorized($totalDue);
                $payment->setBaseAmountAuthorized($baseTotalDue);
                $payment->capture(null);
            }
            if ($chargeStatus == 'failed') {
                throw new StripePaymentException(
                    __("Payment failed")
                );
            }
            return parent::initialize($paymentAction, $stateObject); // TODO: Change the autogenerated stub
        }catch (\Stripe\Error\Base $e){
            throw new LocalizedException(__($e->getMessage()));
        }
    }

    public function authorize(\Magento\Payment\Model\InfoInterface $payment, $amount)
    {
        $payment->setIsTransactionClosed(0);
        return parent::authorize($payment, $amount);
    }

    /**
     * @param \Magento\Payment\Model\InfoInterface|\Magento\Sales\Model\Order\Payment $payment
     * @param float $amount
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function capture(\Magento\Payment\Model\InfoInterface $payment, $amount)
    {
        try {
            Stripe\Stripe::setApiKey($this->stripeConfig->getSecretKey());
            $order = $payment->getOrder();
            $chargeId = $payment->getAdditionalInformation("stripe_charge_id");
            if (!$chargeId) {
                throw new LocalizedException(
                    __("Charge doesn't exist. Please try again later.")
                );
            } else {
                $charge = Stripe\Charge::retrieve($chargeId);
            }
            $chargeStatus = $charge->status;
            if ($chargeStatus == 'pending') {
                throw new LocalizedException(
                    __("Payment is pending. Cannot capture this payment")
                );
            }
            if ($chargeStatus == 'succeeded') {
                $order->setCanSendNewEmailFlag(true);
                $transactionId = $charge->balance_transaction;
                $payment->setTransactionId($transactionId)
                    ->setLastTransId($transactionId);
                $payment->setIsTransactionClosed(1);
                $payment->setShouldCloseParentTransaction(1);
            }
            if ($chargeStatus == 'failed') {
                throw new LocalizedException(
                    __("Payment failed")
                );
            }

            return parent::capture($payment, $amount);
        }catch (\Stripe\Error\Base $e){
            if($e->getStripeCode() == 'idempotency_key_in_use'){
                throw new \Magenest\StripePayment\Exception\StripePaymentDuplicateException($e->getMessage());
            }else {
                throw new LocalizedException(__($e->getMessage()));
            }
        }
    }

    /**
     * @param \Magento\Payment\Model\InfoInterface|\Magento\Sales\Model\Order\Payment $payment
     * @param float $amount
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function refund(\Magento\Payment\Model\InfoInterface $payment, $amount)
    {
        try {
            Stripe\Stripe::setApiKey($this->stripeConfig->getSecretKey());
            $chargeId = $payment->getAdditionalInformation("stripe_charge_id");
            $refundReason = $this->request->getParam('refund_reason');
            $request = $this->_helper->createRefundRequest($payment, $chargeId, $amount);
            if ($refundReason) {
                $request['reason'] = $refundReason;
            }
            $refund = Stripe\Refund::create($request);
            $this->_debug($refund->getLastResponse()->json);
            $transactionId = $refund->balance_transaction;
            if ($transactionId) {
                $payment->setTransactionId($transactionId);
            }
            $payment->setShouldCloseParentTransaction(0);
            return parent::refund($payment, $amount);
        }catch (\Stripe\Error\Base $e){
            throw new LocalizedException(__($e->getMessage()));
        }
    }

    public function void(\Magento\Payment\Model\InfoInterface $payment)
    {
        $order = $payment->getOrder();
        $amount = $order->getBaseGrandTotal();
        $this->refund($payment, $amount);
        $payment->setShouldCloseParentTransaction(1);
        return parent::void($payment);
    }

    public function cancel(\Magento\Payment\Model\InfoInterface $payment)
    {
        if ($this->_appState->getAreaCode() == 'adminhtml') {
            $this->void($payment);
        }
        return parent::cancel($payment);
    }

    public function canUseForCurrency($currencyCode)
    {
        if (!in_array(strtolower($currencyCode), $this->getAcceptedCurrencyCodes())) {
            return false;
        }
        return true;
    }

    private function getAcceptedCurrencyCodes()
    {
        return ['eur'];
    }

    /**
     * @param array|string $debugData
     */
    protected function _debug($debugData)
    {
        $this->stripeLogger->debug(var_export($debugData, true));
    }
}
