<?php

/**
 * Created by PhpStorm.
 * User: jderosa
 * Date: 31/10/19
 * Time: 16.33
 */

namespace FiloBlu\Rma\Helper;

use Magento\Catalog\Api\Data\ProductInterface;
use Magento\Rma\Model\Item;
use Magento\Rma\Model\ResourceModel\Rma\Collection;
use Magento\Rma\Model\Rma;
use Magento\Sales\Model\Order\ItemRepository;
use function count;
use FiloBlu\Rma\Block\Adminhtml\System\Config as Reason;
use function in_array;
use function is_array;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\Helper\AbstractHelper;
use Magento\Framework\App\Helper\Context;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Rma\Api\Data\RmaInterface;
use Magento\Sales\Api\Data\OrderInterface;

use Magento\Sales\Api\OrderItemRepositoryInterface;
use Magento\Store\Model\ScopeInterface;
use Psr\Log\LoggerInterface;

/**
 *
 */
class RmaHelper extends AbstractHelper
{
    /** @var string */
    const XML_PATH_VALIDITY_DAYS = 'sales/rma_validity_settings/validity_days';

    const CACHE_ID = 'rma_reasons';
    const RMA_REASON_CONFIG = 'sales/rma_reason/reason';
    const XML_PATH_RMA_RESOLUTION_MAPPING = 'sales/rma_resolutions_mapping/mapping';
    const STANDARD_REASON_ID_FOR_CHANGESIZE = 'wrong_size';
    const PICKUPINSTORE_KEY = 'pickupinstore';
    const ALLOWED_PICKUPINSTORE_STATUSES = 'filoblu_disablerma_section/rma_group/allowed_pickupinstore_order_status';
    const ALLOW_CUSTOMIZED_PRODUCT_REFUND = 'filoblu_disablerma_section/rma_group/allow_customized_product_return';
    const EASYRMA_MATRIXRATE_SOURCE = 'filoblu_disablerma_section/easy_return_matrixrate_group/matrixrate_source_easy_return';
    const EASYRMA_MATRIXRATE_CONDITION_NAME = 'filoblu_disablerma_section/easy_return_matrixrate_group/condition_name';
    const EASYRMA_CHANGE_SIZE_ORDER_CREATION_STRATEGY = 'filoblu_disablerma_section/rma_group/rma_change_size_order_creation_strategy';
    const EASYRMA_CHANGE_SIZE_SHOW_OSS_SIZES_IN_SELECT = 'filoblu_disablerma_section/rma_group/show_oos_sizes_in_select';
    const CHANGE_SIZE_MATRIXRATE_SOURCE = 'filoblu_disablerma_section/change_size_matrixrate_group/matrixrate_source_change_size';
    const CHANGE_SIZE_CONDITION_NAME  = 'filoblu_disablerma_section/change_size_matrixrate_group/condition_name';
    const XML_PATH_DISALLOWED_RMA_REASON_EMAIL_SENDING = 'filoblu_disablerma_section/rma_group/disallow_email_for_selected_order_status';
    const XML_PATH_SEND_AUTH_EMAIL = 'filoblu_disablerma_section/easy_return_matrixrate_group/send_rma_auth_email';
    const XML_PATH_ENABLE_RMA_USE_CONFIG_PLUGIN = 'sales/extra_settings/enable_rma_use_config_plugin';
    const XML_PATH_WRONG_SIZE_MAPPING = 'filoblu_disablerma_section/wrong_size_mapping/mapping';
    const XML_PATH_WRONG_OR_DAMAGED_RMA_ITEM = 'filoblu_disablerma_section/wrong_or_damaged_item_email/mapping';

    /**
     * @var ScopeConfigInterface
     */
    protected $scopeConfig;

    /**
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * @var Reason
     */
    protected $reason;

    /**
     * @var SerializerHelper
     */
    protected $serializer;

    /**
     * @var OrderItemRepositoryInterface
     */
    private $orderItemRepository;
    /**
     * @var Collection
     */
    private $rmaCollection;

    /**
     * RmaHelper constructor.
     * @param Context $context
     * @param ScopeConfigInterface $scopeConfig
     * @param LoggerInterface $logger
     * @param Reason $reason
     * @param SerializerHelper $serializer
     * @param OrderItemRepositoryInterface $orderItemRepository
     * @param \Magento\Rma\Model\ResourceModel\Rma\Collection $rmaCollection
     */
    public function __construct(
        Context                                         $context,
        ScopeConfigInterface                            $scopeConfig,
        LoggerInterface                                 $logger,
        Reason                                          $reason,
        SerializerHelper                                $serializer,
        OrderItemRepositoryInterface                    $orderItemRepository,
        Collection $rmaCollection
    )
    {
        $this->scopeConfig = $scopeConfig;
        $this->logger = $logger;
        $this->reason = $reason;
        $this->serializer = $serializer;
        $this->orderItemRepository = $orderItemRepository;
        parent::__construct($context);
        $this->rmaCollection = $rmaCollection;
    }

