<?php
/**
 * Mageplaza
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Mageplaza.com license that is
 * available through the world-wide-web at this URL:
 * https://www.mageplaza.com/LICENSE.txt
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade this extension to newer
 * version in the future.
 *
 * @category  Mageplaza
 * @package   Mageplaza_EditOrder
 * @copyright Copyright (c) Mageplaza (https://www.mageplaza.com/)
 * @license   https://www.mageplaza.com/LICENSE.txt
 */

namespace Mageplaza\EditOrder\Plugin\Model\Quote\Item;

use Exception;
use Magento\Framework\App\RequestInterface;
use Magento\Framework\Message\ManagerInterface;
use Magento\Quote\Model\Quote\Item;
use Magento\Quote\Model\Quote\Item\AbstractItem;
use Magento\Sales\Block\Adminhtml\Order\Create\Items\Grid;
use Magento\Store\Model\Store;
use Magento\Tax\Api\Data\QuoteDetailsItemInterfaceFactory;
use Magento\Tax\Api\Data\TaxDetailsItemInterface;
use Magento\Tax\Model\Config as ConfigTax;
use Magento\Tax\Model\Sales\Total\Quote\CommonTaxCollector;
use Mageplaza\EditOrder\Helper\Data as HelperData;
use Mageplaza\EditOrder\Model\Tax\CalculationFactory;

class CustomTax
{
    /**
     * @var RequestInterface
     */
    protected $_request;

    /**
     * @var HelperData
     */
    protected $_helperData;

    /**
     * @var ManagerInterface
     */
    protected $_messageManager;

    /**
     * @var bool
     */
    protected $_isError = false;

    /**
     * @var ConfigTax
     */
    protected $config;

    /**
     * @var Grid
     */
    protected $grid;
    /**
     * @var CalculationFactory
     */
    private $taxCalculation;

    /**
     * @var QuoteDetailsItemInterfaceFactory
     */
    private $quoteDetailsItemInterfaceFactory;

    /**
     * CustomTax constructor.
     *
     * @param RequestInterface $request
     * @param HelperData $helperData
     * @param ManagerInterface $messageManager
     * @param ConfigTax $config
     * @param Grid $grid
     * @param QuoteDetailsItemInterfaceFactory $quoteDetailsItemInterfaceFactory
     * @param CalculationFactory $taxCalculation
     */
    public function __construct(
        RequestInterface $request,
        HelperData $helperData,
        ManagerInterface $messageManager,
        ConfigTax $config,
        Grid $grid,
        QuoteDetailsItemInterfaceFactory $quoteDetailsItemInterfaceFactory,
        CalculationFactory $taxCalculation
    ) {
        $this->_request                         = $request;
        $this->_helperData                      = $helperData;
        $this->_messageManager                  = $messageManager;
        $this->config                           = $config;
        $this->grid                             = $grid;
        $this->quoteDetailsItemInterfaceFactory = $quoteDetailsItemInterfaceFactory;
        $this->taxCalculation                   = $taxCalculation;
    }

