<?php
/**
 * 2007-2019 PrestaShop SA and Contributors.
 *
 * 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:
 * https://opensource.org/licenses/AFL-3.0
 * 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-2019 PrestaShop SA and Contributors
 * @license   https://opensource.org/licenses/AFL-3.0  Academic Free License (AFL 3.0)
 * International Registered Trademark & Property of PrestaShop SA
 */

use Sibs\DB\SibsMigration;
use Sibs\Models\PrestashopAddress;
use Sibs\Models\SibsTransaction;
use Sibs\SibsConstants;
use Sibs\SibsException;
use Sibs\SibsLogger;
use Sibs\SibsPaymentCore;
use Sibs\SibsUtils;

/**
 * @property Sibs $module
 */
class SibsPaymentAbstractModuleFrontController extends ModuleFrontController
{
    /**
     * Payment Method.
     *
     * @var string
     */
    protected $payment_method = '';

    /**
     * Template Name.
     *
     * @var string
     */
    protected $template_name  = '';

    /**
     * Payment Type.
     *
     * @var string
     */
    protected $payment_type   = '';

    /**
     * Payment Brand.
     *
     * @var string
     */
    protected $payment_brand  = '';

    /**
     * Custumer ID.
     *
     * @var string
     */
    protected $id_customer    = 'id_customer';

    /**
     * SSL.
     *
     * @var bool
     */
    public $ssl               = true;

    /**
     * Table Prefix.
     *
     * @var string
     */
    public static $prefix     = _DB_PREFIX_;

    /**
     * Set Payment Method.
     *
     * @param string $paymentMethod
     * @return void
     */
    public function setPaymentMethod($paymentMethod)
    {
        $this->payment_method = $paymentMethod;
    }

    /**
     * Get Payment Brand Cards.
     *
     * @return string
     */
    public function getPaymentBrandCards()
    {
        $brand = Configuration::get("SIBS_{$this->getPaymentMethod()}_CARDS");

        return str_replace(',', ' ', $brand);
    }

    /**
     * Get Payment Method.
     *
     * @return string
     */
    public function getPaymentMethod()
    {
        return $this->payment_method;
    }

    /**
     * Get Template Name.
     *
     * @return string
     */
    public function getTemplateName()
    {
        return "module:sibs/views/templates/front/{$this->template_name}";
    }

    /**
     * Get Payment Type.
     *
     * @return string
     */
    public function getPaymentType()
    {
        return $this->payment_type;
    }

    /**
     * Get Payment Brand.
     *
     * @return string
     */
    public function getPaymentBrand()
    {
        return $this->payment_brand;
    }

