<?php

namespace FiloBlu\Rma\Plugin\Rma\Api\RmaRepositoryInterface;

use Exception;
use FiloBlu\Rma\Api\EasyReturnRepositoryInterface;
use FiloBlu\Rma\Api\RmaExtensionAttributesRepositoryInterface;
use FiloBlu\Rma\Helper\EasyReturnHelper;
use FiloBlu\Rma\Helper\RmaHelper;
use FiloBlu\Rma\Helper\RmaPoliciesHelper;
use FiloBlu\Rma\Model\OrderLocator;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Customer\Api\CustomerRepositoryInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Rma\Api\Data\ItemExtensionFactory;
use Magento\Rma\Api\Data\RmaExtensionInterfaceFactory;
use Magento\Rma\Api\Data\RmaInterface;
use Magento\Rma\Api\Data\RmaSearchResultInterface;
use Magento\Rma\Api\RmaRepositoryInterface;
use Magento\Rma\Model\ResourceModel\Item\CollectionFactory as ItemCollectionFactory;
use Magento\Sales\Api\Data\OrderAddressInterface;
use Magento\Sales\Api\Data\OrderAddressInterfaceFactory;
use Magento\Sales\Api\OrderRepositoryInterface;
use Psr\Log\LoggerInterface;
use Throwable;

/**
 *
 */
class AfterGet
{
    /**
     * @var LoggerInterface
     */
    protected $logger;

    /**
     * @var RmaExtensionAttributesRepositoryInterface
     */
    protected $rmaExtensionAttributesRepository;

    /**
     * @var ItemCollectionFactory
     */
    protected $itemCollectionFactory;

    /**
     * @var ProductRepositoryInterface
     */
    protected $productRepository;
    /**
     * @var RmaPoliciesHelper
     */
    protected $rmaPoliciesHelper;

    /**
     * @var OrderRepositoryInterface
     */
    private $orderRepository;

    /**
     * @var ItemExtensionFactory
     */
    private $extensionInterfaceFactory;

    /**
     * @var ResourceConnection
     */
    private $resourceConnection;

    /**
     * @var RmaHelper
     */
    private $rmaHelper;

    /**
     * @var CustomerRepositoryInterface
     */
    private $customerRepository;

    /**
     * @var RmaExtensionInterfaceFactory
     */
    private $rmaExtensionInterfaceFactory;

    /**
     * @var EasyReturnRepositoryInterface
     */
    private $easyReturnRepository;

    /**
     * @var OrderAddressInterfaceFactory
     */
    private $addressInterfaceFactory;
    /**
     * @var EasyReturnHelper
     */
    private $easyReturnHelper;
    /**
     * @var OrderLocator
     */
    private $orderLocator;

