<?php

/**
 *
 * @category MultiSafepay
 * @package  MultiSafepay_Msp
 */
require_once(Mage::getBaseDir('lib') . DS . 'multisafepay' . DS . 'MultiSafepay.combined.php');
require_once Mage::getModuleDir('', 'MultiSafepay_Msp') . DS . 'Model' . DS . 'Api' . DS . 'Client.php';

abstract class MultiSafepay_Msp_Model_Gateway_Abstract extends Mage_Payment_Model_Method_Abstract
{
    protected $_module = "msp"; // Config root (msp or payment)
    protected $_settings = "msp"; // Config root for settings (always msp for now)
    protected $_code; // Payment method code
    protected $_isGiftcard = false;
    protected $_isRegularGateway = false;
    protected $_requiresShoppingCart = false;
    protected $_backendOrdersAllowed = false;
    protected $_model; // Payment model
    protected $_formBlockType = 'msp/default';
    public $_gateway; // Sp 'gateway'
    public $_mybankissuer;
    protected $_params;
    protected $_loadSettingsConfig = true; // Load 'settings' before payment config
    protected $_loadGatewayConfig = true;
    protected $_canCapture = true;
    protected $_canCapturePartial = true;
    protected $_canUseForMultishipping = false;
    protected $_canUseInternal = true;
    protected $_canRefund = true;
    protected $_canRefundInvoicePartial = true;
    public $payment;
    public $_configCode = 'msp';

    const MSP_GENERAL_CODE = 'msp';
    const MSP_FASTCHECKOUT_CODE = 'mspcheckout';
    const MSP_GENERAL_PAD_CODE = 'msp_payafter';
    const MSP_GENERAL_PAD_INSTALLMENTS_CODE = 'msp_payafterdeliveryinstallments';
    const MSP_GENERAL_IN3_CODE = 'msp_in3';
    const MSP_GENERAL_ZINIA_CODE = 'msp_zinia';
    const MSP_GENERAL_AFTERPAY_CODE = 'msp_afterpay';
    const MSP_GENERAL_KLARNA_CODE = 'msp_klarna';
    const MSP_GENERAL_EINVOICE_CODE = 'msp_einvoice';
    const MSP_GATEWAYS_CODE_PREFIX = 'msp_';

    public $availablePaymentMethodCodes = array(
        'msp',
        'mspcheckout',
        'msp_ideal',
        'msp_creditcard',
        'msp_dotpay',
        'msp_payafter',
        'msp_payafterdeliveryinstallments',
        'msp_einvoice',
        'msp_klarna',
        'msp_mistercash',
        'msp_visa',
        'msp_eps',
        'msp_ferbuy',
        'msp_mastercard',
        'msp_mybank',
        'msp_ing',
        'msp_cbc',
        'msp_kbc',
        'msp_belfius',
        'msp_idealqr',
        'msp_banktransfer',
        'msp_maestro',
        'msp_paypal',
        /* Start Paysafecard */
        'msp_paysafecard',
        /* End Paysafecard */
        'msp_webgift',
        'msp_ebon',
        'msp_babygiftcard',
        'msp_podium',
        'msp_vvvgiftcard',
        'msp_sportenfit',
        'msp_beautyandwellness',
        'msp_boekenbon',
        'msp_erotiekbon',
        'msp_givacard',
        'msp_parfumnl',
        'msp_parfumcadeaukaart',
        'msp_degrotespeelgoedwinkel',
        'msp_giropay',
        'msp_multisafepay',
        'msp_directebanking',
        'msp_directdebit',
        'msp_fastcheckout',
        'msp_amazonpay',
        'msp_amex',
        'msp_alipayplus',
        'msp_billink',
        'msp_bizum',
        'msp_yourgift',
        'msp_wijncadeau',
        'msp_lief',
        'msp_gezondheidsbon',
        'msp_fashioncheque',
        'msp_fashiongiftcard',
        'msp_trustly',
        'msp_afterpay',
        'msp_applepay',
        'msp_directbanktransfer',
        'msp_in3',
        'msp_zinia',
        'msp_good4fun',
    );