    /**
     * Init content.
     *
     * @return void
     */
    public function initContent()
    {
        try {
            $tablesExist = SibsMigration::execute();

            if (! $tablesExist) {
                SibsLogger::error('Table Consistency problem');

                throw new SibsException('ERROR_GENERAL_REDIRECT');
            }

            $environment_file = Sibs::getEnvironmentConfig();
            $widget_endpoints = $environment_file['widget_endpoints'];

            SibsLogger::info('start render sibs form');

            parent::initContent();

            $this->context->cookie->__set('sibs_paymentBrand', $this->getPaymentMethod());
            $this->context->cookie->write();
            SibsLogger::info("cookie sibs_paymentBrand: {$this->context->cookie->__get('sibs_paymentBrand')}");

            $lang = $this->getLanguage();

            $transactionParameter = $this->getTransactionParameter();
            SibsLogger::info('transactionParameter: ' . SibsLogger::prettify($transactionParameter));

            $valide_transaction = SibsTransaction::getTransactionsSibsView($transactionParameter['id_transaction'], $transactionParameter['amount']);
            SibsLogger::info('valide_transaction: ' . SibsLogger::prettify($valide_transaction));

            if (empty($valide_transaction)) {
                // get checkout response
                SibsLogger::info('valide_transaction: NAO');
                $checkoutResult = SibsPaymentCore::getCheckoutResult($transactionParameter, $lang);
                SibsLogger::info('checkoutResult: ' . SibsLogger::prettify($checkoutResult));

                $response = $checkoutResult['response'];

                if (! $checkoutResult['is_valid'] || empty($response['returnStatus']['statusCode']) || $response['returnStatus']['statusCode'] !== '000') {
                    throw new SibsException('ERROR_GENERAL_REDIRECT');
                }
                SibsLogger::info('SibsTransaction::saveTransactionsSibs begin');
                SibsTransaction::saveTransactionsSibs($transactionParameter['id_transaction'], $response);
                SibsLogger::info('SibsTransaction::saveTransactionsSibs end');
            } else {
                SibsLogger::info('valide_transaction: SIM');
                $response = [
                    'transactionID'        => $valide_transaction['id_transaction'],
                    'transactionSignature' => $valide_transaction['signature'],
                    'formContext'          => $valide_transaction['formContext'],
                    'amount'               => [
                        'currency' => $transactionParameter['currency'],
                        'amount'   => $valide_transaction['amount'],
                    ],
                ];

                SibsLogger::info('formContext: ' . $response['formContext']);
            }

            $paymentWidgetUrl = SibsPaymentCore::getPaymentWidgetUrl(
                $transactionParameter,
                $response['transactionID'],
                $widget_endpoints
            );
            SibsLogger::info("paymentWidgetUrl: $paymentWidgetUrl");
            SibsLogger::info("result transactionID: {$response['transactionID']}");

            $paymentWidgetContent = SibsPaymentCore::getResponseData(
                $paymentWidgetUrl,
                $transactionParameter['server_mode'],
                'GET',
                '',
                'json'
            );

            if (! $paymentWidgetContent['is_valid'] || SibsUtils::strContains($paymentWidgetContent['response'], 'errorDetail')) {
                throw new SibsException('ERROR_GENERAL_REDIRECT');
            }

            SibsLogger::info("result transactionID: {$response['transactionID']}");

            $formConfig  = $this->getFormConfig($response, $transactionParameter, $lang);
            $formStyle   = $this->getFormStyle();
            $formContext = isset($response['formContext']) ? $response['formContext'] : null;
            $signature   = isset($response['transactionSignature']) ? $response['transactionSignature'] : null;

            SibsLogger::info("formConfig: $formConfig");
            SibsLogger::info("formStyle: $formStyle");
            SibsLogger::info("formContext: $formContext");
            SibsLogger::info("signature: $signature");

            $responseURL = $this->context->link->getModuleLink(
                'sibs',
                'validation',
                [
                    'payment_method' => $this->getPaymentMethod(),
                ],
                true
            );

            $templateParameters = [
                'fullname'         => "{$this->context->customer->firstname} {$this->context->customer->lastname}",
                'paymentWidgetUrl' => $paymentWidgetUrl,
                'frameTestMode'    => SibsUtils::getTestMode($this->payment_method),
                'paymentBrand'     => $this->getPaymentBrand(),
                'total'            => $this->context->cart->getOrderTotal(true, Cart::BOTH),
                'cancelUrl'        => $this->context->link->getPageLink('order', true, null, ['step' => '3']),
                'is_guest'         => $this->context->customer->is_guest,
                'responseUrl'      => $responseURL,
                'this_path'        => $this->module->getPathUri(),
                'formConfig'       => $formConfig,
                'formContext'      => $formContext,
                'signature'        => $signature,
                'formStyle'        => $formStyle,
                'this_path_ssl'    => Tools::getShopDomainSsl(true, true) . __PS_BASE_URI__ . "modules/{$this->module->name}/",
            ];
            SibsLogger::info('templateParameters: ' . SibsLogger::prettify($templateParameters));

            $this->context->smarty->assign($templateParameters);
            $this->setTemplate($this->getTemplateName());
            SibsLogger::info('get template: ' . SibsLogger::prettify($this->getTemplateName()));

            SibsLogger::info('end render sibs form');
        } catch (SibsException $e) {
            $this->redirectWithErrorMessage($e->getErrorMessage());
        }
    }