    /**
     * AfterGet constructor.
     * @param OrderRepositoryInterface $orderRepository
     * @param ItemExtensionFactory $extensionInterfaceFactory
     * @param ResourceConnection $resourceConnection
     * @param LoggerInterface $logger
     * @param RmaExtensionAttributesRepositoryInterface $rmaExtensionAttributesRepository
     * @param ItemCollectionFactory $itemCollectionFactory
     * @param RmaHelper $rmaHelper
     * @param ProductRepositoryInterface $productRepository
     * @param CustomerRepositoryInterface $customerRepository
     * @param RmaExtensionInterfaceFactory $rmaExtensionInterfaceFactory
     * @param EasyReturnRepositoryInterface $easyReturnRepository
     * @param OrderAddressInterfaceFactory $addressInterfaceFactory
     * @param RmaPoliciesHelper $rmaPoliciesHelper
     * @param EasyReturnHelper $easyReturnHelper
     * @param OrderLocator $orderLocator
     */
    public function __construct(
        OrderRepositoryInterface                  $orderRepository,
        ItemExtensionFactory                      $extensionInterfaceFactory,
        ResourceConnection                        $resourceConnection,
        LoggerInterface                           $logger,
        RmaExtensionAttributesRepositoryInterface $rmaExtensionAttributesRepository,
        ItemCollectionFactory                     $itemCollectionFactory,
        RmaHelper                                 $rmaHelper,
        ProductRepositoryInterface                $productRepository,
        CustomerRepositoryInterface               $customerRepository,
        RmaExtensionInterfaceFactory              $rmaExtensionInterfaceFactory,
        EasyReturnRepositoryInterface             $easyReturnRepository,
        OrderAddressInterfaceFactory              $addressInterfaceFactory,
        RmaPoliciesHelper                         $rmaPoliciesHelper,
        EasyReturnHelper                          $easyReturnHelper,
        OrderLocator                              $orderLocator
    ) {
        $this->orderRepository = $orderRepository;
        $this->extensionInterfaceFactory = $extensionInterfaceFactory;
        $this->resourceConnection = $resourceConnection;
        $this->logger = $logger;
        $this->rmaExtensionAttributesRepository = $rmaExtensionAttributesRepository;
        $this->itemCollectionFactory = $itemCollectionFactory;
        $this->rmaHelper = $rmaHelper;
        $this->productRepository = $productRepository;
        $this->customerRepository = $customerRepository;
        $this->rmaExtensionInterfaceFactory = $rmaExtensionInterfaceFactory;
        $this->easyReturnRepository = $easyReturnRepository;
        $this->addressInterfaceFactory = $addressInterfaceFactory;
        $this->rmaPoliciesHelper = $rmaPoliciesHelper;
        $this->easyReturnHelper = $easyReturnHelper;
        $this->orderLocator = $orderLocator;
    }