    public $giftcards = array(
        'msp_webgift',
        'msp_ebon',
        'msp_babygiftcard',
        'msp_boekenbon',
        'msp_erotiekbon',
        'msp_givacard',
        'msp_parfumnl',
        'msp_parfumcadeaukaart',
        'msp_degrotespeelgoedwinkel',
        'msp_yourgift',
        'msp_wijncadeau',
        'msp_lief',
        'msp_gezondheidsbon',
        'msp_fashioncheque',
        'msp_fashiongiftcard',
        'msp_podium',
        'msp_vvvgiftcard',
        'msp_sportenfit',
        'msp_beautyandwellness',
        'msp_good4fun',
    );
    public $gateways = array(
        'msp_ideal',
        'msp_creditcard',
        'msp_dotpay',
        'msp_payafter',
        'msp_payafterdeliveryinstallments',
        'msp_einvoice',
        'msp_klarna',
        'msp_mistercash',
        'msp_visa',
        'msp_eps',
        'msp_ferbuy',
        'msp_mastercard',
        'msp_mybank',
        'msp_banktransfer',
        'msp_maestro',
        'msp_paypal',
        'msp_giropay',
        'msp_multisafepay',
        'msp_directebanking',
        'msp_directdebit',
        'msp_ing',
        'msp_cbc',
        'msp_kbc',
        'msp_belfius',
        'msp_idealqr',
        'msp_amazonpay',
        'msp_amex',
        'msp_alipayplus',
        'msp_billink',
        'msp_bizum',
        /* Start Paysafecard */
        'msp_paysafecard',
        /* End Paysafecard */
        'msp_trustly',
        'msp_afterpay',
        'msp_applepay',
        'msp_directbanktransfer',
        'msp_in3',
        'msp_zinia',
    );

    public function __construct()
    {
        $storeId = Mage::app()->getStore()->getId();
        if ($this->_code == 'msp') {
            $currencies = explode(',', $this->getConfigData('allowed_currency'));
            $isAllowConvert = $this->getConfigData('allow_convert_currency');

            if ($isAllowConvert) {
                $this->_canUseCheckout = true;
            } else {
                if (in_array(Mage::app()->getStore()->getCurrentCurrencyCode(), $currencies)) {
                    $this->_canUseCheckout = true;
                } else {
                    $this->_canUseCheckout = false;
                }
            }
        } else {
            $isAllowConvert = false;
            $currencies = array();
            if ($this->isRegularGateway()) {
                $this->_configCode = 'msp_gateways';
                $this->_module = 'msp_gateways';
                $currencies = explode(',', Mage::getStoreConfig('msp_gateways/' . $this->_code . '/allowed_currency', $storeId));
                $isAllowConvert = Mage::getStoreConfigFlag('msp/settings/allow_convert_currency');
            } elseif ($this->isGiftcardGateway()) {
                $this->_configCode = 'msp_giftcards';
                $this->_module = 'msp_giftcards';
                $currencies = explode(',', Mage::getStoreConfig('msp_giftcards/' . $this->_code . '/allowed_currency', $storeId));
                $isAllowConvert = Mage::getStoreConfigFlag('msp/settings/allow_convert_currency');
            }

            if ($isAllowConvert) {
                $this->_canUseCheckout = true;
            } else {
                if (in_array(Mage::app()->getStore()->getCurrentCurrencyCode(), $currencies)) {
                    $this->_canUseCheckout = true;
                } else {
                    $this->_canUseCheckout = false;
                }
            }
        }

        $group_id = 0; // If not logged in, customer group id is 0
        if (Mage::getSingleton('customer/session')->isLoggedIn()) { // If logged in, set customer group id
            $group_id = Mage::getSingleton('customer/session')->getCustomer()->getGroupId();
        }
        $option = trim(Mage::getStoreConfig($this->_configCode . '/' . $this->_code . '/specificgroups'));
        $specificgroups = explode(",", $option);
        // If customer group is not in available groups and config option is not empty, disable this gateway
        if (!in_array($group_id, $specificgroups) && $option !== "") {
            $this->_canUseCheckout = false;
        }
    }