    /**
     * @param int $magentoReasonId
     * @return bool
     */
    public function checkIfAutoApproved(int $magentoReasonId)
    {
        $autoApprove = false;

        $value = $this->scopeConfig->getValue(self::RMA_REASON_CONFIG);
        if (empty($value)) {
            return false;
        }

        $mappedReasons = $this->serializer->unserialize($value);
        $standardReasons = $this->reason->getAll();
        foreach ($mappedReasons as $reason) {
            if ((int)$reason['brand_reason'] == $magentoReasonId) {
                foreach ($standardReasons as $stdReason) {
                    if ($stdReason['id'] == $reason['standard_reason'] && $stdReason['automatic_approval']) {
                        $autoApprove = true;
                    }
                }
            }
        }

        return $autoApprove;
    }

    /**
     * @return int
     */
    public function getDefaultChangeSizeMappedReason()
    {
        $reasons = $this->getAllMappedReason();
        if (count($reasons) > 0) {
            foreach ($reasons as $reason) {
                if ($this->checkIfAllowedMagentoChangeSizeReason($reason['brand_reason'], 'brand')) {
                    return (int)$reason['brand_reason'];
                }
            }
        }
        return -1;
    }

    /**
     * @return array
     */
    public function getAllMappedReason()
    {
        $value = $this->scopeConfig->getValue(self::RMA_REASON_CONFIG);

        if (empty($value)) {
            return [];
        }

        return $this->serializer->unserialize($value);
    }

    /**
     * @param int $reasonId
     * @param string|null $reasonType
     * @return bool
     */
    public function checkIfAllowedMagentoChangeSizeReason(int $reasonId, string $reasonType = null)
    {
        if ($this->checkIfItIsMapped($reasonId)) {
            if (in_array(
                self::STANDARD_REASON_ID_FOR_CHANGESIZE,
                $this->getMappedReasonByReasonId($reasonId, 'brand')
            )
            ) {
                return true;
            }

            return false;
        }

        $this->logger->critical("RmaHelper -> Standard Change Size Rma Reason isn't mapped yet!");
        return false;
    }

    /**
     * @param $reasonId
     * @return bool
     */
    public function checkIfItIsMapped($reasonId)
    {
        $value = $this->scopeConfig->getValue(self::RMA_REASON_CONFIG);
        if (empty($value)) {
            return false;
        }

        $mappedReasons = $this->serializer->unserialize($value);
        foreach ($mappedReasons as $reason) {
            if ((int)$reasonId == (int)$reason['brand_reason']) {
                return true;
            }
        }
        return false;
    }

    /**
     * @param int $reasonId
     * @param string $type
     * @return array
     */
    public function getMappedReasonByReasonId(int $reasonId, string $type = 'standard')
    {
        $value = $this->scopeConfig->getValue(self::RMA_REASON_CONFIG);
        if (empty($value)) {
            return [];
        }

        $mappedReasons = $this->serializer->unserialize($value);
        $exists = false;
        $result = [];
        foreach ($mappedReasons as $reason) {
            if ($type === 'standard') {
                if ($reasonId == $reason['standard_reason']) {
                    $exists = true;
                    $result[] = (int)$reason['brand_reason'];
                }
            } else {
                if (($type === 'brand') && $reasonId == (int)$reason['brand_reason']) {
                    $exists = true;
                    $result[] = $reason['standard_reason'];
                }
            }
        }
        if ($exists) {
            return $result;
        }

        return [];
    }

    /**
     * @param OrderInterface $order
     * @return bool
     */
    public function isValidPickupInStoreOrderStatus(OrderInterface $order)
    {
        if (strpos($order->getShippingMethod() ?? '', self::PICKUPINSTORE_KEY) === false) {
            return true;
        }

        $allowedStatuses = $this->getPickupInStoreAllowedStatusesArray();

        if (in_array($order->getStatus(), $allowedStatuses)) {
            return true;
        }

        return false;
    }

