<?php
/**
 * Plumrocket Inc.
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the End-user License Agreement
 * that is available through the world-wide-web at this URL:
 * http://wiki.plumrocket.net/wiki/EULA
 * If you are unable to obtain it through the world-wide-web, please
 * send an email to support@plumrocket.com so we can send you a copy immediately.
 *
 * @package     Plumrocket Product Filter v3.x.x
 * @copyright   Copyright (c) 2020 Plumrocket Inc. (http://www.plumrocket.com)
 * @license     http://wiki.plumrocket.net/wiki/EULA  End-user License Agreement
 */

namespace Plumrocket\ProductFilter\Block\LayeredNavigation;

use Plumrocket\ProductFilter\Model\Config\Source\PriceDisplay;

class RenderPrice extends \Magento\Framework\View\Element\Template
{

    const FILTER_PRICE_SLIDER_TEMPLATE = 'Plumrocket_ProductFilter::layer/renderer/price/slider.phtml';
    const FILTER_PRICE_INPUT_TEMPLATE = 'Plumrocket_ProductFilter::layer/renderer/price/input.phtml';
    const FILTER_PRICE_RANGE_TEMPLATE = 'Plumrocket_ProductFilter::layer/filter.phtml';
    const FILTER_PRICE_REQUEST_VAR = 'price';

    /**
     * Data helper
     * @var \Plumrocket\ProductFilter\Helper\Data
     */
    protected $_dataHelper;

    /**
     * Json Helper
     * @var \Magento\Framework\Json\Helper\Data
     */
    protected $_jsonHelper;

    /**
     * Amp Helper
     *
     * @var \Plumrocket\Amp\Helper\Data
     */
    protected $ampHelper;

    /**
     * @var \Magento\Framework\Registry
     */
    private $registry;

    /**
     * @var \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory
     */
    private $productCollectionFactory;

    /**
     * @var \Magento\Catalog\Model\ResourceModel\Product\Collection\ $originalCollection
     */
    private $originalCollection = null;

    /**
     * RenderPrice constructor.
     *
     * @param \Plumrocket\ProductFilter\Helper\Data                          $dataHelper
     * @param \Magento\Framework\Json\Helper\Data                            $jsonHelper
     * @param \Magento\Framework\Registry                                    $registry
     * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory
     * @param \Magento\Framework\View\Element\Template\Context               $context
     * @param array                                                          $data
     */
    public function __construct(
        \Plumrocket\ProductFilter\Helper\Data $dataHelper,
        \Magento\Framework\Json\Helper\Data $jsonHelper,
        \Magento\Framework\Registry $registry,
        \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $productCollectionFactory,
        \Magento\Framework\View\Element\Template\Context $context,
        array $data = []
    ) {
        $this->_dataHelper = $dataHelper;
        $this->_jsonHelper = $jsonHelper;
        parent::__construct($context, $data);
        $this->registry = $registry;
        $this->productCollectionFactory = $productCollectionFactory;
    }

    /**
     * Get Items
     *
     * @return array
     */
    public function getItems()
    {
        return $this->getFilter()->getItems();
    }

    /**
     * {@inheritdoc}
     */
    protected function _toHtml()
    {
        $types = $this->_getPriceDisplayTypes();

        $this->assign('filterItems', $this->getItems());

        if ($this->ampHelper === null) {
            if ($this->_dataHelper->moduleExists('Amp')) {
                $this->ampHelper = $this->_dataHelper->getModuleHelper('Amp');
            } else {
                $this->ampHelper = false;
            }
        }

        // render only RANGE_TEMPLATE in AMP
        if ($this->ampHelper && $this->ampHelper->isAmpRequest()) {
            $this->setTemplate(self::FILTER_PRICE_RANGE_TEMPLATE);

            $ampHtml = parent::_toHtml();

            $this->assign('filterItems', []);

            return $ampHtml;
        }

        $html = '';
        if (in_array(PriceDisplay::PRICE_DISPLAY_RANGE, $types)) {
            $this->setTemplate(self::FILTER_PRICE_RANGE_TEMPLATE);
            $html .= parent::_toHtml();
        }

        if (in_array(PriceDisplay::PRICE_DISPLAY_SLIDER, $types)) {
            $this->setTemplate(self::FILTER_PRICE_SLIDER_TEMPLATE);
            $html .= parent::_toHtml();
        }

        if (in_array(PriceDisplay::PRICE_DISPLAY_INPUT, $types)) {
            $this->setTemplate(self::FILTER_PRICE_INPUT_TEMPLATE);
            $html .= parent::_toHtml();
        }

        $this->assign('filterItems', []);

        return $html;
    }

