<?php

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

class MultiSafepay_Msp_Model_Api_Paylink
{
    public $test = false;
    public $custom_api;
    public $extrapublics = '';
    public $use_shipping_xml;
    public $use_shipping_notification = false;
    // Merchant data
    public $merchant = array(
        'api_key' => '',
    );
    // Transaction data
    public $transaction = array(
        'id' => '',
        'currency' => '',
        'amount' => '',
        'days_active' => '',
        "gateway_reset" => ''
    );
    public $signature;
    public $api_url;
    public $request_xml;
    public $reply_xml;
    public $payment_url;
    public $status;
    public $error_code;
    public $error;
    public $debug;
    public $parsed_xml;
    public $parsed_root;
    protected $_logFileName = 'msp_paylink.log';
    public $availablePaymentMethodCodes = array(
        'msp' => '',
        'msp_ideal' => 'IDEAL',
        'msp_dotpay' => 'DOTPAY',
        //'msp_in3', for now we dont allow iDEAL+in3 manual transaction requests
        //'msp_zinia', for now we dont allow zinia manual transaction requests
        //'msp_afterpay', for now we dont allow afterpay manual transaction requests
        //'msp_payafter', for now we dont allow payafter manual transaction requests
        'msp_einvoice' => 'EINVOICE',
        'msp_mistercash' => 'MISTERCASH',
        'msp_visa' => 'VISA',
        'msp_paysafecard' => 'PSAFECARD',
        'msp_eps' => 'EPS',
        'msp_ing' => 'INGHOME',
        'msp_cbc' => 'CBC',
        'msp_kbc' => 'KBC',
        'msp_belfius' => 'Belfius',
        'msp_idealqr' => 'IDEALQR',
        'msp_ferbuy' => 'FERBUY',
        'msp_mastercard' => 'MASTERCARD',
        'msp_mybank' => 'MYBANK',
        'msp_banktransfer' => 'BANKTRANS',
        'msp_maestro' => 'MAESTRO',
        'msp_paypal' => 'PAYPAL',
        'msp_webgift' => 'WEBSHOPGIFTCARD',
        'msp_ebon' => 'EBON',
        'msp_babygiftcard' => 'BABYGIFTCARD',
        'msp_boekenbon' => 'BOEKENBON',
        'msp_erotiekbon' => 'EROTIEKBON',
        'msp_givacard' => 'GIVACARD',
        'msp_parfumnl' => 'PARFUMNL',
        'msp_parfumcadeaukaart' => 'PARFUMCADEAUKAART',
        'msp_degrotespeelgoedwinkel' => 'DEGROTESPEELGOEDWINKEL',
        'msp_giropay' => 'GIROPAY',
        'msp_multisafepay' => 'WALLET',
        'msp_directebanking' => 'DIRECTBANK',
        'msp_directdebit' => 'DIRDEB',
        'msp_amazonpay' => 'AMAZONBTN',
        'msp_amex' => 'AMEX',
        'msp_alipayplus' => 'ALIPAYPLUS',
        'msp_billink' => 'BILLINK',
        'msp_bizum' => 'BIZUM',
        'msp_yourgift',
        'msp_wijncadeau',
        'msp_lief',
        'msp_gezondheidsbon',
        'msp_fashioncheque',
        'msp_fashiongiftcard',
        'msp_podium',
        'msp_vvvgiftcard',
        'msp_sportenfit',
        'msp_beautyandwellness',
        'msp_trustly' => 'TRUSTLY',
        'msp_applepay' => 'APPLEPAY',
        'msp_directbanktransfer' => 'DBRTP',
        'msp_good4fun' => 'GOOD4FUN',
    );