    public function isAvailableMethod()
    {
        return in_array($this->_code, $this->availablePaymentMethodCodes);
    }

    public function isRegularGateway()
    {
        return $this->_isRegularGateway | in_array($this->_code, $this->gateways);
    }

    public function isGiftcardGateway()
    {
        return $this->_isGiftcard | in_array($this->_code, $this->giftcards);
    }

    public function requiresShoppingCart()
    {
        return $this->_requiresShoppingCart | $this->getConfigData('requires_shopping_cart');
    }

    public function backendOrdersAllowed()
    {
        return $this->_backendOrdersAllowed;
    }

    /**
     * get the url of the configured gateway icon from the database
     */
    public function getIconUrl($locale = "en")
    {
        $fileWithPath = 'msp' . DS . $locale . DS . strtolower($this->getCode()) . '.' . 'png';
        $iconFileDir = Mage::getBaseDir(Mage_Core_Model_Store::URL_TYPE_MEDIA) . DS . $fileWithPath;
        if (file_exists($iconFileDir)) {
            $iconFileUrl = Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_MEDIA) . $fileWithPath;
            return $iconFileUrl;
        }
        return "";
    }

    // For 1.3.2.4
    // Disabled, needs testing. Comment mentioned this was for 1.3.x.x
    // and that version is no longer supported by this release
    /*
        public function isAvailable($quote = null) {
            return $this->getConfigData('active');
        }
    */

    public function setSortOrder($order)
    {
        // Magento tries to set the order from payment/, instead of our msp/
        $this->sort_order = Mage::getStoreConfig($this->_configCode . '/' . $this->_code . '/sort_order');
    }

    /**
     * Append the current model to the URL
     */
    public function getModelUrl($url)
    {
        if (!empty($this->_model)) {
            $url .= "/model/" . $this->_model;
        }

        return Mage::getUrl($url, array("_secure" => true));
    }

    /**
     * Magento will use this for payment redirection
     */
    public function getOrderPlaceRedirectUrl()
    {
        return $this->getModelUrl("msp/standard/redirect");
    }

    /**
     * Get the payment object and set the right config values
     */
    public function getPayment($storeId = null)
    {
        $payment = Mage::getSingleton("msp/payment");

        // Get store id
        if (!$storeId) {
            // $storeId = $this->getStore();
            $storeId = Mage::app()->getStore()->getStoreId();
        }

        $orderId = Mage::app()->getRequest()->getQuery('transactionid');

        if ($orderId) {
            $storeId = Mage::getSingleton('sales/order')->loadByIncrementId($orderId)->getStoreId();
        }

        // Basic settings
        $configSettings = array();
        if ($this->_loadSettingsConfig) {
            $configSettings = Mage::getStoreConfig($this->_settings . "/settings", $storeId);
        }

        // Load gateway specific config and merge
        $configGateway = array();
        if ($this->_loadGatewayConfig) {
            $configGateway = Mage::getStoreConfig($this->_module . "/" . $this->_code, $storeId);
        }

        // Merge
        $config = array_merge($configSettings, $configGateway);

        // Payment
        $payment->setConfigObject($config);
        $payment->setNotificationUrl($this->getNotificationUrl());
        $payment->setReturnUrl($this->getReturnUrl());
        $payment->setCancelUrl($this->getCancelUrl());
        $payment->setGateway($this->getGateway());
        $payment->setMyBankIssuer($this->getMyBankIssuer());
        return $payment;
    }

    /**
     * Start fco xml transaction transaction
     */
    public function startPayAfterTransaction()
    {
        // Pass store (from this getLastOrderId) to the getPayment?
        $payment = $this->getPayment();

        return $payment->startPayAfterTransaction();
    }

    /**
     * Start a transaction
     */
    public function startTransaction()
    {
        // Pass store (from this getLastOrderId) to the getPayment?
        $payment = $this->getPayment();

        return $payment->startTransaction();
    }

    /**
     * Notification
     *
     * @param $id integer|string
     * @return mixed
     */
    public function notification($id)
    {
        /** @var $order Mage_Sales_Model_Order */
        $order = Mage::getSingleton('sales/order')->loadByIncrementId($id);

        /** @var $payment MultiSafepay_Msp_Model_Payment */
        $payment = $this->getPayment($order->getStore());

        return $payment->notification($id);
    }

    /**
     * @return mixed
     */
    public function getIssuersHTML($gateway = '')
    {
        $storeId = Mage::app()->getStore()->getStoreId();
        $configSettings = array();
        if ($this->_loadSettingsConfig) {
            $configSettings = Mage::getStoreConfig($this->_settings . '/settings', $storeId);
        }

        $msp = new Client();
        $msp->setTestMode($configSettings['test_api'] === 'test');
        $msp->setApiKey($configSettings['api_key']);

        return $msp->issuers->get('issuers', $gateway);
    }

    /**
     * Notification URL of the model
     */
    public function getNotificationUrl()
    {
        return $this->getModelUrl("msp/standard/notification");
    }

    /**
     * Return URL of the model
     */
    public function getReturnUrl()
    {
        return Mage::getUrl("msp/standard/return", array("_secure" => true));
    }

    /**
     * Cancel URL of the model
     */
    public function getCancelUrl()
    {
        return Mage::getUrl("msp/standard/cancel", array("_secure" => true));
    }

    /**
     * Selected 'gateway'
     */
    public function getGateway()
    {
        return $this->_gateway;
    }

    public function getMyBankIssuer()
    {
        return $this->_mybankissuer;
    }

    /**
     * Pass params to the model
     */
    public function setParams($params)
    {
        $this->_params = $params;
    }

    /**
     * Get config data
     */
    public function getConfigData($field, $storeId = null)
    {
        if (null === $storeId) {
            // $storeId = Mage::app()->getStore()->getStoreId();//$this->getStore();
            $storeId = $this->getStore();
        }
        $path = $this->_module . "/" . $this->_code . '/' . $field;

        return Mage::getStoreConfig($path, $storeId);
    }

    public function refund(Varien_Object $payment, $amount)
    {
        $order = $payment->getOrder();

        /** @var MultiSafepay_Msp_Model_Gateway_Abstract $payment */
        $payment = $order->getPayment()->getMethodInstance();

        $data = Mage::app()->getRequest()->getPost('creditmemo');

        if (isset($data['servicecost'])) {
            $refunded_servicecost = $data['servicecost'];
            if ($refunded_servicecost != $order->getServicecost()) {
                $amount = $amount - $order->getServicecost() + $refunded_servicecost;
            }
        }

        switch ($payment->getCode()) {
            // MSP - Fast Checkout
            case self::MSP_FASTCHECKOUT_CODE:
                $settingsPathPrefix = 'mspcheckout/settings';
                break;

            // General (Main settings in the 'Payment Methods' tab
            case self::MSP_GENERAL_CODE:
                $settingsPathPrefix = 'payment/msp';
                break;

            // MSP - Gateways (Pay After Delivery)
            case self::MSP_GENERAL_PAD_CODE:
                $settingsPathPrefix = 'msp_gateways/' . self::MSP_GENERAL_PAD_CODE;
                break;
            case self::MSP_GENERAL_PAD_INSTALLMENTS_CODE:
                $settingsPathPrefix = 'msp_gateways/' . self::MSP_GENERAL_PAD_INSTALLMENTS_CODE;
                break;
            case self::MSP_GENERAL_KLARNA_CODE:
                $settingsPathPrefix = 'msp_gateways/' . self::MSP_GENERAL_KLARNA_CODE;
                break;
            case self::MSP_GENERAL_EINVOICE_CODE:
                $settingsPathPrefix = 'msp_gateways/' . self::MSP_GENERAL_EINVOICE_CODE;
                break;

            // MSP - Gateways
            default:
                $settingsPathPrefix = 'msp/settings';
                break;
        }

        $config = Mage::getStoreConfig($settingsPathPrefix, $order->getStoreId());

        $isBillingSuite = in_array(
            $payment->getCode(),
            array(
                self::MSP_GENERAL_PAD_CODE,
                self::MSP_GENERAL_PAD_INSTALLMENTS_CODE,
                self::MSP_GENERAL_KLARNA_CODE,
                self::MSP_GENERAL_EINVOICE_CODE,
                self::MSP_GENERAL_AFTERPAY_CODE,
                self::MSP_GENERAL_IN3_CODE,
                self::MSP_GENERAL_ZINIA_CODE)
        );

        // Use refund by Credit Memo is enabled
        $pathCreditMemoIsEnabled = $isBillingSuite ? 'msp/settings' : $settingsPathPrefix;
        if (!Mage::getStoreConfigFlag($pathCreditMemoIsEnabled . '/use_refund_credit_memo', $order->getStoreId())) {
            Mage::getSingleton('adminhtml/session')->addNotice(Mage::helper('msp')->__('Refund has not been send to MultiSafepay. You need to refund manually at MultiSafepay. Please check if the creditmemo option is configured within the MultiSafepay payment methods configuration!'));
            return $this;
        }

        // Check payment method is from MultiSafepayment
        if (!in_array($payment->getCode(), $this->availablePaymentMethodCodes)) {
            Mage::getSingleton('adminhtml/session')->addNotice(Mage::helper('msp')->__('Refund has not been send to MultiSafepay. Looks like a non MultiSafepay payment method was selected'));
            return $this;
        }

        // Prevent zero amount refunds (full refund)
        if ($amount <= 0) {
            return $this;
        }

        // Get account data from correct gateway settings for pad klarna and coupons.
        if (isset($config['test_api_pad'])) {
            if ($config['test_api_pad'] == 'test') {
                $config['test_api'] = 'test';
                $config['api_key'] = $config['api_key_pad_test'];
            } else {
                $config['api_key'] = $config['api_key_pad'];
            }
        }
        $msp = new Client();
        $msp->setTestMode($config['test_api'] === 'test');
        $msp->setApiKey($config['api_key']);

        // This is a BillingSuite refund so we need to update the checkout data. We will be using the JSON API instead
        if ($isBillingSuite || $payment->requiresShoppingCart()) {
            $msporder = $msp->orders->get($type = 'orders', $order->getIncrementId(), $body = array(), $query_string = false);
            $originalCart = $msporder->shopping_cart;

            $refundData = array();

            foreach ($originalCart->items as $key => $item) {
                if ($item->unit_price > 0) {
                    $refundData['checkout_data']['items'][] = $item;
                }

                foreach ($order->getCreditmemosCollection() as $creditmemo) {
                    foreach ($creditmemo->getAllItems() as $product) {
                        $product_id = $product->getData('order_item_id');

                        if ($product_id == $item->merchant_item_id) {
                            $qty_refunded = $product->getData('qty');
                            if ($qty_refunded > 0) {
                                if ($item->unit_price > 0) {
                                    $refundItem = new stdClass();
                                    $refundItem->name = $item->name;
                                    $refundItem->description = $item->description;
                                    $refundItem->unit_price = '-' . $item->unit_price;
                                    $refundItem->quantity = round($qty_refunded);
                                    $refundItem->merchant_item_id = $item->merchant_item_id;
                                    $refundItem->tax_table_selector = $item->tax_table_selector;
                                    $refundData['checkout_data']['items'][] = $refundItem;
                                }
                            }
                        }
                    }
                }

                foreach ($data['items'] as $productid => $proddata) {
                    if ($item->merchant_item_id == $productid) {
                        if ($proddata['qty'] > 0) {
                            $refundItem = (object) array();
                            $refundItem->name = $item->name;
                            $refundItem->description = $item->description;
                            $refundItem->unit_price = '-' . $item->unit_price;
                            $refundItem->quantity = round($proddata['qty']);
                            $refundItem->merchant_item_id = $item->merchant_item_id;
                            $refundItem->tax_table_selector = $item->tax_table_selector;
                            $refundData['checkout_data']['items'][] = $refundItem;
                        }
                    }
                }

                // The complete shipping cost is refunded also, so we can remove it from the checkout data and refund it
                if ($item->merchant_item_id == 'msp-shipping') {
                    if ($data['shipping_amount'] == $order->getShippingAmount()
                        || (Mage::getSingleton('tax/config')->displaySalesShippingInclTax($order->getStoreId())
                        && $data['shipping_amount'] == $order->getShippingInclTax())) {
                        $refundItem = (object) array();
                        $refundItem->name = $item->name;
                        $refundItem->description = $item->description;
                        $refundItem->unit_price = '-' . $item->unit_price;
                        $refundItem->quantity = '1';
                        $refundItem->merchant_item_id = $item->merchant_item_id;
                        $refundItem->tax_table_selector = $item->tax_table_selector;
                        $refundData['checkout_data']['items'][] = $refundItem;
                    } else {
                        if ($data['shipping_amount'] != 0) {
                            Mage::getSingleton('adminhtml/session')->addError('MultiSafepay: Refund not processed online as it did not match the complete shipping cost');
                            $order->addStatusHistoryComment('MultiSafepay: Refund not processed online as it did not match the complete shipping cost', false);
                            $order->save();
                            return $this;
                        }
                    }
                }
                if ($item->name == $order->getShippingDescription() && $item->unit_price < 0) {
                    $refundItem = (object) array();
                    $refundItem->name = $item->name;
                    $refundItem->description = $item->description;
                    $refundItem->unit_price = $item->unit_price;
                    $refundItem->quantity = '1';
                    $refundItem->merchant_item_id = $item->merchant_item_id;
                    $refundItem->tax_table_selector = $item->tax_table_selector;
                    $refundData['checkout_data']['items'][] = $refundItem;
                }
            }

            $endpoint = 'orders/' . $order->getIncrementId() . '/refunds';
            try {
                $mspreturn = $msp->orders->post($refundData, $endpoint);
                Mage::log($mspreturn, null, 'MultiSafepay-Refunds.log');
                Mage::getSingleton('adminhtml/session')->addNotice(Mage::helper('msp')->__('Refund request has been sent successfully to MultiSafepay, your transaction has been refunded.'));
            } catch (Exception $e) {
                Mage::log($e->getMessage(), null, 'MultiSafepay-Refunds.log');
                Mage::log($refundData, null, 'MultiSafepay-Refunds.log');

                Mage::getSingleton('adminhtml/session')->addError('Online processing of the refund failed, reason: ' . $e->getMessage());
                $order->addStatusHistoryComment('Online processing of the refund failed, reason: ' . $e->getMessage(), false);
                $order->save();
            }
            return $this;
        }

        if (isset($config['custom_refund_desc']) && $config['custom_refund_desc'] !== '') {
            $refundData['description'] = str_replace(['{{order.increment_id}}'], [$order->getIncrementId()], $config['custom_refund_desc']);
        }

        $endpoint = 'orders/' . $order->getIncrementId() . '/refunds';
        $refundData['amount'] = $amount * 100; // $order->getGrandTotal() * 100;
        $refundData['currency'] = Mage::app()->getStore()->getCurrentCurrencyCode();

        Mage::log($refundData, null, 'MultiSafepay-Refunds.log');

        try {
            $response = $msp->orders->post($refundData, $endpoint);
            Mage::log($response, null, 'MultiSafepay-Refunds.log');
            Mage::getSingleton('adminhtml/session')->addNotice(Mage::helper('msp')->__('Refund request has been sent successfully to MultiSafepay, your transaction has been refunded.'));
        } catch (Exception $exception) {
            Mage::log($exception->getMessage(), null, 'MultiSafepay-Refunds.log');
            Mage::getSingleton('adminhtml/session')->addError($exception->getMessage());
            $order->addStatusHistoryComment('Online processing of the refund failed<br/>' .
                'Error: ' . $exception->getMessage(), false);
        }

        return $this;
    }
}