    /**
     * Retrieve from value
     * @return string
     */
    public function getFromValue()
    {
        $fromRequest = $this->_getRequestedPrice();
        if (isset($fromRequest['min'])) {
            return $fromRequest['min'];
        }

        return $this->getMinValue();
    }

    /**
     * Retrieve "to'" value
     * @return string
     */
    public function getToValue()
    {
        $fromRequest = $this->_getRequestedPrice();

        if (isset($fromRequest['max'])) {
            return $fromRequest['max'];
        }

        return $this->getMaxValue();
    }

    /**
     * Get min value
     * @return string
     */
    public function getMinValue()
    {
        if (null !== $this->_request->getParam(self::FILTER_PRICE_REQUEST_VAR, null)
            && !$this->_request->isXmlHttpRequest()
        ) {
            return $this->getOriginalMinValue();
        }

        return $this->getFilter()->getLayer()
                ->getProductCollection()
                ->getMinPrice();
    }

    /**
     * Get original collection min price value
     * @return float
     */
    private function getOriginalMinValue()
    {
        /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */
        $collection = $this->getOriginalCollection();

        return $collection->getMinPrice();
    }

    /**
     * Get max value
     * @return string
     */
    public function getMaxValue()
    {
        if (null !== $this->_request->getParam(self::FILTER_PRICE_REQUEST_VAR, null)
            && !$this->_request->isXmlHttpRequest()
        ) {
            return $this->getOriginalMaxValue();
        }

        return $this->getFilter()->getLayer()
                ->getProductCollection()
                ->getMaxPrice();
    }

    /**
     * Get original collection max price value
     * @return float
     */
    private function getOriginalMaxValue()
    {
        /** @var \Magento\Catalog\Model\ResourceModel\Product\Collection $collection */
        $collection = $this->getOriginalCollection();

        return $collection->getMaxPrice();
    }

    /**
     * Retrieve not filtered collection with price data
     * @return \Magento\Catalog\Model\ResourceModel\Product\Collection\
     */
    private function getOriginalCollection()
    {
        if (null === $this->originalCollection) {
            $category = $this->registry->registry('current_category');
            $this->originalCollection = $this->productCollectionFactory->create()
                ->addPriceData();

            if ($category) {
                $this->originalCollection->addCategoryFilter($category);
            }
        }

        return $this->originalCollection;
    }

    /**
     * Retrieve prices from request
     * @return string
     */
    public function getRequestedPrice()
    {
        $result = $this->_getRequestedPrice();
        return $this->_jsonHelper->jsonEncode($result);
    }

    /**
     * Retrieve requested price
     * @return array
     */
    private function _getRequestedPrice()
    {
        $result = [];
        if ($this->_request->getParam(self::FILTER_PRICE_REQUEST_VAR)) {
            $prices = array_map(
                'floatval',
                explode('-', $this->_request->getParam(self::FILTER_PRICE_REQUEST_VAR))
            );

            if (!empty($prices[0])) {
                $result['min'] = round($prices[0] * $this->getCurrentCurrencyRate(), 2);
            }

            if (!empty($prices[1])) {
                $result['max'] = round($prices[1] * $this->getCurrentCurrencyRate(), 2);
            }
        }

        return $result;
    }

    /**
     * Retrieve price display types from configs
     * @return array
     */
    protected function _getPriceDisplayTypes()
    {
        $path = $this->_dataHelper->getConfigSectionId() . '/' . PriceDisplay::CONFIG_PATH;
        $types = $this->_dataHelper->getConfig($path);
        return explode(',', $types);
    }

    /**
     * Retrieve currency symbol
     * @return string
     */
    public function getCurrencySymbol()
    {
        return $this->_storeManager->getStore()->getCurrentCurrency()->getCurrencySymbol();
    }

    /**
     * Get current currency rate
     *
     * @return float
     */
    public function getCurrentCurrencyRate()
    {
        $currencyRate = (float)$this->_storeManager->getStore()->getCurrentCurrencyRate();

        return $currencyRate ?: 1;
    }

    /**
     * Retrieve filter key for amp filter
     *
     * @return mixed
     */
    public function getFilterKey()
    {
        /** @var \Plumrocket\Amp\Block\Catalog\Layer\Navigation\FilterRenderer $rendererBlock */
        $rendererBlock = $this->getLayout()->getBlock('amp.catalog.navigation.renderer');

        return method_exists($rendererBlock, 'createFilterCode')
            ? $rendererBlock->createFilterCode($this->getFilter()->getRequestVar())
            : $this->getFilter()->getRequestVar();
    }
}