    /**
     * Starts a transaction and returns the payment url
     *
     * @return string
     */
    public function getPaymentLink($order)
    {
        $this->log('Request payment link for manual order');

        $this->checkSettings();

        $this->order = $order;

        /** @var MultiSafepay_Msp_Model_Gateway_Abstract $payment */
        $payment = $this->order->getPayment()->getMethodInstance();
        $pm_code = $payment->getCode();
        $storename = strtok($this->order->getStoreName(), "\n"); // Mage::app()->getStore()->getName();
        $billing = $this->order->getBillingAddress();
        $shipping = $this->order->getShippingAddress();

        $items = "<ul>\n";
        foreach ($this->order->getAllVisibleItems() as $item) {
            $items .= "<li>" . ($item->getQtyOrdered() * 1) . " x : " . $item->getName() . "</li>\n";
        }
        $items .= "</ul>\n";

        // Build request
        $this->mapi = new MultiSafepay();
        $this->mapi->plugin_name = 'Magento';
        $this->mapi->version = Mage::getConfig()->getNode('modules/MultiSafepay_Msp/version');
        $this->mapi->use_shipping_notification = false;
        $this->mapi->merchant['api_key'] = $this->merchant['api_key'];

        $this->mapi->test = $this->test;
        $this->mapi->merchant['notification_url'] = Mage::getUrl("msp/standard/notification", array("_secure" => true, "_store" => $this->order->getStoreId())) . '&type=initial';
        $this->mapi->merchant['cancel_url'] = Mage::getUrl("msp/standard/cancel", array("_secure" => true, "_store" => $this->order->getStoreId()));
        $this->mapi->merchant['redirect_url'] = Mage::getUrl("msp/standard/return", array("_secure" => true, "_store" => $this->order->getStoreId()));

        $this->mapi->parseCustomerAddress($billing->getStreet(1));

        if ($this->mapi->customer['housenumber'] == '') {
            $this->mapi->customer['housenumber'] = $billing->getStreet(2);
            $this->mapi->customer['address1'] = $billing->getStreet(1);
        }

        if ($billing->getStreet(3) != '') {
            $this->mapi->customer['housenumber'] .= ' ' . $billing->getStreet(3);
        }

        $locale = Mage::getStoreConfig('general/locale/code', $this->order->getStoreId());

        $this->mapi->customer['locale'] = $locale; // Mage::app()->getLocale()->getLocaleCode(); // Mage::app()->getLocale()->getDefaultLocale();
        $this->mapi->customer['firstname'] = $billing->getFirstname();
        $this->mapi->customer['lastname'] = $billing->getLastname();
        $this->mapi->customer['zipcode'] = $billing->getPostcode();
        $this->mapi->customer['city'] = $billing->getCity();
        $this->mapi->customer['state'] = $billing->getState();
        $this->mapi->customer['country'] = $billing->getCountry();
        $this->mapi->customer['phone'] = $billing->getTelephone();
        $this->mapi->customer['email'] = $this->order->getCustomerEmail();
        $this->mapi->customer['ipaddress'] = $_SERVER['REMOTE_ADDR'];
        $this->mapi->transaction['id'] = $this->transaction['id'];
        $this->mapi->transaction['amount'] = $this->transaction['amount'];
        $this->mapi->transaction['currency'] = $this->transaction['currency'];
        $this->mapi->transaction['var3'] = Mage::app()->getStore()->getStoreId();
        $this->mapi->transaction['description'] = 'Order #' . $this->transaction['id'] . ' at ' . $storename;

        if ($this->transaction['gateway_reset']) {
            $this->mapi->transaction['gateway'] = '';
        } elseif (isset($this->availablePaymentMethodCodes[$pm_code])) {
            $this->mapi->transaction['gateway'] = $this->availablePaymentMethodCodes[$pm_code];
        } else {
            $this->mapi->transaction['gateway'] = $payment->getGateway();
        }
        $this->mapi->transaction['items'] = $items;

        $mainConfig = Mage::getStoreConfig('msp/settings', $order->getStoreId());
        $config = Mage::getStoreConfig('msp_gateways/msp_' . strtolower($this->mapi->transaction['gateway']), Mage::app()->getStore()->getId());
        $this->mapi->transaction['daysactive'] = isset($config['pad_daysactive']) ?$config['pad_daysactive'] :$mainConfig['daysactive'];
        $this->mapi->transaction['secondsactive'] = isset($config['pad_seconds_active']) ? $config['pad_seconds_active'] : $mainConfig['seconds_active'];

        // Fill shoppingcart (for now only for einvoice)
        if (in_array($this->mapi->transaction['gateway'], array ('EINVOICE'))) {
            $this->mapi->gatewayinfo['bankaccount'] = '';
            $this->mapi->gatewayinfo['email'] = $this->order->getCustomerEmail();
            $this->mapi->gatewayinfo['phone'] = $billing->getTelephone();

            // Set Gender
            switch ($this->order->getCustomerGender()) {
                case 0:
                    $gender = 'male';
                    break;
                case 1:
                    $gender = 'female';
                    break;
                default:
                    $gender = '';
                    break;
            }
            $this->mapi->customer['gender']    = $gender;
            $this->mapi->gatewayinfo['gender'] = $gender;

            // Birthday
            $birthday = Mage::getModel('core/date')->date('d-m-Y', strtotime($this->order->getCustomerDob()));
            $this->mapi->gatewayinfo['birthday'] = $birthday;
            $this->mapi->customer['birthday'] = $birthday;

            $this->mapi->setDefaultTaxZones();

            // Currency check
            $isAllowConvert = Mage::getStoreConfigFlag('msp/settings/allow_convert_currency');
            $currencies = explode(',', $config['allowed_currency']);
            $canUseCurrentCurrency = in_array(Mage::app()->getStore()->getCurrentCurrencyCode(), $currencies);

            $currentCurrencyCode = Mage::app()->getStore()->getCurrentCurrencyCode();
            $baseCurrencyCode = Mage::app()->getBaseCurrencyCode();

            if ($order->getGlobalCurrencyCode() == 'EUR' && $isAllowConvert) {
                $currencyCode = 'EUR';
            } elseif ($canUseCurrentCurrency) {
                $currencyCode = $currentCurrencyCode;
            } elseif ($isAllowConvert) {
                $currencyCode = MultiSafepay_Msp_Helper_Data::CONVERT_TO_CURRENCY_CODE;
            } else {
                $currencyCode = $baseCurrencyCode;
            }

            $this->getItems($this->order, $currencyCode);

            $discountAmount = $this->_convertCurrency($this->order->getData('base_discount_amount'), $baseCurrencyCode, $currencyCode);
            $discountAmountFinal = number_format($discountAmount, 4, '.', '');

            // Add discount line item
            if ($discountAmountFinal != 0) {
                $c_item = new MspItem('Discount', 'Discount', 1, $discountAmountFinal, 'KG', 0); // Todo adjust the amount to cents, and round it up.
                $c_item->SetMerchantItemId('Discount');
                $c_item->SetTaxTableSelector('BTW0');
                $this->mapi->cart->AddItem($c_item);
            }

            $taxClass = $config['fee_tax_class'];

            if ($taxClass == 0) {
                $this->_rate = 1;
            }

            $taxCalculationModel = Mage::getSingleton('tax/calculation');
            $request = $taxCalculationModel->getRateRequest(
                $order->getShippingAddress(),
                $order->getBillingAddress(),
                $order->getCustomerTaxClassId(),
                Mage::app()->getStore()->getId()
            );
            $request->setStore(Mage::app()->getStore())->setProductClassId($taxClass);

            $rate = $taxCalculationModel->getRate($request);
            $bigRate = 100 + $rate;
            $feeRate = $rate / 100;

            if ($feeRate == 0) {
                $feeRate = '0.00';
            }

            $table = new MspAlternateTaxTable();
            $table->name = 'FEE';
            $rule = new MspAlternateTaxRule($feeRate);
            $table->AddAlternateTaxRules($rule);
            $this->mapi->cart->AddAlternateTaxTables($table);

            $total_fee = 0;
            $fee = $config['fee_amount'];
            $fee_array = explode(':', $fee);

            // Fee is not configured
            if ($fee_array[0] != '') {
                $fixed_fee = str_replace(',', '.', $fee_array[0]);

                // Check for configured percentage value
                if (!empty($fee_array[1])) {
                    $fee_array[1] = str_replace(',', '.', $fee_array[1]);
                    $serviceCostPercentage = str_replace('%', '', $fee_array[1]);
                    // If the service cost is added, then first remove it before calcualting the fee
                    if ($order->getBaseServicecost()) {
                        $fee_percentage = ($order->getBaseGrandTotal() - $order->getBaseServicecost()) * ($serviceCostPercentage / 100);
                    } else {
                        $fee_percentage = $order->getBaseGrandTotal() * ($serviceCostPercentage / 100);
                    }
                    $total_fee += $fee_percentage;
                }
                $total_fee += $fixed_fee;
                $fee = $total_fee;
                $tax = ($fee / $bigRate) * $rate;
                $fee = $fee - $tax;

                // Add pay after delivery fee if enabled
                if ($config['fee']) {
                    // Todo adjust the amount to cents, and round it up.
                    $c_item = new MspItem('Fee', 'Fee', 1, $fee, 'KG', 0);
                    $c_item->SetMerchantItemId('payment-fee');
                    $c_item->SetTaxTableSelector('FEE');
                    $this->mapi->cart->AddItem($c_item);
                }
            }

            // Add none taxtable
            $table = new MspAlternateTaxTable();
            $table->name = 'none';
            $rule = new MspAlternateTaxRule('0.00');
            $table->AddAlternateTaxRules($rule);
            $this->mapi->cart->AddAlternateTaxTables($table);

            // Add shipping line item
            $title = $this->order->getShippingDescription();

            // Code blow added to recalculate excluding tax for the shipping cost.
            // Older Magento installations round differently, causing a 1 cent mismatch.
            // This is why we recalculate it.
            $diff = $this->order->getShippingInclTax() - $this->order->getShippingAmount();

            if ($this->order->getShippingAmount() > 0) {
                $cost = ($diff / $this->order->getShippingAmount()) * 100;
            } else {
                $cost = $diff * 100;
            }

            $shipping_percentage = 1 + round($cost, 0) / 100;
            $shippin_exc_tac_calculated = $this->order->getShippingInclTax() / $shipping_percentage;
            $percentage = round($cost, 0) / 100;
            $price = number_format($this->_convertCurrency($shippin_exc_tac_calculated, $currentCurrencyCode, $currencyCode), 10, '.', '');

            $table = new MspAlternateTaxTable();
            $table->name = $percentage;
            $rule = new MspAlternateTaxRule($percentage);
            $table->AddAlternateTaxRules($rule);
            $this->mapi->cart->AddAlternateTaxTables($table);

            $c_item = new MspItem($title, 'Shipping', 1, $price, 'KG', 0);
            $c_item->SetMerchantItemId('msp-shipping');
            $c_item->SetTaxTableSelector($percentage);
            $this->mapi->cart->AddItem($c_item);

            $this->getTaxes();
        }

        if (!in_array($this->mapi->transaction['gateway'], array('EINVOICE'))) {
            $url = $this->mapi->startJSONTransaction('redirect');
        } else {
            $url = $this->mapi->startJSONCheckout();
        }

        if ($this->mapi->error) {
            return array(
                'error' => true,
                'code' => $this->mapi->error_code,
                'description' => $this->mapi->error
            );
        }

        return array('error' => false, 'url' => $url);
    }

