<?php

declare(strict_types=1);

namespace FiloBlu\Refilo\Model;

use FiloBlu\Refilo\Helper\Data as DataHelper;
use Magento\Directory\Helper\Data;
use Magento\Directory\Model\Region;
use Magento\Directory\Model\ResourceModel\Region\CollectionFactory;
use Magento\Quote\Api\Data\AddressInterface;
use Magento\Quote\Api\Data\AddressInterfaceFactory;
use Magento\Quote\Api\Data\CartInterface;
use Magento\Quote\Model\Quote\Address\Rate;
use Magento\Quote\Model\Quote\Address\RateCollectorInterfaceFactory;
use Magento\Quote\Model\Quote\Address\RateRequestFactory;

/**
 *
 */
class ShippingEstimationCountryAndRegionNoRecollect implements ShippingEstimationStrategyInterface
{
    /**
     * @var AddressInterfaceFactory
     */
    private $addressFactory;

    /**
     * @var Data
     */
    private $data;

    /**
     * @var CollectionFactory
     */
    private $collectionFactory;

    /**
     * @var DataHelper
     */
    private $helper;

    /**
     * @var RateRequestFactory
     */
    protected $rateRequestFactory;

    /**
     * @var \Magento\Quote\Model\Quote\Address\RateCollectorInterfaceFactory
     */
    protected $rateCollectorFactory;

    /**
     * @param AddressInterfaceFactory $addressFactory
     * @param Data $data
     * @param CollectionFactory $collectionFactory
     * @param DataHelper $helper
     * @param RateRequestFactory $rateRequestFactory
     * @param RateCollectorInterfaceFactory $rateCollectorFactory
     */
    public function __construct(
        AddressInterfaceFactory $addressFactory,
        Data $data,
        CollectionFactory $collectionFactory,
        DataHelper $helper,
        RateRequestFactory $rateRequestFactory,
        RateCollectorInterfaceFactory $rateCollectorFactory
    ) {
        $this->addressFactory = $addressFactory;
        $this->data = $data;
        $this->collectionFactory = $collectionFactory;
        $this->helper = $helper;
        $this->rateRequestFactory = $rateRequestFactory;
        $this->rateCollectorFactory = $rateCollectorFactory;
    }

    /**
     * @param \Magento\Quote\Api\Data\CartInterface $cart
     * @return \Magento\Quote\Api\Data\CartInterface
     * @throws \Exception
     */
    public function estimate(CartInterface $cart): CartInterface
    {
        $shippingAddress = $cart->getShippingAddress();

        if (!$shippingAddress) {
            $shippingAddress = $this->addressFactory->create();
        }

        if (!$shippingAddress->getCountryId()) {
            $defaultCountry = $this->data->getDefaultCountry($cart->getStoreId());
            $shippingAddress->setCountryId($defaultCountry);
            if ($this->data->isRegionRequired($defaultCountry)) {
                /** @var Region $region */
                $region = $this->collectionFactory->create()
                    ->addCountryFilter($defaultCountry)
                    ->getFirstItem();
                $shippingAddress->setRegion($region->getName());
                $shippingAddress->setRegionId($region->getId());
            }
        }

        if (!$shippingAddress->getShippingMethod()) {

            /** @var Rate $first */
            $first = $this->getEstimatedRate($cart, $shippingAddress);
            if (!$first) {
                return $cart;
            }

            $shippingAddress->setShippingMethod($first->getCarrier()."_".$first->getMethod());
            $shippingAddress->setShippingDescription($first->getMethodTitle());
            $shippingAddress
                ->setCollectShippingRates(true);
            $cart->setShippingAddress($shippingAddress);
            $cart->setTriggerRecollect(1);
            $cart->setTotalsCollectedFlag(false);
            $cart->collectTotals();
            $cart->save();
        }

        return $cart;
    }

    /**
     * @param CartInterface|\Magento\Quote\Model\Quote $cart
     * @param AddressInterface $address
     * @return mixed
     */
    public function getEstimatedRate(CartInterface $cart, AddressInterface $address)
    {
        $carriers = $this->helper->getCarriers($cart->getStoreId());
        $request = $this->rateRequestFactory->create();
        $request->setDestCountryId($address->getCountryId());
        $request->setDestRegionId($address->getRegionId());
        $request->setDestPostcode($address->getPostcode());
        $request->setDestCity($address->getCity());
        $request->setPackageValue($cart->getBaseSubtotal());
        $request->setPackageValueWithDiscount($cart->getBaseSubtotal());
        $request->setPackageWeight(1);
        $request->setFreeMethodWeight(1);
        $request->setPackageQty($cart->getItemsQty());
        $request->setStoreId($cart->getStoreId());
        $request->setWebsiteId($cart->getStore()->getWebsiteId());
        $request->setBaseCurrency($cart->getBaseCurrencyCode());
        $request->setPackageCurrency($cart->getCurrency()->getQuoteCurrencyCode());
        $request->setLimitCarrier($carriers);
        $request->setFreeShipping(false);
        $request->setAllItems($cart->getAllItems());
        $request->setSkipDisableFreeShipping(true);
        $request->setQuoteStoreId($cart->getStoreId());

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

        if ($result) {
            $rates = $result->getAllRates();
            if (!empty($rates)) {
                foreach ($rates as $rate) {
                    $price = $rate->getPrice();
                    if (isset($price) && $price > 0) {
                        return $rate;
                    }
                }
            }
        }

        return $rate;
    }
}