    /**
     * @param RmaRepositoryInterface $subject
     * @param RmaInterface $result
     * @return RmaInterface
     */
    public function afterGet(RmaRepositoryInterface $subject, RmaInterface $result)
    {
        try {

            /*
             * FRANCHI-1165
             * Nelle chiamate API per i resi, l'order locator non veniva inizializzato
             * e nel momento in cui veniva fatto il load andava in eccezione
             */
            if (!$this->orderLocator->hasOrder()) {
                $this->orderLocator->setCurrentOrder($result->getOrder());
            }

            // TODO: Find better solution, Duck typing for now ..
            if (method_exists($result, 'setData')) {
                $result->setData('is_easy_return', false);
            }

            $needEnrichment = false;

            if ($result->getItems()) {
                // Check if condition , reason and resolution are set
                foreach ($result->getItems() as $item) {
                    if (!$item->getCondition() || !$item->getResolution() || !$item->getReason()) {
                        $needEnrichment = true;
                        break;
                    }
                }
            }

            // Backward compatibility
            if ($result->getOrderId() && !$result->getItems() || $needEnrichment) {
                $orderItems = $this->orderRepository->get($result->getOrderId())->getItems();
                $tmpItems = [];
                foreach ($orderItems as $orderItem) {
                    $orderItemId = $orderItem->getItemId();
                    $tmpItems = $tmpItems + $this->itemCollectionFactory->create()->addFieldToSelect('*')
                            ->addFieldToFilter('order_item_id', $orderItemId)
                            ->addFieldToFilter('rma_entity_id', $result->getEntityId())
                            ->getItems();
                }
                $rmaItems = $tmpItems;
                $result->setItems($rmaItems);
            } else {
                $rmaItems = $result->getItems();
            }

            $mappedResolutions = $this->rmaHelper->getRmaMappedResolutions();

            foreach ($rmaItems as $rmaItem) {
                $attributes = $rmaItem->getExtensionAttributes();
                if ($attributes === null) {
                    /** @var ItemExtensionFactory $attributes */
                    $attributes = $this->extensionInterfaceFactory->create();
                }

                // Sku
                $productSku = $rmaItem->getProductSku();
                $attributes->setSku($productSku);

                $weight = 0;

                if ($this->easyReturnHelper->isABundleSku($rmaItem->getOrderItemId())) {
                    $bundleSku = $this->easyReturnHelper->getBundleSku($rmaItem->getOrderItemId());

                    $skus = $this->easyReturnHelper->resolveBundleSkus($bundleSku, $productSku);

                    if (is_array($skus)) {
                        foreach ($skus as $sku) {
                            $weight += $rmaItem->getQtyRequested() * $this->productRepository->get($sku)->getWeight();
                        }
                        continue;
                    }

                    $productSku = $skus;
                } else {
                    $product = $this->productRepository->get($rmaItem->getProductSku());
                    $weight = $this->getProductWeight($product, $attributes, $rmaItem);
                }

                $attributes->setWeight($weight);

                if ($changeSizeOrderId = $this->rmaExtensionAttributesRepository->getChangeSizeOrderId($rmaItem->getEntityId())) {
                    // Change size order id
                    $attributes->setChangeSizeOrderId($changeSizeOrderId);
                    $changeSizeOrder = $this->orderRepository->get($changeSizeOrderId);
                    // Change size increment id
                    $attributes->setChangeSizeOrderIncrementId($changeSizeOrder->getIncrementId());
                    foreach ($changeSizeOrder->getItems() as $item) {
                        // Change size sku
                        $attributes->setChangeSizeSku($item->getSku());
                    }
                }

                // Standard reason
                if ($rmaItem->getReason() !== null) {
                    $attributes->setStandardReason($this->getStandardReasonByReasonId($rmaItem->getReason()));
                }

                $currentResolution = (int)$rmaItem->getResolution();

                if (isset($mappedResolutions[$currentResolution])) {
                    $attributes->setStandardResolution($mappedResolutions[$currentResolution]);
                }

                $attributes->setBrandReason('');

                $ibanForReturn = null;

                if (!empty($rmaItem->getData('iban_for_return'))) {
                    $attributes->setIbanForReturn($rmaItem->getData('iban_for_return'));
                    $ibanForReturn = $rmaItem->getData('iban_for_return');
                }

                foreach ($this->rmaHelper->getWrongSizeMapping() as $magentoReason => $brandReason) {
                    if ($magentoReason == $rmaItem->getReason()) {
                        $attributes->setBrandReason($brandReason);
                    }
                }

                // Save extension attributes
                $rmaItem->setExtensionAttributes($attributes);
            }

            $rmaAttributes = $result->getExtensionAttributes();
            if ($rmaAttributes === null) {
                /** @var RmaExtensionInterfaceFactory $rmaAttributes */
                $rmaAttributes = $this->rmaExtensionInterfaceFactory->create();
            }

            if ($result->getOrderId()) {
                $order = $this->orderRepository->get($result->getOrderId());

                //ext_order_id
                $rmaAttributes->setExtOrderId($order->getExtOrderId());

                //customer_firstname
                $rmaAttributes->setCustomerFirstname($order->getCustomerFirstname());

                //customer_lastname
                $rmaAttributes->setCustomerLastname($order->getCustomerLastname());
            }

            //theoric shipping amount
            if ($result->getEntityId()) {
                $returnType = $this->rmaPoliciesHelper->check($result);

                $shippingAmount = $this->getTheoricShippingAmount($result->getEntityId());

                if ($returnType == 'free_return') {
                    $pickUpAddress = $this->getPickupAddress($result);
                    $shippingAmount = $this->easyReturnHelper->simulateEasyReturnShippingCost(
                        $pickUpAddress,
                        $result->getOrder()->getStore(),
                        $result->getOrder()->getWeight(),
                        $result->getOrder()->getGrandTotal()
                    );
                }

                if ($shippingAmount != '') {
                    $rmaAttributes->setTheoricShippingAmount($shippingAmount);
                }

                //easy_return
                $easyReturn = $this->getEasyReturn($result->getEntityId());
                $rmaAttributes->setEasyReturn($easyReturn);

                //pickup Address
                if ($easyReturn) {
                    $pickUpAddress = $this->getPickupAddress($result);
                    $rmaAttributes->setPickupAddress($pickUpAddress);
                    // TODO: Find better solution, Duck typing for now ..
                    if (method_exists($result, 'setData')) {
                        $result->setData('is_easy_return', true);
                    }
                }

                $rmaAttributes->setReturnType($returnType);

                if (!empty($ibanForReturn)) {
                    $rmaAttributes->setIbanForReturn($ibanForReturn);
                }
            }

            //save
            $result->setExtensionAttributes($rmaAttributes);

            return $result;
        } catch (Exception $exception) {
            $this->logger->critical($exception->getMessage(), ['exception' => $exception]);
            return $result;
        } catch (Throwable $throwable) {
            $this->logger->critical($throwable->getMessage(), ['exception' => $throwable]);
            return $result;
        }
    }