    protected function getTaxes()
    {
        $this->_getTaxTable($this->_getShippingTaxRules(), 'default');
        $this->_getTaxTable($this->_getTaxRules(), 'alternate');
        $this->_getTaxTable($this->_getShippingTaxRules(), 'alternate');
        // Add 'none' group?
    }

    protected function _getTaxTable($rules, $type)
    {
        if (is_array($rules)) {
            foreach ($rules as $group => $taxRates) {
                if ($type != 'default') {
                    $table = new MspAlternateTaxTable($group, 'true');
                    $shippingTaxed = 'false';
                } else {
                    $shippingTaxed = 'true';
                }

                if (is_array($taxRates)) {
                    foreach ($taxRates as $rate) {
                        if ($type != 'default') {
                            $rule = new MspAlternateTaxRule($rate['value']);
                            $rule->AddPostalArea($rate['country']);
                            $table->AddAlternateTaxRules($rule);
                        } else {
                            $rule = new MspDefaultTaxRule($rate['value'], $shippingTaxed);
                            $rule->AddPostalArea($rate['country']);
                            $this->mapi->cart->AddDefaultTaxRules($rule);
                        }
                    }
                } else {
                    $taxRate = $taxRates / 100;
                    if ($type != 'default') {
                        $rule = new MspAlternateTaxRule($taxRate);
                        $rule->SetWorldArea();

                        $table->AddAlternateTaxRules($rule);
                    } else {
                        $rule = new MspDefaultTaxRule($taxRate, $shippingTaxed);
                        $rule->SetWorldArea();
                        $this->mapi->cart->AddDefaultTaxRules($rule);
                    }
                }
                if ($type != 'default') {
                    $this->mapi->cart->AddAlternateTaxTables($table);
                }
            }
        } else {
            if (is_numeric($rules)) {
                $taxRate = $rules / 100;
                if ($type != 'default') {
                    $table = new MspAlternateTaxTable();
                    $rule = new MspAlternateTaxRule($taxRate);
                    $rule->SetWorldArea();
                    $table->AddAlternateTaxRules($rule);
                    $this->mapi->cart->AddAlternateTaxTables($table);
                } else {
                    $rule = new MspDefaultTaxRule($taxRate, 'true');
                    $rule->SetWorldArea();
                    $this->mapi->cart->AddDefaultTaxRules($rule);
                }
            }
        }
    }