    /**
     * @return array
     */
    protected function getPickupInStoreAllowedStatusesArray()
    {
        $allowedStatus = [];
        $allowedStatusesConfig = $this->scopeConfig->getValue(self::ALLOWED_PICKUPINSTORE_STATUSES);

        if (!is_array($allowedStatusesConfig)) {
            $allowedStatusesConfig = $this->serializer->unserialize($allowedStatusesConfig);
        }

        foreach ($allowedStatusesConfig as $item) {
            if (isset($item['pickupinstore_allowed_status'])) {
                $allowedStatus[] = $item['pickupinstore_allowed_status'];
            }
        }

        return $allowedStatus;
    }

    /**
     * @return mixed
     */
    public function isCustomizedProductRefundAllowed()
    {
        return $this->scopeConfig->getValue(self::ALLOW_CUSTOMIZED_PRODUCT_REFUND);
    }

    /**
     * @return mixed
     */
    public function getEasyReturnMatrixrateSource()
    {
        return $this->scopeConfig->getValue(self::EASYRMA_MATRIXRATE_SOURCE, ScopeInterface::SCOPE_STORE);
    }

    /**
     * @return mixed
     */
    public function getEasyReturnMatrixrateConditionName()
    {
        return $this->scopeConfig->getValue(self::EASYRMA_MATRIXRATE_CONDITION_NAME, ScopeInterface::SCOPE_STORE);
    }

    /**
     * @return mixed
     */
    public function getChangeSizeOrderCreationStrategy()
    {
        return $this->scopeConfig->getValue(self::EASYRMA_CHANGE_SIZE_ORDER_CREATION_STRATEGY);
    }

    /**
     * @return mixed
     */
    public function getChangeSizeMatrixrateSource()
    {
        return $this->scopeConfig->getValue(self::CHANGE_SIZE_MATRIXRATE_SOURCE, ScopeInterface::SCOPE_STORE);
    }

    /**
     * @return mixed
     */
    public function getChangeSizeMatrixrateConditionName()
    {
        return $this->scopeConfig->getValue(self::CHANGE_SIZE_CONDITION_NAME, ScopeInterface::SCOPE_STORE);
    }

    /**
     * @param $store
     * @return bool
     */
    public function getShowOosSizesInSelect($store): bool
    {
        return $this->scopeConfig->isSetFlag(
            self::EASYRMA_CHANGE_SIZE_SHOW_OSS_SIZES_IN_SELECT,
            ScopeInterface::SCOPE_STORE,
            $store
        );
    }

    /**
     * @param $itemId
     * @return int|null
     * @throws InputException
     * @throws NoSuchEntityException
     */
    public function getStoreByOrderItemId($itemId)
    {
        /** @var ItemRepository|OrderItemRepositoryInterface $repository */
        $repository = $this->orderItemRepository;
        return $repository->get($itemId)->getStoreId();
    }

    /**
     * @param $store
     * @return int
     */
    public function getValidityDays($store)
    {
        return (int)$this->scopeConfig->getValue(
            self::XML_PATH_VALIDITY_DAYS,
            ScopeInterface::SCOPE_STORE,
            $store
        );
    }

    /**
     * @return bool
     */
    public function mustSendRmaAuthEmail()
    {
        return $this->scopeConfig->isSetFlag(self::XML_PATH_SEND_AUTH_EMAIL);
    }

    /**
     * @param RmaInterface $rma
     * @return bool
     */
    public function isRmaStatusAllowedToSendEmail(RmaInterface $rma): bool
    {
        $disallowedStatuses = $this->getDisallowedRmaStatusEmailSending();

        foreach ($rma->getItems() as $item) {
            if (in_array($item->getReason(), $disallowedStatuses)) {
                return false;
            }
        }

        return true;
    }

    /**
     * @return array
     */
    protected function getDisallowedRmaStatusEmailSending(): array
    {
        $disallowedStatusesArray = $this->getDisallowedRmaReasonEmailSending();

        if (!is_array($disallowedStatusesArray)) {
            $disallowedStatusesArray = $this->serializer->unserialize($disallowedStatusesArray);
        }

        if (!$disallowedStatusesArray) {
            return [];
        }

        $statuses = [];

        foreach ($disallowedStatusesArray as $item) {
            $statuses[] = $item['rma_reson'];
        }

        return $statuses;
    }

    /**
     * @return string|null|array
     */
    public function getDisallowedRmaReasonEmailSending()
    {
        return $this->scopeConfig->getValue(
            self::XML_PATH_DISALLOWED_RMA_REASON_EMAIL_SENDING
        );
    }

