<?php

namespace Sibs\Sibs\Helper;

use Exception;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\UrlInterface;
use Magento\Store\Model\ScopeInterface;
use Sibs\Sibs\Model\Api\SibsApi;
use Sibs\Sibs\Model\SibsConstants;
use Sibs\Sibs\Utils\SibsLog;

class DataHelper extends AbstractHelper
{
    /**
     * @var \Magento\Framework\Module\ModuleListInterface
     */
    protected $_moduleList;

    /**
     * @var \Magento\Sales\Model\Service\InvoiceService
     */
    protected $_invoiceService;

    /**
     * @var \Magento\Framework\DB\Transaction
     */
    protected $_transaction;

    /**
     * @var \Magento\Catalog\Api\ProductRepositoryInterface
     */
    protected $_productRepository;

    /**
     * @var \Magento\Framework\App\ResourceConnection
     */
    protected $_resourceConnection;

    /**
     * @var \Magento\Sales\Api\OrderManagementInterface
     */
    protected $_orderManagement;

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

    /**
     * @var \Magento\Framework\Stdlib\DateTime\TimezoneInterface
     */
    protected $_timezone;

    /**
     * @var \Magento\Framework\Locale\Resolver
     */
    protected $_localeResolver;

    /**
     * @var \Magento\Framework\App\ProductMetadataInterface
     */
    protected $_magentoMetadata;

    /**
     * @var \Magento\Framework\App\Config\ScopeConfigInterface
     */
    protected $_scopeConfig;

    /**
     * @var \stdClass
     */
    protected $_sibsUrl;

    /**
     * @var \stdClass
     */
    protected $_sibsInfo;

    /**
     * Constructor
     *
     * @param \Magento\Framework\App\Helper\Context $context,
     * @param \Magento\Framework\Module\ModuleListInterface $moduleList,
     * @param \Magento\Sales\Model\Service\InvoiceService $invoiceService,
     * @param \Magento\Framework\DB\Transaction $transaction,
     * @param \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
     * @param \Magento\Framework\App\ResourceConnection $resourceConnection,
     * @param \Magento\Sales\Api\OrderManagementInterface $orderManagement,
     * @param \Magento\Store\Model\StoreManagerInterface $storeManager,
     * @param \Magento\Framework\Stdlib\DateTime\TimezoneInterface $timezone,
     * @param \Magento\Framework\Locale\Resolver $localeResolver,
     * @param \Magento\Framework\App\ProductMetadataInterface $magentoMetadata
     */
    public function __construct(
        \Magento\Framework\App\Helper\Context $context,
        \Magento\Framework\Module\ModuleListInterface $moduleList,
        \Magento\Sales\Model\Service\InvoiceService $invoiceService,
        \Magento\Framework\DB\Transaction $transaction,
        \Magento\Catalog\Api\ProductRepositoryInterface $productRepository,
        \Magento\Framework\App\ResourceConnection $resourceConnection,
        \Magento\Sales\Api\OrderManagementInterface $orderManagement,
        \Magento\Store\Model\StoreManagerInterface $storeManager,
        \Magento\Framework\Stdlib\DateTime\TimezoneInterface $timezone,
        \Magento\Framework\Locale\Resolver $localeResolver,
        \Magento\Framework\App\ProductMetadataInterface $magentoMetadata
    ) {
        parent::__construct($context);

        $this->_moduleList         = $moduleList;
        $this->_invoiceService     = $invoiceService;
        $this->_transaction        = $transaction;
        $this->_productRepository  = $productRepository;
        $this->_resourceConnection = $resourceConnection;
        $this->_orderManagement    = $orderManagement;
        $this->_storeManager       = $storeManager;
        $this->_timezone           = $timezone;
        $this->_localeResolver     = $localeResolver;
        $this->_magentoMetadata    = $magentoMetadata;

        $this->_scopeConfig        = $context->getScopeConfig();
        $this->_sibsInfo           = $this->getConfigData();
        $this->_sibsUrl            = $this->getSibsUrl();
    }

    /**
     * getVersion
     *
     * @return string
     */
    public function getVersion()
    {
        $setup_version = $this->_moduleList->getOne(SibsConstants::MODULE_NAME)['setup_version'] ?? '0.0.0';

        return $setup_version;
    }

    /**
     * getMagentoVersion
     *
     * @return string
     */
    public function getMagentoVersion()
    {
        return $this->_magentoMetadata->getVersion() ?? '0.0.0';
    }