    /**
     * Get Form Config.
     *
     * @param array $response
     * @param array $transactionParameter
     * @param string $lang
     * @return string|false
     */
    public function getFormConfig($response, $transactionParameter, $lang)
    {
        $redirect_url =  $this->context->link->getModuleLink(
            'sibs',
            'validation',
            [
                'payment_method' => $this->getPaymentMethod(),
                'id'             => $response['transactionID'],
            ],
            true
        );

        $amount_value    = $this->context->cart->getOrderTotal(true, Cart::BOTH);
        SibsLogger::info('amount_value: ' . SibsLogger::prettify($amount_value));
        $amount_currency = isset($response['amount']['currency']) ? $response['amount']['currency'] : null;
        SibsLogger::info('amount_currency: ' . SibsLogger::prettify($amount_currency));
        $formConfig = [
            'paymentMethodList' => SibsPaymentCore::sibs_get_payment_method_for_spg($this->getPaymentMethod()),
            'amount'            => [
                'value'    => $amount_value,
                'currency' => $amount_currency,
            ],
            'language'     => $lang,
            'redirectUrl'  => $redirect_url,
            'customerData' => $this->getCustomerData($transactionParameter),
        ];

        return json_encode($formConfig);
    }

    /**
     * Get Form Style.
     *
     * @return string|false
     */
    public function getFormStyle()
    {
        // TODO: get form style custom data
        $formStyle = [
            'layout' => 'default',
            'theme'  => 'default',
            'color'  => [
                'primary'   => '',
                'secondary' => '',
                'border'    => '',
                'surface'   => '',
                'header'    => [
                    'text'       => '',
                    'background' => '',
                ],
                'body' => [
                    'text'       => '',
                    'background' => '',
                ],
            ],
            'font' => '',
        ];

        return json_encode($formStyle);
    }

    /**
     * Get Customer Data.
     *
     * @param array $transactionParameter
     * @return array
     */
    public function getCustomerData($transactionParameter)
    {
        $customerName  = $transactionParameter['customer']['first_name'] . ' ' . $transactionParameter['customer']['last_name'];
        $customerEmail = $transactionParameter['customer']['email'];

        $customerData = [
            'customerName'  => $customerName,
            'customerEmail' => $customerEmail,
        ];

        return $customerData;
    }

    /**
     * Redirect and show the error message.
     *
     * @param string $message
     * @return void
     */
    public function redirectWithErrorMessage($message)
    {
        $this->errors[] = $message;
        $this->redirectWithNotifications(
            $this->context->link->getPageLink('order', true, null, ['step' => '3'])
        );
    }

    /**
     * Return transaction parameter to be sent to the gateway.
     *
     * @return array
     */
    public function getTransactionParameter()
    {
        $currencyobj = new Currency((int) $this->context->cart->id_currency);
        $currency    = $currencyobj->iso_code;

        $paymentMethod                       = $this->getPaymentMethod();
        $credentials                         = SibsUtils::getCredentials();
        $customer                            = $this->getCustomerParameter();
        $payment                             = $this->getPaymentParameter($currency, $paymentMethod);
        $transactionParameter                = array_merge($credentials, $customer, $payment);
        $transactionParameter['customer_ip'] = $this->getCustomerIP();

        // added description for blik
        if ($this->getPaymentMethod() == SibsConstants::PAYMENT_METHOD_BLIK) {
            $transactionParameter['descriptor'] = Configuration::get('PS_SHOP_NAME');
        }

        return $transactionParameter;
    }