    protected function _getTaxRules()
    {
        $customerTaxClass = $this->_getCustomerTaxClass();
        if (Mage::helper('tax')->getTaxBasedOn() == 'origin') {
            $request = Mage::getSingleton('tax/calculation')->getRateRequest();
            return Mage::getSingleton('tax/calculation')->getRatesForAllProductTaxClasses($request->setCustomerClassId($customerTaxClass));
        } else {
            $customerRules = Mage::getSingleton('tax/calculation')->getRatesByCustomerTaxClass($customerTaxClass);
            $rules = array();
            foreach ($customerRules as $rule) {
                $rules[$rule['product_class']][] = $rule;
            }

            return $rules;
        }
    }

    protected function _getShippingTaxRules()
    {
        $customerTaxClass = $this->_getCustomerTaxClass();

        // Validate the returned data. Doesn't work with connect pad
        if ($shippingTaxClass = Mage::getStoreConfig(Mage_Tax_Model_Config::CONFIG_XML_PATH_SHIPPING_TAX_CLASS, $this->order->getStoreId())) {
            if (Mage::helper('tax')->getTaxBasedOn() == 'origin') {
                $request = Mage::getSingleton('tax/calculation')->getRateRequest();
                $request->setCustomerClassId($customerTaxClass)->setProductClassId($shippingTaxClass);
                return Mage::getSingleton('tax/calculation')->getRate($request);
            }
            $customerRules = Mage::getSingleton('tax/calculation')->getRatesByCustomerAndProductTaxClasses($customerTaxClass, $shippingTaxClass);
            $rules = array();
            foreach ($customerRules as $rule) {
                $rules[$rule['product_class']][] = $rule;
            }

            return $rules;
        }

        return array();
    }