    /**
     * getBaseUrl
     *
     * @return string
     */
    public function getBaseUrl()
    {
        return $this->_storeManager->getStore()->getBaseUrl(UrlInterface::URL_TYPE_LINK) ?? '';
    }

    /**
     * getSibsUrl
     *
     * @return string
     */
    public function getSibsUrl()
    {
        $env      = $this->_sibsInfo->environment;
        $env_file = $this->getEnvironmentConfig();

        $sibsUrl           = new \stdClass;
        $sibsUrl->checkout = $env_file['checkout_endpoints'][$env] ?? '';
        $sibsUrl->callback = $env_file['url_callback'][$env] ?? '';

        return $sibsUrl;
    }

    /**
     * getStoreID
     *
     * @return string
     */
    public function getStoreID()
    {
        return $this->_storeManager->getStore()->getId();
    }

    /**
     * getStoreLanguage
     *
     * @param bool $isFullLanguage
     *
     * @return string
     */
    public function getStoreLanguage($isFullLanguage = false)
    {
        $locale = $this->_localeResolver->getLocale();

        if ($isFullLanguage) {
            return $locale;
        }

        $storeLanguage = substr($locale, 0, 2);

        if (in_array($storeLanguage, SibsConstants::ALLOWED_LANGUAGES)) {
            return $storeLanguage;
        }

        return SibsConstants::LNG_EN;
    }

    /**
     * getConfigData
     *
     * @return stdClass
     */
    public function getConfigData()
    {
        $sibsInfo                         = new \stdClass;
        $sibsInfo->webhook_secret         = $this->getConfigField('webhook_secret') ?? '';
        $sibsInfo->terminal_code          = $this->getConfigField('terminal_code') ?? '';
        $sibsInfo->token                  = $this->getConfigField('token') ?? '';
        $sibsInfo->clientid               = $this->getConfigField('client_id') ?? '';
        $sibsInfo->environment            = $this->getConfigField('environment') ?? '';

        return $sibsInfo;
    }

    /**
     * getConfigField
     *
     * @param string $field
     * @param string $group
     *
     * @return string
     */
    public function getConfigField($field, $group = 'sibs_config')
    {
        return $this->_scopeConfig->getValue(
            "payment/$group/$field",
            ScopeInterface::SCOPE_STORE,
            $this->getStoreID()
        );
    }

    /**
     * Pass an object to array
     *
     * @param object $data
     *
     * @return array
     */
    protected function _object2array($data)
    {
        if (! is_object($data) && ! is_array($data)) {
            return $data;
        }

        if (is_object($data)) {
            $data = get_object_vars($data);
        }

        return array_map([
            $this, '_object2array',
        ], $data);
    }

    /**
     * Get Creditcard Payment Type
     *
     * @return string
     */
    public function getCCPaymentType()
    {
        return $this->getConfigField(
            'payment_typeCC',
            SibsConstants::SIBS_PAYMENT_METHOD_CREDITCARD
        );
    }

    /**
     * Get Creditcard Instruction
     *
     * @return string
     */
    public function getCCInstruction()
    {
        return $this->getConfigField(
            'instructions',
            SibsConstants::SIBS_PAYMENT_METHOD_CREDITCARD
        );
    }

    /**
     * Get BLIK Payment Type
     *
     * @return string
     */
    public function getBLIKPaymentType()
    {
        return SibsConstants::SIBS_PAYMENT_TYPE_PURS;
    }

    /**
     * Get BLIK Instruction
     *
     * @return string
     */
    public function getBLIKInstruction()
    {
        return $this->getConfigField(
            'instructions',
            SibsConstants::SIBS_PAYMENT_METHOD_BLIK
        );
    }

    /**
     * Get BLIK Number of Retries
     *
     * @return string
     */
    public function getBLIKNumOfRetries()
    {
        return SibsConstants::SIBS_NUMBER_OF_RETRIES_BLIK;
    }

    /**
     * Get BLIK Retry Delay
     *
     * @return string
     */
    public function getBLIKRetryDelay()
    {
        return SibsConstants::SIBS_RETRY_DELAY_BLIK;
    }

    /**
     * Get Pay By Link Payment Type
     *
     * @return string
     */
    public function getPBLPaymentType()
    {
        return SibsConstants::SIBS_PAYMENT_TYPE_PURS;
    }

