<?php

declare(strict_types=1);

namespace Macopedia\OrlenShipping\Plugin\Quote;

use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Quote\Model\Quote\Address\RateFactory;
use Magento\Quote\Model\Quote\Address\RateRequest;
use Magento\Quote\Model\Quote\Address\RateRequestFactory;
use Magento\Quote\Model\Quote\Address\RateCollectorInterfaceFactory;
use Magento\Quote\Model\Quote\Item\AbstractItem;
use Magento\Store\Api\Data\StoreInterface;
use Magento\Store\Model\ScopeInterface;
use Magento\Store\Model\StoreManagerInterface;

class Address
{
    /**
     * @param ScopeConfigInterface $scopeConfig
     * @param StoreManagerInterface $storeManager
     * @param RateRequestFactory $rateRequestFactory
     * @param RateCollectorInterfaceFactory $rateCollector
     * @param RateFactory $addressRateFactory
     */
    public function __construct(
        protected readonly ScopeConfigInterface $scopeConfig,
        protected readonly StoreManagerInterface $storeManager,
        protected readonly RateRequestFactory $rateRequestFactory,
        protected readonly RateCollectorInterfaceFactory $rateCollector,
        protected readonly RateFactory $addressRateFactory
    ) {
    }

    /**
     * Around request shipping rates plugin
     *
     * @param \Magento\Quote\Model\Quote\Address $subject
     * @param \Closure $callable
     * @param AbstractItem|null $item
     * @return bool
     * @throws LocalizedException
     * @throws NoSuchEntityException
     */
    public function aroundRequestShippingRates(
        \Magento\Quote\Model\Quote\Address $subject,
        \Closure $callable,
        ?AbstractItem $item = null
    ) {
        $storeId = $subject->getQuote()->getStoreId() ?: $this->storeManager->getStore()->getId();
        $taxInclude = $this->scopeConfig->getValue(
            'tax/calculation/price_includes_tax',
            ScopeInterface::SCOPE_STORE,
            $storeId
        );

        /** @var $request RateRequest */
        $request = $this->rateRequestFactory->create();
        $request->setAllItems($item ? [$item] : $subject->getAllItems());
        $request->setDestCountryId($subject->getCountryId());
        $request->setDestRegionId($subject->getRegionId());
        $request->setDestRegionCode($subject->getRegionCode());
        $request->setDestStreet($subject->getStreetFull());
        $request->setDestCity($subject->getCity());
        $request->setDestPostcode($subject->getPostcode());
        $baseSubtotal = $taxInclude ? $subject->getBaseSubtotalTotalInclTax() : $subject->getBaseSubtotal();
        $request->setPackageValue($item ? $item->getBaseRowTotal() : $baseSubtotal);
        $baseSubtotalWithDiscount = $baseSubtotal + $subject->getBaseDiscountAmount();
        $packageWithDiscount = $item ? $item->getBaseRowTotal() -
            $item->getBaseDiscountAmount() : $baseSubtotalWithDiscount;
        $request->setPackageValueWithDiscount($packageWithDiscount);
        $request->setPackageWeight($item ? $item->getRowWeight() : $subject->getWeight());
        $request->setPackageQty($item ? $item->getQty() : $subject->getItemQty());

        /**
         * Need for shipping methods that use insurance based on price of physical products
         */
        $packagePhysicalValue = $item ? $item->getBaseRowTotal() : $baseSubtotal - $subject->getBaseVirtualAmount();
        $request->setPackagePhysicalValue($packagePhysicalValue);

        $request->setFreeMethodWeight($item ? 0 : $subject->getFreeMethodWeight());

        /**
         * Store and website identifiers specified from StoreManager
         */
        $request->setStoreId($storeId);
        if ($subject->getQuote()->getStoreId()) {
            $request->setWebsiteId($this->storeManager->getStore($storeId)->getWebsiteId());
        } else {
            $request->setWebsiteId($this->storeManager->getWebsite()->getId());
        }
        $request->setFreeShipping($subject->getFreeShipping());
        /**
         * Currencies need to convert in free shipping
         */
        $request->setBaseCurrency($this->storeManager->getStore()->getBaseCurrency());
        $request->setPackageCurrency($this->storeManager->getStore()->getCurrentCurrency());
        $request->setLimitCarrier($subject->getLimitCarrier());
        $baseSubtotalInclTax = $subject->getBaseSubtotalTotalInclTax();
        $request->setBaseSubtotalInclTax($baseSubtotalInclTax);
        $request->setBaseSubtotalWithDiscountInclTax(
            $subject->getBaseSubtotalWithDiscount() + $subject->getBaseTaxAmount()
        );

        //Macopedia custom START
        $request->setShippingMethod($subject->getShippingMethod());
        //Macopedia custom END

        $result = $this->rateCollector->create()->collectRates($request)->getResult();

        $found = false;
        if ($result) {
            $shippingRates = $result->getAllRates();

            foreach ($shippingRates as $shippingRate) {
                $rate = $this->addressRateFactory->create()->importShippingRate($shippingRate);
                if (!$item) {
                    $subject->addShippingRate($rate);
                }

                if ($subject->getShippingMethod() == $rate->getCode()) {
                    if ($item) {
                        $item->setBaseShippingAmount($rate->getPrice());
                    } else {

                        /** @var StoreInterface */
                        $store = $this->storeManager->getStore();
                        $amountPrice = $store->getBaseCurrency()
                            ->convert($rate->getPrice(), $store->getCurrentCurrencyCode());
                        $subject->setBaseShippingAmount($rate->getPrice());
                        $subject->setShippingAmount($amountPrice);
                    }

                    $found = true;
                }
            }
        }

        return $found;
    }
}