    protected function _getCustomerTaxClass()
    {
        $customerGroup = $this->order->getCustomerGroupId();
        if (!$customerGroup) {
            $customerGroup = Mage::getStoreConfig('customer/create_account/default_group', $this->order->getStoreId());
        }

        return Mage::getModel('customer/group')->load($customerGroup)->getTaxClassId();
    }

    protected function getItems($order, $targetCurrencyCode)
    {
        $items = $order->getAllItems();

        foreach ($items as $item) {
            $product_id = $item->getProductId();
            foreach ($order->getAllItems() as $order_item) {
                $order_product_id = $order_item->getProductId();
                if ($order_product_id == $product_id) {
                    $quantity = $item->getQtyOrdered();
                }
            }

            if ($item->getParentItem()) {
                continue;
            }
            $taxClass = ($item->getTaxPercent() == 0 ? 'none' : $item->getTaxPercent());
            $rate = $item->getTaxPercent() / 100;

            $table = new MspAlternateTaxTable();
            $table->name = $item->getTaxPercent();
            $rule = new MspAlternateTaxRule($rate);
            $table->AddAlternateTaxRules($rule);
            $this->mapi->cart->AddAlternateTaxTables($table);

            $product_id = $item->getProductId();

            // Name and options
            $itemName = $item->getName();

            $proddata = Mage::getModel('catalog/product')->load($product_id);
            $currentCurrencyCode = Mage::app()->getStore()->getCurrentCurrencyCode();

            $ndata = $item->getData();

            $rounding = 10;
            if ($ndata['price'] != 0) {
                $price = number_format($this->_convertCurrency($ndata['price'], $currentCurrencyCode, $targetCurrencyCode), $rounding, '.', '');

                $tierprices = $proddata->getTierPrice();
                if (count($tierprices) > 0) {
                    $product_tier_prices = (object) $tierprices;
                    $product_price = array();
                    foreach ($product_tier_prices as $key => $value) {
                        $value = (object) $value;
                        if ($item->getQtyOrdered() >= $value->price_qty) {
                            if ($ndata['price'] < $value->price) {
                                $price = $ndata['price'];
                            } else {
                                $price = $value->price;
                            }
                        }
                        $price = number_format($this->_convertCurrency($price, $currentCurrencyCode, $targetCurrencyCode), $rounding, '.', '');
                    }
                }

                // Fix for 1027 with catalog prices including tax
                if (Mage::getStoreConfig('tax/calculation/price_includes_tax')) {
                    $price = ($item->getRowTotalInclTax() / $item->getQtyOrdered() / (1 + ($item->getTaxPercent() / 100)));
                    $price = round($price, $rounding);
                }

                // Create item
                $c_item = new MspItem($itemName, $item->getDescription(), $quantity, $price, 'KG', $item->getWeight());
                $c_item->SetMerchantItemId($item->getId());
                $c_item->SetTaxTableSelector($taxClass);
                $this->mapi->cart->AddItem($c_item);
            }
        }
    }