    /**
     * @param \Magento\Catalog\Api\Data\ProductInterface $product
     * @param $orderedSku
     * @return bool
     */
    public function isProductReturnable(ProductInterface $product, $orderedSku = ''): bool
    {
        if (!$product->getIsReturnable()) {
            return false;
        }

        $notReturnableItems = [];

        if ($product->getTypeId() === 'configurable') {
            $configurable = $product->getTypeInstance();
            foreach ($configurable->getUsedProducts($product) as $child) {

                //reload product in order to force data refresh
                $child->load($child->getEntityId());

                if (!(bool)$child->getIsReturnable()) {
                    $notReturnableItems[] = $child->getSku();
                }

            }
        }

        if (in_array($orderedSku, $notReturnableItems)) {
            return false;
        }

        return true;
    }

    /**
     * @return array
     */
    public function getRmaMappedResolutions()
    {
        $resolutionMappingSerialized = $this->scopeConfig->getValue(self::XML_PATH_RMA_RESOLUTION_MAPPING);
        $resolutionMapping = $this->serializer->unserialize($resolutionMappingSerialized);

        $mappedResolutions = [];

        foreach ($resolutionMapping as $item) {
            $mappedResolutions[(int)$item['rma_resolution']] = $item['netsuite_id'];
        }

        return $mappedResolutions;
    }

    /**
     * @param $order
     * @return bool
     */
    public function orderContainsReturnableProducts($order): bool
    {

        $rmas = $this->rmaCollection
            ->addFieldToFilter('order_id', $order->getId())
            ->addFieldToFilter('status', ['neq' => 'closed'])
            ->getItems();

        if (!count($rmas)) {
            return true;
        }

        $returnedProducts = [];
        $returnedQuantity = [];

        /** @var Rma $rma */
        foreach ($rmas as $rma) {
            /** @var Item $item */
            foreach ($rma->getItems() as $item) {
                $returnedProducts[] = $item->getProductSku();

                if (!isset($returnedQuantity[$item->getProductSku()])) {
                    $returnedQuantity[$item->getProductSku()] = 0;
                }

                $returnedQuantity[$item->getProductSku()] += (int)$item->getQtyRequested();
            }
        }

        return array_sum($returnedQuantity) != (int)$order->getTotalQtyOrdered();
    }

    /**
     * @return bool
     */
    public function isUseRmaConfigPluginEnabled()
    {
        return $this->scopeConfig->isSetFlag(self::XML_PATH_ENABLE_RMA_USE_CONFIG_PLUGIN);
    }

    /**
     * @return array
     */
    public function getWrongSizeMapping()
    {
        $wrongSizeMappingSerialized = $this->scopeConfig->getValue(self::XML_PATH_WRONG_SIZE_MAPPING);
        $wrongSizeMapping = $this->serializer->unserialize($wrongSizeMappingSerialized);

        $mappedReasons = [];

        foreach ($wrongSizeMapping as $item) {
            $mappedReasons[$item['magento_reason']] = $item['brand_reason'];
        }

        return $mappedReasons;
    }

    /**
     * @return array
     */
    public function getWrongOrDamageRmaItemsMapping()
    {
        $wrongSizeMappingSerialized = $this->scopeConfig->getValue(self::XML_PATH_WRONG_OR_DAMAGED_RMA_ITEM);
        $wrongSizeMapping = $this->serializer->unserialize($wrongSizeMappingSerialized);

        $mappedReasons = [];

        foreach ($wrongSizeMapping as $item) {
            $mappedReasons[$item['magento_reason']] = $item['brand_reason'];
        }

        return $mappedReasons;
    }

    /**
     * @param $config
     * @param $storeId
     * @return bool
     */
    public function isWrongOrDamagedEmailEmailConfigEnabled($config, $storeId)
    {
        return $this->scopeConfig->isSetFlag(
            $config . '/enabled',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }

    /**
     * @param $config
     * @param $storeId
     * @return mixed
     */
    public function getCopyTo($config, $storeId)
    {
        return $this->scopeConfig->getValue(
            $config. '/copy_to',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }

    /**
     * @param $config
     * @param $storeId
     * @return mixed
     */
    public function getCopyMethod($config, $storeId)
    {
        return $this->scopeConfig->getValue(
            $config. '/copy_method',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }

    /**
     * @param $config
     * @param $storeId
     * @return mixed
     */
    public function getTemplate($config, $storeId)
    {
        return $this->scopeConfig->getValue(
            $config. '/template',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }

    /**
     * @param $config
     * @param $storeId
     * @return mixed
     */
    public function getIdentity($config, $storeId)
    {
        return $this->scopeConfig->getValue(
            $config. '/identity',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );
    }

}