    /**
     * Recalculate custom tax
     *
     * @param CommonTaxCollector $subject
     * @param AbstractItem $quoteItem
     * @param TaxDetailsItemInterface $itemTaxDetails
     * @param TaxDetailsItemInterface $baseItemTaxDetails
     * @param Store $store
     *
     * @return array
     */
    public function beforeUpdateItemTaxInfo(
        CommonTaxCollector $subject,
        $quoteItem,
        $itemTaxDetails,
        $baseItemTaxDetails,
        $store
    ) {
        $request = $this->_request->getParams();
        if (!$this->_helperData->isMpEdit() || !isset($request['item'])) {
            return [$quoteItem, $itemTaxDetails, $baseItemTaxDetails, $store];
        }
        [$itemTaxDetails, $baseItemTaxDetails] = $this->updateTaxCalCustomPrice(
            $quoteItem,
            $itemTaxDetails,
            $baseItemTaxDetails
        );
        $order       = $this->_helperData->quoteSession->getOrder();
        $orderStatus = $order ? $order->getStatus() : 'mp_disable';
        if (!$this->_helperData->isEnabled($store->getStoreId())
            || !$this->isCustomTax($request, $quoteItem)
            || !in_array($orderStatus, $this->_helperData->getEditableOrderStatus())) {
            $tax = $itemTaxDetails->getTaxPercent();

            if ($quoteItem->getParentItem() && $quoteItem->getParentItem()->getProductType() === 'bundle') {
                $requestItem = $this->getRequestItem($request['item'], $quoteItem->getParentItem()->getId());
                $customTax   = (float) $requestItem['custom_tax'];

                return $this->calculationTax($subject, $customTax, $quoteItem, $store, false);
            }

            // need reCalculationTax for fix Tax ApplyAfterDiscount
            return $this->calculationTax($subject, $tax, $quoteItem, $store, false);
        }

        try {
            // Calculate custom tax
            $requestItem = $this->getRequestItem($request['item'], $quoteItem->getId());
            $customTax   = (float) $requestItem['custom_tax'];

            //             add discount to cal tax config, and show on Item view
            $this->addDiscountBundle($quoteItem);

            return $this->calculationTax($subject, $customTax, $quoteItem, $store);

            //            foreach ($request['item'] as $itemId => $data) {
            //                $customTax = (float) $data['custom_tax'];
            //                if ($itemId === (int) $quoteItem->getId()) {
            //                    // add discount to cal tax config, and show on Item view
            //                    $this->addDiscountBundle($quoteItem);
            //                    return $this->calculationTax($subject, $customTax, $quoteItem, $store);
            //                }
            //
            ////                elseif ($this->isCustomTaxOnBundle($quoteItem, $itemId)) {
            ////                    return $this->calculationTax($subject, $customTax, $quoteItem, $store);
            ////                }
            //            }

        } catch (Exception $e) {
            if (!$this->_isError) {
                $this->_messageManager->addErrorMessage(__('Unknown error, unable to update order.'));
                $this->_isError = true;
            }
        }

        return [$quoteItem, $itemTaxDetails, $baseItemTaxDetails, $store];
    }

    /**
     * @param CommonTaxCollector $subject
     * @param callable $proceed
     * @param $quoteItem
     * @param $itemTaxDetails
     * @param $baseItemTaxDetails
     * @param $store
     *
     * @return mixed
     */
    public function aroundUpdateItemTaxInfo(
        CommonTaxCollector $subject,
        callable $proceed,
        $quoteItem,
        $itemTaxDetails,
        $baseItemTaxDetails,
        $store
    ) {
        $result = $proceed($quoteItem, $itemTaxDetails, $baseItemTaxDetails, $store);

        if ($quoteItem->getProductType() === 'bundle') {
            $request = $this->_request->getParams();
            if (!$this->_helperData->isMpEdit() || !isset($request['item'])) {
                return $result;
            }

            $requestItem = $this->getRequestItem($request['item'], $quoteItem->getId());
            $isCustomTax = $requestItem['is_custom_tax'];

            if ($isCustomTax == 0) {
                $children      = $quoteItem->getChildren();
                $taxAmount     = 0;
                $baseTaxAmount = 0;
                $taxPercent    = 0;
                foreach ($children as $child) {
                    $taxAmount     += $child->getTaxAmount();
                    $baseTaxAmount += $child->getBaseTaxAmount();
                    $taxPercent    = $child->getTaxPercent();
                }
                $quoteItem->setTaxAmount($taxAmount);
                $quoteItem->setBaseTaxAmount($baseTaxAmount);
                $quoteItem->setTaxPercent($taxPercent);
            }
        }

        return $result;
    }

    /**
     * @param $requestItems
     * @param $quoteId
     *
     * @return false | array
     */
    private function getRequestItem($requestItems, $quoteId)
    {
        foreach ($requestItems as $itemId => $data) {
            if ($itemId === (int) $quoteId) {
                return $data;
            }
        }

        return false;
    }