    /**
     * Get Pay By Link Instruction
     *
     * @return string
     */
    public function getPBLInstruction()
    {
        return $this->getConfigField(
            'instructions',
            SibsConstants::SIBS_PAYMENT_METHOD_PAY_BY_LINK
        );
    }

    /**
     * Get Pay By Expiration Date Value
     *
     * @return string
     */
    public function getPBLExpirationDateValue()
    {
        return SibsConstants::SIBS_PAYMENT_EXPIRATION_DATE_VALUE;
    }

    /**
     * Get Pay By Expiration Date Unit
     *
     * @return string
     */
    public function getPBLExpirationDateUnit()
    {
        return SibsConstants::SIBS_PAYMENT_EXPIRATION_DATE_UNIT;
    }

    /**
     * Get Xpay Payment Type
     *
     * @return string
     */
    public function getXpayPaymentType()
    {
        return SibsConstants::SIBS_PAYMENT_TYPE_PURS;
    }

    /**
     * Get Xpay Instruction
     *
     * @return string
     */
    public function getXpayInstruction()
    {
        return $this->getConfigField(
            'instructions',
            SibsConstants::SIBS_PAYMENT_METHOD_PAY_BY_LINK
        );
    }

    /**
     * Get Url Class
     *
     * @return stdClass
     */
    public function getUrl()
    {
        return $this->_sibsUrl;
    }

    /**
     * Get Url Checkout
     *
     * @return string
     */
    public function getUrlCheckout()
    {
        return $this->_sibsUrl->checkout;
    }

    /**
     * Get Url Payment
     *
     * @return string
     */
    public function getUrlPayment($refId)
    {
        return $this->getUrlCheckout() . "/$refId";
    }

    /**
     * Get Url Capture
     *
     * @return string
     */
    public function getUrlCapture($refId)
    {
        return $this->getUrlPayment($refId) . '/capture';
    }

    /**
     * Get Url Refund
     *
     * @return string
     */
    public function getUrlRefund($refId)
    {
        return $this->getUrlPayment($refId) . '/refund';
    }

    /**
     * Get Url Status
     *
     * @return string
     */
    public function getUrlStatus($refId)
    {
        return $this->getUrlPayment($refId) . '/status';
    }

    /**
     * Get Url Callback
     *
     * @return string
     */
    public function getUrlCallback()
    {
        return $this->_sibsUrl->callback;
    }

    /**
     * Get Info
     *
     * @return stdClass
     */
    public function getInfo()
    {
        return $this->_sibsInfo;
    }

    /**
     * Get Webhook Secret
     *
     * @return string
     */
    public function getWebhookSecret()
    {
        return $this->getInfo()->webhook_secret ?? '';
    }

    /**
     * Get Terminal ID
     *
     * @return string
     */
    public function getTerminalID()
    {
        return $this->getInfo()->terminal_code ?? '';
    }

    /**
     * Get Bearer Token
     *
     * @return string
     */
    public function getToken()
    {
        return $this->getInfo()->token ?? '';
    }

    /**
     * Get Client ID
     *
     * @return string
     */
    public function getClientID()
    {
        return $this->getInfo()->clientid ?? '';
    }

    /**
     * Get Environment
     *
     * @return string
     */
    public function getEnvironment()
    {
        return $this->getInfo()->environment ?? '';
    }

    /**
     * Get All Stores Webhook Secrets
     *
     * @return array
     */
    public function getAllWebhookSecrets()
    {
        $webhookSecrets = [];

        foreach ($this->_storeManager->getStores(true) as $storeID => $store) {
            $webhookSecrets[] = [
                'storeId'   => $storeID,
                'storeCode' => $store->getCode(),
                'storeName' => $store->getName(),
                'secret'    => $this->getWebhookSecretPerStore($storeID)
            ];
        }

        return $webhookSecrets;
    }

    /**
     * Get Webhook Secret Per Store
     *
     * @param string $storeID
     *
     * @return string
     */
    public function getWebhookSecretPerStore($storeID)
    {
        return $this->_scopeConfig->getValue(
            "payment/sibs_config/webhook_secret",
            ScopeInterface::SCOPE_STORE,
            $storeID
        ) ?? $this->getDefaultWebhookSecret();
    }

