<?php

namespace Leadlion\SalesOrder\Model;

use Exception;
use Magento\Backend\Model\Session\Quote as QuoteSession;
use Magento\Bundle\Model\Product\Type as BundleProductType;
use Magento\Catalog\Api\ProductRepositoryInterface;
use Magento\Catalog\Model\Product\Type;
use Magento\Catalog\Model\Product\Type as ProductType;
use Magento\CatalogInventory\Api\Data\StockItemInterface;
use Magento\CatalogInventory\Api\StockRegistryInterface;
use Magento\Checkout\Model\Session as CheckoutSession;
use Magento\ConfigurableProduct\Model\Product\Type\Configurable as Configurable;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\Exception\InputException;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException as NoSuchEntityException;
use Magento\Framework\Model\AbstractModel;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\InventoryConfigurationApi\Exception\SkuIsNotAssignedToStockException;
use Magento\InventoryReservationsApi\Model\ReservationInterface;
use Magento\InventorySalesApi\Model\GetStockItemDataInterface;
use Magento\Quote\Model\Quote\Item;
use Magento\Quote\Model\Quote\ItemFactory as QuoteItemFactory;
use Magento\Quote\Model\QuoteFactory;
use Magento\Quote\Model\QuoteManagement;
use Magento\Sales\Api\OrderManagementInterface as OrderManagement;
use Magento\Sales\Api\OrderRepositoryInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Model\Order\ItemFactory as OrderItemFactory;
use Magento\Sales\Model\OrderFactory;
use Magento\Sales\Model\ResourceModel\Order\Item\CollectionFactory as OrderItemCollectionFactory;
use Magento\Sales\Model\ResourceModel\Order\Tax\Item as TaxItem;
use Mageplaza\EditOrder\Helper\Data;
use Mageplaza\EditOrder\Helper\Data as HelperData;
use Mageplaza\EditOrder\Model\PreviousCartFactory as PreviousCartFactory;
use Psr\Log\LoggerInterface;

class ItemComparison extends \Mageplaza\EditOrder\Model\ItemComparison
{
     /**
     * @param $order
     *
     * @return array|array[]
     * @throws Exception
     */
    public function reSetUpdateOrder($order)
    {
        $quoteId         = $this->quoteSession->getQuoteId();
        $quote           = $this->quoteFactory->create()->load($quoteId);
        $diffItemInQuote = $this->compareItemsInQuote($quote, $order);
        $previousCart    = $this->previousCartFactory->create();
        $oldItemOrder    = $previousCart->getItemIdOrderByOrderId($order->getId());

        if ($diffItemInQuote[self::REMOVE_ITEMS] && !empty($diffItemInQuote[self::REMOVE_ITEMS])) {
            $removeItem = [];
            foreach ($diffItemInQuote[self::REMOVE_ITEMS] as $item) {
                $removeItem[] = $item['item_id'];
            }
            $this->removeQuoteItemsToOrder($order, $removeItem, $oldItemOrder);
        }
        
        if ($diffItemInQuote[self::NEW_ITEMS] && !empty($diffItemInQuote[self::NEW_ITEMS])) {
            $this->addQuoteItemsToOrder($order, $quote, $diffItemInQuote[self::REMOVE_ITEMS]);
        }

        //set quote id by orderRepository
        $order->setQuoteId($quoteId);
        $this->orderRepository->save($order);

        return $diffItemInQuote;
    }

    /**
     * @param $order
     * @param $removeItem
     * @param $oldItemOrder
     *
     * @return $this
     * @throws Exception
     */
    public function removeQuoteItemsToOrder($order, $removeItem, $oldItemOrder)
    {
        foreach ($order->getAllItems() as $orderItem) {
            // if (in_array($orderItem->getQuoteItemId(), $oldItemOrder) ||
            //     in_array($orderItem->getQuoteItemId(), $removeItem)) {
                $this->changeStockProduct($order, $orderItem, true);
                $orderItem->isDeleted(true);
            //}
        }
        $this->orderRepository->save($order);

        return $this;
    }