    /**
     * @param float  $amount
     * @param string $currentCurrencyCode
     * @param string $targetCurrencyCode
     * @return float
     */
    protected function _convertCurrency($amount, $currentCurrencyCode, $targetCurrencyCode)
    {
        if ($currentCurrencyCode == $targetCurrencyCode) {
            return $amount;
        }

        $currentCurrency = Mage::getModel('directory/currency')->load($currentCurrencyCode);
        $rateCurrentToTarget = $currentCurrency->getAnyRate($targetCurrencyCode);

        if ($rateCurrentToTarget === false) {
            Mage::throwException(Mage::helper("msp")->__("Imposible convert %s to %s", $currentCurrencyCode, $targetCurrencyCode));
        }

        $revertCheckingCode = Mage::getModel('directory/currency')->load($targetCurrencyCode);
        $revertCheckingRate = $revertCheckingCode->getAnyRate($currentCurrencyCode);
        $rateCurrentToTarget = 1 / $revertCheckingRate;

        return round($amount * $rateCurrentToTarget, 2);
    }

    /**
     * Check the settings before using them
     *
     * @return void
     */
    public function checkSettings()
    {
        $this->merchant['api_key'] = trim($this->merchant['api_key']);
    }

    /**
     * Check if a certain MultiSafepay status is already in the order history (to prevent doubles)
     */
    public function isPaymentLinkCreated($order)
    {
        $history = $order->getAllStatusHistory();
        foreach ($history as $status) {
            if (strpos($status->getComment(), 'Manual Payment link') !== false) {
                return true;
            }
        }
        return false;
    }

    /**
     * Logging functions
     *
     * @return mixed
     */
    public function isDebug()
    {
        return $this->getConfigData('debug');
    }

    /**
     * @return void
     */
    public function log()
    {
        $argv = func_get_args();
        $data = array_shift($argv);

        if (is_string($data)) {
            $logData = @vsprintf($data, $argv);

            // If vsprintf failed, just use the data
            if (!$logData) {
                $logData = $data;
            }
        } else {
            $logData = $data;
        }

        if ($this->debug) {
            Mage::log($logData, null, $this->_logFileName);
        }
    }
}