    /**
     * Check is have custom tax on bundle item parent
     *
     * @param AbstractItem $quoteItem
     * @param string|int $itemId
     *
     * @return bool
     */
    private function isCustomTaxOnBundle($quoteItem, $itemId)
    {
        if ($quoteItem->getParentItem()->getProductType() === 'bundle') {
            $bundleItem = $quoteItem->getParentItem();
            if ((int) $bundleItem->getId() === (int) $itemId) {
                return true;
            }
        }

        return false;
    }

    /**
     * @param CommonTaxCollector $subject
     * @param $customTax
     * @param $quoteItem
     * @param $store
     * @param bool $isUseCustomTax
     *
     * @return array
     */
    private function calculationTax($subject, $customTax, $quoteItem, $store, $isUseCustomTax = true)
    {
        $isTaxIncludedInPrice = $this->config->priceIncludesTax($store);
        $taxCalculation       = $this->taxCalculation->create(['storeId' => $store->getId()]);
        $quoteDetailFactory   = $this->quoteDetailsItemInterfaceFactory;
        $quoteDetail          = $subject->mapItem(
            $quoteDetailFactory,
            $quoteItem,
            $isTaxIncludedInPrice,
            true
        );
        $baseQuoteDetail      = $subject->mapItem(
            $quoteDetailFactory,
            $quoteItem,
            $isTaxIncludedInPrice,
            false
        );
        $taxDetail            = $taxCalculation
            ->calculate($quoteDetail, $quoteItem->getQty(), true, $customTax);
        $baseTaxDetails       = $taxCalculation
            ->calculate($baseQuoteDetail, $quoteItem->getQty(), true, $customTax);
        if (!$isUseCustomTax) {
            $customTax = null;
        }
        $quoteItem->setData('mp_custom_tax_percent', $customTax);

        return [$quoteItem, $taxDetail, $baseTaxDetails, $store];
    }

    /**
     * @param AbstractItem $quoteItem
     */
    private function addDiscountBundle($quoteItem)
    {
        if ($quoteItem->getProductType() === 'bundle') {
            $discountBundle     = 0;
            $baseDiscountBundle = 0;
            foreach ($quoteItem->getChildren() as $child) {
                $discountBundle     += $child->getDiscountAmount();
                $baseDiscountBundle += $child->getBaseDiscountAmount();
            }
            if ($discountBundle) {
                $quoteItem->setDiscountAmount($discountBundle);
                $quoteItem->setBaseDiscountAmount($baseDiscountBundle);
                $quoteItem->setNoDiscount(false);
            }
        }
    }

    /**
     * True if have any $quoteItem[mp_custom_tax_percent] or $requestData['custom_tax']
     *
     * @param array $request
     * @param AbstractItem $quoteItem
     *
     * @return bool
     */
    private function isCustomTax($request, $quoteItem)
    {

        foreach ($request['item'] as $id => $data) {
            if (isset($data['is_custom_tax']) && $id === (int) $quoteItem->getId() && $data['is_custom_tax'] === '1') {
                return true;
            }
        }

        return false;
    }

    /**
     * To fixed bug when custom price is set form Magento Tax Calculation
     *
     * @param AbstractItem $quoteItem
     * @param TaxDetailsItemInterface $itemTaxDetails
     * @param TaxDetailsItemInterface $baseItemTaxDetails
     *
     * @return array
     */
    public function updateTaxCalCustomPrice($quoteItem, $itemTaxDetails, $baseItemTaxDetails)
    {
        if ($quoteItem->getCustomPrice()) {
            $itemTaxDetailsClone = clone $itemTaxDetails;
            $itemTaxDetails      = $baseItemTaxDetails;
            $baseItemTaxDetails  = $itemTaxDetailsClone;
        }

        return [$itemTaxDetails, $baseItemTaxDetails];
    }
}