     /**
     * @param $order
     * @param $quote
     * @param $removedItems
     *
     * @return $this
     * @throws InputException
     * @throws LocalizedException
     * @throws NoSuchEntityException
     * @throws SkuIsNotAssignedToStockException
     */
    public function addQuoteItemsToOrder($order, $quote, $removedItems)
    {
        $parentItemId             = null;
        $parentProductId          = null;
        $qtyOrder                 = null;
        $taxPercent               = null;
        $quoteParentItem          = null;
        $updateAfterEditingConfig = (int) $this->_helperData->getUpdateAfterEditing()[0];
        $skuList                  = array_column($removedItems, 'sku');
        foreach ($quote->getAllItems() as $quoteItem) {
            $orderItem = $this->orderItemFactory->create();
            if (!$this->checkStockBackOrder($quoteItem) && !in_array(
                $quoteItem->getProduct()->getSku(),
                $skuList
            ) && $quoteItem->getProductType() != ProductType::TYPE_BUNDLE) {
                continue;
            }
            foreach ($quoteItem->getData() as $key => $dataItem) {
                if (!in_array($key, ['item_id', 'parent_item'])) {
                    if ($updateAfterEditingConfig === 0) {
                        $qty_invoiced = $orderItem->getQtyInvoiced();
                        $qty_shipped  = $orderItem->getQtyShipped();
                        $qty_refunded = $orderItem->getQtyRefunded();
                        $orderItem->setData($key, $quoteItem->getData($key));
                        $orderItem->setQtyInvoiced($qty_invoiced);
                        $orderItem->setQtyShipped($qty_shipped);
                        $orderItem->setQtyRefunded($qty_refunded);
                    } else {
                        $orderItem->setData($key, $quoteItem->getData($key));
                    }
                }
            }
            $originalPrice = $quoteItem->getProduct()->getPrice();
            $orderItem->setOriginalPrice($this->priceCurrency->convert($originalPrice, $order->getOrderCurrencyCode()));
            $orderItem->setBaseOriginalPrice($originalPrice);
            $orderItem->setQtyOrdered($this->getCustomQty($quoteItem, $order));
            $orderItem->setOrderId($order->getId())
                ->setQuoteItemId($quoteItem->getItemId())
                ->setStoreId($order->getStoreId());
            $productOptions = $quoteItem->getProduct()->getTypeInstance(true)
                ->getOrderOptions($quoteItem->getProduct()) ?? [];

            //get option child in the product bundle
            if ($quoteItem->getOptionByCode('bundle_selection_attributes')) {
                $bundle_selection_attributes = $quoteItem->getOptionByCode('bundle_selection_attributes')
                   ? json_decode($quoteItem->getOptionByCode('bundle_selection_attributes')->getValue(), true)
                   : [];
                $productOptions['bundle_selection_attributes'] = json_encode($bundle_selection_attributes);
            }

            $orderItem->setProductOptions($productOptions);
            $orderItem->setData('quote_item_id', $quoteItem->getId());
            $orderItem->setData('quote_id', $quoteItem->getQuoteId());

            if ($quoteItem->getProductType() === Configurable::TYPE_CODE ||
                $quoteItem->getProductType() === ProductType::TYPE_BUNDLE) {
                $quoteParentItem = $quoteItem->getItemId();
                $order->addItem($orderItem);

                $this->orderRepository->save($order);
                $parentItemId    = $orderItem->getItemId();
                $parentProductId = $orderItem->getProductId();

                $taxPercent = $orderItem->getTaxPercent();
                $qtyOrder   = $orderItem->getQtyOrdered();

            } else {
                if ($quoteParentItem === $quoteItem->getParentItemId() &&
                    $quoteItem->getParentItemId()) {

                    $discountAmount        = $quoteItem->getDiscountAmount();
                    $subtotalAfterDiscount = ($quoteItem->getProduct()->getPrice() * $quoteItem->getQty() * $qtyOrder) - $discountAmount;
                    $taxAmount             = $subtotalAfterDiscount * ($taxPercent / 100);

                    $orderItem->setTaxPercent($taxPercent);
                    $orderItem->setTaxAmount($taxAmount);
                    $orderItem->setParentItemId($parentItemId);
                }

                // Add the order item to the order
                $order->addItem($orderItem);
                $this->changeStockProduct($order, $orderItem, false);
            }
        }
        $this->orderRepository->save($order);

        return $this;
    }
}