<?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_magento2
 * @copyright   Copyright (c) 2020 Plumrocket Inc. (http://www.plumrocket.com)
 * @license     http://wiki.plumrocket.net/wiki/EULA  End-user License Agreement
 */

declare(strict_types=1);

namespace Plumrocket\ProductFilter\Plugin\Elasticsearch;

use Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection;
use Plumrocket\ProductFilter\Helper\Config;
use Plumrocket\ProductFilter\Helper\Elasticsearch;
use Plumrocket\ProductFilter\Model\CatalogSearch\Model\ResourceModel\Fulltext\Collection\CurrentLoading;

/**
 * Temporary fix for
 * @link https://github.com/magento/magento2/issues/28919
 * TODO: remove after left support magento version with bug
 *
 * @since 3.2.12
 */
class FixMaxAndMinPrices
{
    /**
     * @var \Plumrocket\ProductFilter\Model\CatalogSearch\Model\ResourceModel\Fulltext\Collection\CurrentLoading
     */
    private $currentLoadingCollection;

    /**
     * @var \Plumrocket\ProductFilter\Helper\Config
     */
    private $config;

    /**
     * @var \Plumrocket\ProductFilter\Helper\Elasticsearch
     */
    private $elasticsearchHelper;

    /**
     * @param \Plumrocket\ProductFilter\Model\CatalogSearch\Model\ResourceModel\Fulltext\Collection\CurrentLoading $currentLoadingCollection
     * @param \Plumrocket\ProductFilter\Helper\Config                                                              $config
     * @param \Plumrocket\ProductFilter\Helper\Elasticsearch                                                       $elasticsearchHelper
     */
    public function __construct(
        CurrentLoading $currentLoadingCollection,
        Config $config,
        Elasticsearch $elasticsearchHelper
    ) {
        $this->currentLoadingCollection = $currentLoadingCollection;
        $this->config = $config;
        $this->elasticsearchHelper = $elasticsearchHelper;
    }

    /**
     * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $subject
     * @param bool                                                           $printQuery
     * @param bool                                                           $logQuery
     */
    public function beforeLoad(
        Collection $subject,
        $printQuery = false,
        $logQuery = false
    ) {
        if (! $this->needFix()) {
            return;
        }

        $this->currentLoadingCollection->set($subject);
    }

    /**
     * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $subject
     * @param                                                                $result
     * @param bool                                                           $printQuery
     * @param bool                                                           $logQuery
     * @return mixed
     */
    public function afterLoad(
        Collection $subject,
        $result,
        $printQuery = false,
        $logQuery = false
    ) {
        if ($priceData = $this->currentLoadingCollection->getPriceData()) {
            $this->setPropertyValue($subject, '_maxPrice', (double) ($priceData['max'] ?? 0));
            $this->setPropertyValue($subject, '_minPrice', (double) ($priceData['min'] ?? 0));
        }

        $this->currentLoadingCollection->reset();
        return $result;
    }

    /**
     * @return bool
     */
    public function needFix(): bool
    {
        return $this->config->isModuleEnabled() && $this->elasticsearchHelper->isCurrentSearchEngine();
    }

    /**
     * @param \Magento\CatalogSearch\Model\ResourceModel\Fulltext\Collection $subject
     * @param string                                                         $propertyName
     * @param float                                                          $value
     */
    private function setPropertyValue(Collection $subject, string $propertyName, float $value)
    {
        try {
            $reflectionSubject = new \ReflectionObject($subject);
            $reflectionProperty = $reflectionSubject->getProperty($propertyName);
            $reflectionProperty->setAccessible(true);
            $reflectionProperty->setValue($subject, $value);
            $reflectionProperty->setAccessible(false);
        } catch (\ReflectionException $e) {
        }
    }
}