    /**
     * Get Webhook Secret Default
     *
     * @return string
     */
    public function getDefaultWebhookSecret()
    {
        $this->_scopeConfig->getValue(
            "payment/sibs_config/webhook_secret",
            ScopeInterface::SCOPE_STORE
        ) ?? $this->getWebhookSecret();
    }

    /**
     * Get Request Params
     *
     * @return array
     */
    public function getRequestData()
    {
        $data = $this->_getRequest()->getParams();

        return (! empty($data)) ? $data : null;
    }

    /**
     * Get Payment Instructions By Code
     *
     * @param string $code
     *
     * @return string
     */
    public function getInstructionByCode($code)
    {
        return $this->getConfigField(
            'instructions',
            $code
        );
    }

    /**
     * Get Moto
     *
     * @return string
     */
    public function getMoto()
    {
        return $this->getConfigField('moto');
    }

    /**
     * Get Timezone
     *
     * @return string
     */
    public function getTimezone()
    {
        return $this->_timezone->getConfigTimezone(
            ScopeInterface::SCOPE_STORES,
            $this->getStoreID()
        );
    }

    /**
     * Get Date from Magento 2
     *
     * @param ?string $datetime
     * @param ?string $format
     * @param ?string $interval
     *
     * @return string
     */
    public function getDateFromMagento($datetime = 'now', $format = 'Y-m-d H:i:s', $interval = null)
    {
        $timezone = $this->getTimezone();
        $datetimeClass = new \DateTime($datetime, new \DateTimeZone($timezone));

        if (!empty($interval)) {
            $intervalTime = \DateInterval::createFromDateString($interval);
            $datetimeClass->add($intervalTime);
        }

        return $datetimeClass->format($format);
    }

    /**
     * Get Payment Method for SPG
     *
     * @param string $payment_id
     *
     * @return string
     */
    public function sibs_get_payment_method_for_spg($payment_id)
    {
        switch ($payment_id) {
            case SibsConstants::SIBS_PAYMENT_METHOD_CREDITCARD:
                $payment_brand = SibsConstants::SIBS_API_METHOD_CREDITCARD;

                break;
            case SibsConstants::SIBS_PAYMENT_METHOD_BLIK:
                $payment_brand = SibsConstants::SIBS_API_METHOD_BLIK;

                break;
            case SibsConstants::SIBS_PAYMENT_METHOD_PAY_BY_LINK:
                $payment_brand = SibsConstants::SIBS_API_METHOD_PAY_BY_LINK_KEVIN;

            case SibsConstants::SIBS_PAYMENT_METHOD_XPAY:
                $payment_brand = SibsConstants::SIBS_API_METHOD_XPAY;

                break;
            default:
                $payment_brand = false;

                break;
        }

        return $payment_brand;
    }

    /**
     * Get Payment Result
     *
     * @param string $url
     * @param string $token
     * @param string $client_id
     *
     * @return mixed
     */
    public function get_payment_result($url, $token, $client_id)
    {
        $header = [
            "Authorization: Bearer $token",
            "X-IBM-Client-ID: $client_id",
        ];

        return SibsApi::get($url, $header);
    }

    /**
     * Convert SPG payment status to Magento 2 state and status.
     *
     * @param string $paymentStatus SPG payment status
     * @param string $paymentType SPG payment type
     *
     * @return array [$state, $status] Magento 2 state and status
     */
    public function sibs_get_order_state_and_status($paymentStatus, $paymentType)
    {
        switch ($paymentStatus) {
            case SibsConstants::SIBS_API_STATUS_SUCCESS:
            case SibsConstants::SIBS_API_STATUS_PARTIAL:
                list($orderState, $orderStatus) = $this->sibs_get_success_order_state_and_status($paymentType);

                break;
            case SibsConstants::SIBS_API_STATUS_PROCESSING:
            case SibsConstants::SIBS_API_STATUS_PENDING:
                list($orderState, $orderStatus) = $this->sibs_get_pending_order_state_and_status($paymentType);

                break;
            case SibsConstants::SIBS_API_STATUS_DECLINED:
            case SibsConstants::SIBS_API_STATUS_TIMEOUT:
            case SibsConstants::SIBS_API_STATUS_ERROR:
            default:
                list($orderState, $orderStatus) = $this->sibs_get_error_order_state_and_status($paymentType);

                break;
        }

        return [$orderState, $orderStatus];
    }