    public function getProductWeight($product, $attributes, $rmaItem)
    {
        // Barcode
        $productBarcode = $product->getBarcode();
        $attributes->setBarcode($productBarcode);

        // Name
        $productName = $rmaItem->getProductName();
        $attributes->setName($productName);

        // Weight
        return $product->getWeight();
    }

    /**
     * @param int $reasonId
     * @return string
     */
    public function getStandardReasonByReasonId(int $reasonId)
    {
        $rmaReasonId = $reasonId;

        if ($this->rmaHelper->checkIfItIsMapped($rmaReasonId)) {
            $standardReason = $this->rmaHelper->getMappedReasonByReasonId($rmaReasonId, 'brand');
            if ($standardReason) {
                return $standardReason[0];
            } else {
                return '';
            }
        }

        return '';
    }

    /**
     * @param int $rmaId
     * @return string
     */
    protected function getTheoricShippingAmount(int $rmaId)
    {
        if ($rmaId) {
            return $this->easyReturnRepository->getByRmaId($rmaId)
                                              ->getTheoricShippingAmount();
        }
        return '';
    }

    /**
     * @param RmaInterface $rma
     * @return OrderAddressInterface
     */
    protected function getPickupAddress(RmaInterface $rma)
    {
        if ($this->getEasyReturn($rma->getEntityId())) {
            $address = $this->easyReturnRepository->getByRmaId($rma->getEntityId())
                                              ->getPickUpAddress();

            if (empty($address->getFirstname() && $address->getLastname())) {
                $order = $rma->getOrder();

                $address = $this->easyReturnHelper->fillPickupAddressByOrderShippingAddress($address, $order->getShippingAddress());

            }

            return $address;
        }

        return $this->addressInterfaceFactory->create();
    }

    /**
     * @param int $rmaId
     * @return bool
     */
    protected function getEasyReturn(int $rmaId)
    {
        if ($rmaId) {
            $easyReturn = $this->easyReturnRepository->getByRmaId($rmaId);
            return (bool)$easyReturn->getId();
        }
        return false;
    }

    /**
     * @param \Magento\Rma\Api\RmaRepositoryInterface $subject
     * @param \Magento\Rma\Api\Data\RmaSearchResultInterface $result
     * @return \Magento\Rma\Api\Data\RmaSearchResultInterface
     */
    public function afterGetList(RmaRepositoryInterface $subject, RmaSearchResultInterface $result)
    {
        foreach ($result->getItems() as $rma) {
            $ibanForReturn = null;
            foreach ($rma->getItems() as $rmaItem) {

                if(!$rmaItem->getExtensionAttributes()){
                    continue;
                }

                if (!empty($rmaItem->getData('iban_for_return'))) {
                    $rmaItem->getExtensionAttributes()->setIbanForReturn($rmaItem->getData('iban_for_return'));
                    $ibanForReturn = $rmaItem->getData('iban_for_return');
                }
            }

            if(!$rma->getExtensionAttributes()){
                continue;
            }

            $rma->getExtensionAttributes()->setIbanForReturn($ibanForReturn);
        }

        return $result;
    }
}
