<?php

namespace FiloBlu\Esb\Model\Loader;

use FiloBlu\Esb\Api\Data\ObjectTypeDescriptorInterface;
use FiloBlu\Esb\Api\Data\ObjectTypeInterface;
use FiloBlu\Esb\Helper\LoggerProvider;
use Magento\Catalog\Model\ProductFactory;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Framework\Phrase;
use Magento\Framework\Serialize\SerializerInterface;
use Magento\Sales\Api\Data\OrderItemExtensionFactory;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\ResourceModel\Order\Tax\ItemFactory;
use Magento\Store\Model\ScopeInterface;

/**
 * Class OrderEnrichedLoader
 * @package FiloBlu\Esb\Model\Loader
 */
class OrderEnrichedLoader extends OrderLoader
{
    /**
     * @var ScopeConfigInterface
     */
    protected $_scopeConfig;

    /**
     * @var ProductFactory
     */
    protected $_productFactory;

    /**
     * @var \Magento\Sales\Model\Order\ItemFactory
     */
    protected $_orderItemFactory;

    /**
     * @var OrderItemExtensionFactory
     */
    protected $_itemExtensionFactory;

    /**
     * @var \Magento\Sales\Model\Order\ItemFactory
     */
    protected $_orderItemTaxFactory;

    /**
     * @var \FiloBlu\Esb\Helper\SerializerHelper
     */
    protected $_serializer;

    /**
     * @var Logger
     */
    protected $_logger;

    protected $loaded;

    /**
     * OrderEnrichedLoader constructor
     *
     * @param OrderRepositoryInterface $orderRepository
     * @param ObjectTypeDescriptorInterface $objectTypeDescriptor
     * @param \FiloBlu\Esb\Helper\SerializerHelper $serializer
     * @param ScopeConfigInterface $scopeConfig
     * @param ProductFactory $productFactory
     * @param \Magento\Sales\Model\Order\ItemFactory $orderItemFactory
     * @param OrderItemExtensionFactory $itemExtensionFactory
     * @param ItemFactory $orderItemTaxFactory
     * @param LoggerProvider $loggerProvider
     */
    public function __construct(
        OrderRepositoryInterface $orderRepository,
        ObjectTypeDescriptorInterface $objectTypeDescriptor,
        \FiloBlu\Esb\Helper\SerializerHelper $serializer,
        ScopeConfigInterface $scopeConfig,
        ProductFactory $productFactory,
        \Magento\Sales\Model\Order\ItemFactory $orderItemFactory,
        OrderItemExtensionFactory $itemExtensionFactory,
        ItemFactory $orderItemTaxFactory,
        LoggerProvider $loggerProvider
    ) {
        parent::__construct($orderRepository, $objectTypeDescriptor);
        $this->_serializer = $serializer;
        $this->_scopeConfig = $scopeConfig;
        $this->_productFactory = $productFactory;
        $this->_orderItemFactory = $orderItemFactory;
        $this->_itemExtensionFactory = $itemExtensionFactory;
        $this->_orderItemTaxFactory = $orderItemTaxFactory;
        $this->_logger = $loggerProvider->getLogger();
        $this->loaded=false;
    }

    /**
     * @inheritDoc
     */
    public function get(ObjectTypeInterface $objectType)
    {
        $order = parent::get($objectType);
        return $this->addGiftWrapProduct($order);
    }

    /**
     * If gift wrap is selected, add linked product to order, see config esb/gwmapping/gwproducts
     *
     * @param OrderRepositoryInterface $order
     * @return OrderRepositoryInterface|$order
     * @throws NoSuchEntityException
     */

