<?php
namespace Autogedal\AutogedalHelper\Plugin;

use Magento\Backend\Model\Session\Quote;
use Magento\Framework\DataObject\Copy;
use Magento\Framework\Event\ManagerInterface;
use Magento\Quote\Api\CartRepositoryInterface;
use Magento\Sales\Model\Order;
use Magento\Sales\Api\Data\OrderAddressInterface;
use Magento\Framework\Api\ExtensibleDataObjectConverter;
use Magento\Sales\Model\AdminOrder\Create;

class AdminOrderCreate{

    protected $_session;
    protected $quoteRepository;
    protected $objectCopyService;
    protected $_eventManager = null;
    private $dataObjectConverter;
    protected $adminCreate;
    protected $_quote;

    private Copy $_objectCopyService;

    public function __construct(
        Quote $quoteSession,
        CartRepositoryInterface $quoteRepository,
        Copy $objectCopyService,
        ManagerInterface $eventManager,
        ExtensibleDataObjectConverter $dataObjectConverter,
        Create $adminCreate
    ) {
        $this->_session = $quoteSession;
        $this->quoteRepository = $quoteRepository;
        $this->_objectCopyService = $objectCopyService;
        $this->_eventManager = $eventManager;
        $this->dataObjectConverter = $dataObjectConverter;
        $this->adminCreate = $adminCreate;
    }

    public function afterGetQuote(Create $order, $result)
    {
        $orderSource = $order->getData('autogedal_order_source');
        if (empty($result->getData('autogedal_order_source')) && !empty($orderSource)) {
            $result->setData('autogedal_order_source', $orderSource);
        }

        $orderAgent = $order->getData('autogedal_operator_id');
        if (empty($result->getData('autogedal_operator_id')) && !empty($orderAgent)) {
            $result->setData('autogedal_operator_id', $orderAgent);
        }

        return $result;
    }

    public function aroundInitFromOrder(Create $subject, $result, Order $order)
    {
        $session = $this->getSession();
        $session->setData($order->getReordered() ? 'reordered' : 'order_id', $order->getId());
        $session->setCurrencyId($order->getOrderCurrencyCode());
        /* Check if we edit guest order */
        $session->setCustomerId($order->getCustomerId() ?: false);
        $session->setStoreId($order->getStoreId());
        if ($session->getData('reordered')) {
            $this->getQuote()->setCustomerGroupId($order->getCustomerGroupId());
        }

        /* Initialize catalog rule data with new session values */
        $subject->initRuleData();

        $salesConfig = ['simple','virtual','configurable','downloadable','grouped','bundle'];
        foreach ($order->getItemsCollection($salesConfig, true) as $orderItem) {
            /* @var $orderItem \Magento\Sales\Model\Order\Item */
            if (!$orderItem->getParentItem()) {
                $qty = $orderItem->getQtyOrdered();

                if ($qty > 0) {
                    $item = $subject->initFromOrderItem($orderItem, $qty);
                    if (is_string($item)) {
                        throw new \Magento\Framework\Exception\LocalizedException(__($item));
                    }
                }
            }
        }

        $shippingAddress = $order->getShippingAddress();

        if ($shippingAddress) {
            $shippingAddress->setSameAsBilling($this->isAddressesAreEqual($order));
        }

        $this->_initBillingAddressFromOrder($order);
        $this->_initShippingAddressFromOrder($order);

        $quote = $this->getQuote();


        if (!$quote->isVirtual() && $subject->getShippingAddress()->getSameAsBilling()) {
            $quote->getBillingAddress()->setCustomerAddressId(
                $quote->getShippingAddress()->getCustomerAddressId()
            );
            $subject->setShippingAsBilling(1);
        }

        $subject->setShippingMethod($order->getShippingMethod());
        $quote->getShippingAddress()->setShippingDescription($order->getShippingDescription());

        $orderCouponCode = $order->getCouponCode();
        if ($orderCouponCode) {
            $quote->setCouponCode($orderCouponCode);
        }

        if ($quote->getCouponCode()) {
            $quote->collectTotals();
        }

        $this->_objectCopyService->copyFieldsetToTarget('sales_copy_order', 'to_edit', $order, $quote);

        $this->_eventManager->dispatch('sales_convert_order_to_quote', ['order' => $order, 'quote' => $quote]);

        if (!$order->getCustomerId()) {
            $quote->setCustomerIsGuest(true);
        }

        if ($session->getUseOldShippingMethod(true)) {
            /*
             * if we are making reorder or editing old order
             * we need to show old shipping as preselected
             * so for this we need to collect shipping rates
             */
            $subject->collectShippingRates();
        } else {
            /*
             * if we are creating new order then we don't need to collect
             * shipping rates before customer hit appropriate button
             */
            $subject->collectRates();
        }

        $quote->getShippingAddress()->unsCachedItemsAll();
        $quote->getBillingAddress()->unsCachedItemsAll();
        $quote->setTotalsCollectedFlag(false);

        $this->quoteRepository->save($quote);

        return $result;
    }

    /**
     * Retrieve session model object of quote
     *
     * @return Quote
     */
    public function getSession()
    {
        return $this->_session;
    }

    public function getQuote()
    {
        if (!$this->_quote) {
            $this->_quote = $this->getSession()->getQuote();
        }

        return $this->_quote;
    }

    public function setQuote(\Magento\Quote\Model\Quote $quote)
    {
        $this->_quote = $quote;
        return $this;
    }

    /**
     * Copy billing address from order
     *
     * @param \Magento\Sales\Model\Order $order
     * @return void
     */
    protected function _initBillingAddressFromOrder(\Magento\Sales\Model\Order $order)
    {
        $this->getQuote()->getBillingAddress()->setCustomerAddressId('');
        $this->_objectCopyService->copyFieldsetToTarget(
            'sales_copy_order_billing_address',
            'to_order',
            $order->getBillingAddress(),
            $this->getQuote()->getBillingAddress()
        );
    }

    /**
     * Copy shipping address from order
     *
     * @param \Magento\Sales\Model\Order $order
     * @return void
     */
    protected function _initShippingAddressFromOrder(\Magento\Sales\Model\Order $order)
    {
        $orderShippingAddress = $order->getShippingAddress();
        $quoteShippingAddress = $this->getQuote()->getShippingAddress()->setCustomerAddressId(
            ''
        )->setSameAsBilling(
            $orderShippingAddress && $orderShippingAddress->getSameAsBilling()
        );
        $this->_objectCopyService->copyFieldsetToTarget(
            'sales_copy_order_shipping_address',
            'to_order',
            $orderShippingAddress,
            $quoteShippingAddress
        );
    }

    /**
     * Checks id shipping and billing addresses are equal.
     *
     * @param Order $order
     * @return bool
     */
    private function isAddressesAreEqual(Order $order)
    {
        $shippingAddress = $order->getShippingAddress();
        $billingAddress = $order->getBillingAddress();
        $shippingData = $this->dataObjectConverter->toFlatArray($shippingAddress, [], OrderAddressInterface::class);
        $billingData = $this->dataObjectConverter->toFlatArray($billingAddress, [], OrderAddressInterface::class);
        unset(
            $shippingData['address_type'],
            $shippingData['entity_id'],
            $billingData['address_type'],
            $billingData['entity_id']
        );

        return $shippingData == $billingData;
    }
}