    /**
     * Return all parameters that required for complete the payment.
     *
     * @param  string $currency
     * @param  string $paymentMethod
     * @return array
     */
    private function getPaymentParameter($currency, $paymentMethod)
    {
        $sibs_transactionid = '' . $this->context->cart->id;
        $this->context->cookie->__set('sibs_transactionid', $sibs_transactionid);
        $this->context->cookie->write();

        $transaction = [
            'id_transaction' => $sibs_transactionid,
            'payment_type'   => $this->getPaymentType(),
            'amount'         => $this->context->cart->getOrderTotal(true, Cart::BOTH),
            'currency'       => $currency,
            'test_mode'      => SibsUtils::getTestMode($paymentMethod),
            'payment_method' => $paymentMethod,
        ];

        return $transaction;
    }

    /**
     * Get Customer Parameter.
     *
     * @return array
     */
    public function getCustomerParameter()
    {
        $customerID       = (int) $this->context->cookie->__get('id_customer');
        $address_shipping = new Address((int) $this->context->cart->id_address_delivery);
        $country_shipping = new Country($address_shipping->id_country);

        $address_billing = new Address((int) $this->context->cart->id_address_invoice);
        $country_billing = new Country($address_billing->id_country);

        $customer = [
            'customer' => [
                'first_name' => $this->context->customer->firstname,
                'last_name'  => $this->context->customer->lastname,
                'email'      => $this->context->customer->email,
                'phone'      => PrestashopAddress::getPhoneNumber($customerID),
                'birthdate'  => $this->context->customer->birthday,
                'sex'        => ($this->context->customer->id_gender == '1') ? 'M' : 'F',
            ],
            'shipping' => [
                'street'       => $address_shipping->address1 . $address_shipping->address2,
                'city'         => $address_shipping->city,
                'zip'          => $address_shipping->postcode,
                'country_code' => $country_shipping->iso_code,
            ],
            'billing' => [
                'street'       => $address_billing->address1 . $address_billing->address2,
                'city'         => $address_billing->city,
                'zip'          => $address_billing->postcode,
                'country_code' => $country_billing->iso_code,
            ],
        ];

        return $customer;
    }

    /**
     * Get Cart items.
     *
     * @return array
     */
    public function getCartItems()
    {
        $percent   = 100;
        $cartItems = [];
        $carts     = $this->context->cart->getProducts();

        foreach ($carts as $cart) {
            $priceWithTax    = number_format($cart['price_without_reduction'], 2);
            $priceWithDisc   = number_format($cart['price_with_reduction'], 2);
            $priceWithoutTax = number_format($cart['price_with_reduction_without_tax'], 2);

            $discount = (($priceWithTax - $priceWithDisc) * $percent) / $priceWithTax;
            $tax      = (($priceWithDisc - $priceWithoutTax) * $percent) / $priceWithDisc;

            array_push($cart, [
                'merchant_item_id' => $cart['id_product'],
                'discount'         => $discount,
                'quantity'         => $cart['cart_quantity'],
                'name'             => $cart['name'],
                'price'            => $priceWithTax,
                'tax'              => number_format($tax, 0),
            ]);
        }

        return ['cartItems' => $cartItems];
    }

    /**
     * Get Customer IP.
     *
     * @return string
     */
    public function getCustomerIP()
    {
        $customerIP = $_SERVER['REMOTE_ADDR'];

        return ($customerIP == '::1') ? '127.0.0.1' : $customerIP;
    }

    /**
     * Get Language.
     *
     * @return string
     */
    protected function getLanguage()
    {
        $langobj       = new Language((int) $this->context->cart->id_lang);
        $lang_iso_code = $langobj->iso_code;

        switch ($lang_iso_code) {
            case 'pl':
                $lang = $lang_iso_code;

                break;
            default:
                $lang = 'en';
        }

        return $lang;
    }

    /**
     * Check if a cart not empty.
     *
     * @return bool
     */
    public function isCartItemEmpty()
    {
        $cartItem = $this->getCartItems();

        if (empty($cartItem['cartItems'])) {
            return false;
        }

        return true;
    }
}