    /**
     * Get Success Order State and Status By Payment Type
     *
     * @param string $paymentType
     *
     * @return array
     */
    public function sibs_get_success_order_state_and_status($paymentType)
    {
        switch ($paymentType) {
            case SibsConstants::SIBS_PAYMENT_TYPE_AUTH:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_PROCESSING, SibsConstants::SIBS_STATUS_AUTHORIZED];

                break;
            case SibsConstants::SIBS_PAYMENT_TYPE_PURS:
            case SibsConstants::SIBS_PAYMENT_TYPE_CAPT:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_PROCESSING, SibsConstants::SIBS_STATUS_PROCESSING];

                break;
            case SibsConstants::SIBS_PAYMENT_TYPE_RFND:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_CLOSED, SibsConstants::SIBS_STATUS_REFUNDED];

                break;
            default:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_CANCELED, SibsConstants::SIBS_STATUS_CANCELED];

                break;
        }

        return [$orderState, $orderStatus];
    }

    /**
     * Get Pending Order State and Status By Payment Type
     *
     * @param string $paymentType
     *
     * @return array
     */
    public function sibs_get_pending_order_state_and_status($paymentType)
    {
        switch ($paymentType) {
            case SibsConstants::SIBS_PAYMENT_TYPE_AUTH:
            case SibsConstants::SIBS_PAYMENT_TYPE_PURS:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_HOLDED, SibsConstants::SIBS_STATUS_HOLDED];
            case SibsConstants::SIBS_PAYMENT_TYPE_CAPT:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_HOLDED, SibsConstants::SIBS_STATUS_CAPTURE_HOLDED];
            case SibsConstants::SIBS_PAYMENT_TYPE_RFND:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_HOLDED, SibsConstants::SIBS_STATUS_REFUND_HOLDED];

                break;
            default:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_HOLDED, SibsConstants::MAGENTO_STATE_HOLDED];

                break;
        }

        return [$orderState, $orderStatus];
    }

    /**
     * Get Error Order State and Status By Payment Type
     *
     * @param string $paymentType
     *
     * @return array
     */
    public function sibs_get_error_order_state_and_status($paymentType)
    {
        switch ($paymentType) {
            case SibsConstants::SIBS_PAYMENT_TYPE_AUTH:
            case SibsConstants::SIBS_PAYMENT_TYPE_PURS:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_CANCELED, SibsConstants::MAGENTO_STATE_CANCELED];
            case SibsConstants::SIBS_PAYMENT_TYPE_CAPT:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_PROCESSING, SibsConstants::SIBS_STATUS_AUTHORIZED];
            case SibsConstants::SIBS_PAYMENT_TYPE_RFND:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_PROCESSING, SibsConstants::SIBS_STATUS_PROCESSING];
            default:
                list($orderState, $orderStatus) = [SibsConstants::MAGENTO_STATE_CANCELED, SibsConstants::SIBS_STATUS_CANCELED];

                break;
        }

        return [$orderState, $orderStatus];
    }

    /**
     * Convert Blik payment status to Magento status.
     *
     * @param string $paymentStatus SPG payment status
     *
     * @return string Magento 2  status
     */
    public function sibs_get_capture_refund_status($paymentStatus)
    {
        switch ($paymentStatus) {
            case SibsConstants::SIBS_API_STATUS_SUCCESS:
            case SibsConstants::SIBS_API_STATUS_PARTIAL:
                $refundStatus = SibsConstants::MAGENTO_STATE_COMPLETE;

                break;
            case SibsConstants::SIBS_API_STATUS_PROCESSING:
            case SibsConstants::SIBS_API_STATUS_PENDING:
                $refundStatus = SibsConstants::MAGENTO_STATE_HOLDED;

                break;
            case SibsConstants::SIBS_API_STATUS_DECLINED:
            case SibsConstants::SIBS_API_STATUS_TIMEOUT:
            case SibsConstants::SIBS_API_STATUS_ERROR:
            default:
                $refundStatus = SibsConstants::MAGENTO_STATE_CANCELED;

                break;
        }

        return $refundStatus;
    }

    /**
     * Get Environment Config
     *
     * @return array
     */
    public function getEnvironmentConfig()
    {
        try {
            $json_file = file_get_contents(BP . '/app/code/Sibs/Sibs/environment.json');

            return json_decode($json_file, true);
        } catch (Exception $e) {
            SibsLog::err('Caught exception on accessing environment json: ' . $e->getMessage());

            return [];
        }
    }
}