    protected function addGiftWrapProduct($order)
    {
        $products = $this->_serializer->unserialize($this->_scopeConfig->getValue(
            'esb/gwmapping/gwproducts',
            ScopeInterface::SCOPE_STORE,
            $order->getStoreId()
        ));

        if (empty($products)) {
            return $order;
        }

        if($this->loaded){
            return $order;
        }

        if ($order->getGwId()) {
            $productSku = null;
            foreach ($products as $productData) {
                if ($productData['wrapping_id'] === '*' || $productData['wrapping_id'] == $order->getGwId()) {
                    $productSku = $productData['product_sku'];
                    break;
                }
            }


            $product = $this->_productFactory->create()->loadByAttribute('sku', $productSku);
            if($product!==false){
                $giftOrderItem = $this->_orderItemFactory->create();

                $giftOrderItem->setProductId($product->getId());
                $giftOrderItem->setSku($product->getSku());
                $giftOrderItem->setName($product->getName());
                $giftOrderItem->setQtyOrdered(1);
                $giftOrderItem->setQtyInvoiced(1);
                $giftOrderItem->setProductType($product->getTypeId());
                $giftOrderItem->setBasePrice($order->getGwBasePrice());
                $giftOrderItem->setPrice($order->getGwPrice());
                $giftOrderItem->setBasePriceInclTax($order->getGwBasePriceInclTax());
                $giftOrderItem->setPriceInclTax($order->getGwPriceInclTax());
                $giftOrderItem->setBaseTaxAmount($order->getGwBaseTaxAmount());
                $giftOrderItem->setTaxAmount($order->getGwTaxAmount());
                $giftOrderItem->setTaxInvoiced($order->getGwTaxAmount());
                $giftOrderItem->setBaseRowInvoiced($order->getGwBasePrice());
                $giftOrderItem->setBaseRowTotal($order->getGwBasePrice());
                $giftOrderItem->setRowTotal($order->getGwBasePrice());
                $giftOrderItem->setBaseRowTotalInclTax($order->getGwBasePriceInclTax());

                $itemTax = $this->_orderItemTaxFactory->create()->getTaxItemsByOrderId($order->getId());
                $percent = 0;
                foreach ($itemTax as $tax) {
                    if ($tax['taxable_item_type'] === 'quote_gw') {
                        $percent = $tax['tax_percent'];
                        break;
                    }
                }
                $giftOrderItem->setTaxPercent($percent);
                $giftOrderItem->setBaseAmountRefunded('0.0000');
                $giftOrderItem->setBaseDiscountAmount('0.0000');
                $giftOrderItem->setBaseDiscountTaxCompensationAmount('0.0000');
                $giftOrderItem->setBaseDiscountTaxCompensationInvoiced('0.0000');
                $giftOrderItem->setDiscountAmount('0.0000');
                $giftOrderItem->setDiscountInvoiced('0.0000');
                $giftOrderItem->setDiscountPercent('0.0000');

                $extensionAttributes = $this->_itemExtensionFactory->create();
                $extensionAttributes->setData('kpi_full_price', $order->getGwBasePriceInclTax());
                $giftOrderItem->setExtensionAttributes($extensionAttributes);

                $order->addItem($giftOrderItem);
                $this->loaded=true;
            }else{
                $message = __('Cannot find product for gift wrap mapping: %1',$productSku);
                $this->_logger->critical($message->render());
                throw new NoSuchEntityException(new Phrase($message->render()));
            }
        }

        $orderItems = $order->getItems();
        foreach ($orderItems as $orderItem) {
            if ($orderItem->getGwId()) {
                $productSku = null;
                foreach ($products as $productData) {
                    if ($productData['wrapping_id'] === '*' || $productData['wrapping_id'] == $orderItem->getGwId()) {
                        $productSku = $productData['product_sku'];
                        break;
                    }
                }

                $product = $this->_productFactory->create()->loadByAttribute('sku', $productSku);
                if($product!==false){
                    $giftOrderItem = $this->_orderItemFactory->create();

                    $giftOrderItem->setProductId($product->getId());
                    $giftOrderItem->setSku($product->getSku());
                    $giftOrderItem->setName($product->getName() . ' (pack for ' . $orderItem->getSku() . ')');
                    $giftOrderItem->setQtyOrdered(1);
                    $giftOrderItem->setQtyInvoiced(1);
                    $giftOrderItem->setProductType($product->getTypeId());
                    $giftOrderItem->setBasePrice($orderItem->getGwBasePrice());
                    $giftOrderItem->setPrice($orderItem->getGwPrice());
                    $giftOrderItem->setBasePriceInclTax($orderItem->getGwBasePrice() + $orderItem->getGwBaseTaxAmount());
                    $giftOrderItem->setPriceInclTax($orderItem->getGwPrice() + $orderItem->getGwTaxAmount());
                    $giftOrderItem->setBaseTaxAmount($orderItem->getGwBaseTaxAmount());
                    $giftOrderItem->setTaxAmount($orderItem->getGwTaxAmount());
                    $giftOrderItem->setTaxInvoiced($orderItem->getGwTaxAmount());
                    $giftOrderItem->setBaseRowInvoiced($orderItem->getGwBasePrice());
                    $giftOrderItem->setBaseRowTotal($orderItem->getGwBasePrice());
                    $giftOrderItem->setRowTotal($orderItem->getGwBasePrice());
                    $giftOrderItem->setBaseRowTotalInclTax($orderItem->getGwBasePrice() + $orderItem->getGwBaseTaxAmount());

                    $itemTax = $this->_orderItemTaxFactory->create()->getTaxItemsByOrderId($order->getId());
                    $percent = 0;
                    foreach ($itemTax as $tax) {
                        if ($tax['taxable_item_type'] === 'item_gw' && (int)$tax['associated_item_id'] === $orderItem->getId()) {
                            $percent = $tax['tax_percent'];
                            break;
                        }
                    }
                    $giftOrderItem->setTaxPercent($percent);
                    $giftOrderItem->setBaseAmountRefunded('0.0000');
                    $giftOrderItem->setBaseDiscountAmount('0.0000');
                    $giftOrderItem->setBaseDiscountTaxCompensationAmount('0.0000');
                    $giftOrderItem->setBaseDiscountTaxCompensationInvoiced('0.0000');
                    $giftOrderItem->setDiscountAmount('0.0000');
                    $giftOrderItem->setDiscountInvoiced('0.0000');
                    $giftOrderItem->setDiscountPercent('0.0000');

                    $extensionAttributes = $this->_itemExtensionFactory->create();
                    $extensionAttributes->setData('kpi_full_price', $orderItem->getGwBasePriceInclTax());
                    $extensionAttributes->setData('packed_sku', $orderItem->getSku());
                    $giftOrderItem->setExtensionAttributes($extensionAttributes);

                    $order->addItem($giftOrderItem);
                }else{
                    $message = __('Cannot find product for gift wrap mapping: %1',$productSku);
                    $this->_logger->critical($message->render());
                    throw new NoSuchEntityException(new Phrase($message->render()));
                }
            }
        }

        return $order;
    }

    /**
     * @inheritDoc
     */
    public function getName(): string
    {
        return 'Enriched Order Loader';
    }

    /**
     * @inheritDoc
     */
    public function getUniqueName(): string
    {
        return 'FiloBlu_Esb::order_enriched_loader';
    }
}
