<?php
declare(strict_types=1);

namespace FiloBlu\Refilo\Remote\Entity\Provider;

use FiloBlu\Refilo\Helper\Catalog\ProductFilters;
use FiloBlu\Refilo\Remote\Entity\AbstractEntity;
use FiloBlu\Refilo\Remote\Entity\EntityProviderInterface;
use FiloBlu\Refilo\Remote\Entity\Product;
use Magento\Catalog\Api\Data\EavAttributeInterface;
use Magento\Catalog\Api\Data\ProductAttributeInterface;
use Magento\Catalog\Model\Product\Attribute\Source\Status as AttributeStatus;
use Magento\Catalog\Model\Product\Visibility;
use Magento\Catalog\Model\ResourceModel\Product\Collection;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Eav\Api\AttributeRepositoryInterface;
use Magento\Framework\Api\FilterBuilder;
use Magento\Framework\Api\Search\FilterGroupBuilder;
use Magento\Framework\Api\SearchCriteriaBuilder;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\Exception\NoSuchEntityException;
use Magento\Store\Api\Data\StoreInterface;
use Magento\Store\Api\Data\WebsiteInterface;

/**
 * Class VisibleProductProvider
 * @package FiloBlu\Refilo\Remote\Entity\Provider
 */
class VisibleProductProvider extends AbstractFromCollectionProvider
{
    /**
     * @var Collection
     */
    protected $collection;
    /**
     * @var AttributeRepositoryInterface
     */
    private $attributeRepository;
    /**
     * @var SearchCriteriaBuilder
     */
    private $searchCriteriaBuilder;
    /**
     * @var FilterBuilder
     */
    private $filterBuilder;
    /**
     * @var FilterGroupBuilder
     */
    private $filterGroupBuilder;
    /**
     * @var CollectionFactory
     */
    private $collectionFactory;
    /**
     * @var \FiloBlu\Refilo\Helper\Catalog\ProductFilters
     */
    private $productFilters;

    /**
     * @param \Magento\Framework\App\Config\ScopeConfigInterface $scopeConfig
     * @param \Magento\Catalog\Model\ResourceModel\Product\CollectionFactory $collectionFactory
     * @param \Magento\Eav\Api\AttributeRepositoryInterface $attributeRepository
     * @param \Magento\Framework\Api\SearchCriteriaBuilder $searchCriteriaBuilder
     * @param \Magento\Framework\Api\FilterBuilder $filterBuilder
     * @param \Magento\Framework\Api\Search\FilterGroupBuilder $filterGroupBuilder
     * @param \FiloBlu\Refilo\Helper\Catalog\ProductFilters $productFilters
     */
    public function __construct(
        ScopeConfigInterface $scopeConfig,
        CollectionFactory             $collectionFactory,
        AttributeRepositoryInterface  $attributeRepository,
        SearchCriteriaBuilder         $searchCriteriaBuilder,
        FilterBuilder                 $filterBuilder,
        FilterGroupBuilder            $filterGroupBuilder,
        ProductFilters $productFilters
    )
    {
        parent::__construct($scopeConfig);
        $this->attributeRepository = $attributeRepository;
        $this->searchCriteriaBuilder = $searchCriteriaBuilder;
        $this->filterBuilder = $filterBuilder;
        $this->filterGroupBuilder = $filterGroupBuilder;
        $this->collectionFactory = $collectionFactory;
        $this->productFilters = $productFilters;
    }

    /**
     * @param $items
     * @return array
     * @throws NoSuchEntityException
     * @throws \Magento\Framework\Exception\LocalizedException
     */
    public function adapt($items)
    {
        $result = [];
        foreach ($items as $product) {
            $result[] = new Product( [
                AbstractEntity::ID => (int)$product->getEntityId(),
                Product::FILTERS => $this->productFilters->getFilterableAttributesWithChildrenWithoutOutOfStock($product)
            ]);
        }

        return $result;
    }

    /**
     * @param StoreInterface $store
     * @return EntityProviderInterface
     */
    public function forStore(StoreInterface $store): EntityProviderInterface
    {
        $this->getCollection()
             ->setStore($store)
             ->addStoreFilter($store);

        return $this;
    }

    /**
     * @return Collection
     */
    public function getCollection()
    {
        if ($this->collection !== null) {
            return $this->collection;
        }

        $attributes = $this->attributeRepository->getList(
            ProductAttributeInterface::ENTITY_TYPE_CODE,
            $this->searchCriteriaBuilder->setFilterGroups(
                [
                    $this->filterGroupBuilder->setFilters(
                        [
                            $this->filterBuilder->setField(EavAttributeInterface::IS_FILTERABLE)
                                                ->setValue(true)
                                                ->setConditionType('eq')
                                                ->create()


                        ]
                    )->create()
                ]
            )->create()
        );

        $this->collection = $this->collectionFactory->create();

        foreach ($attributes->getItems() as $attribute) {
            $this->collection->addAttributeToSelect($attribute->getAttributeCode(), true);
        }

        $this->collection->addAttributeToFilter('status', AttributeStatus::STATUS_ENABLED);
        $this->collection->addAttributeToFilter('visibility',  ['in' => [
            Visibility::VISIBILITY_BOTH,
            Visibility::VISIBILITY_IN_CATALOG,
            Visibility::VISIBILITY_IN_SEARCH
        ]]);

        return $this->collection;
    }

    /**
     * @param \Magento\Store\Api\Data\WebsiteInterface $website
     * @return \FiloBlu\Refilo\Remote\Entity\EntityProviderInterface
     */
    public function forWebsite(WebsiteInterface $website): EntityProviderInterface
    {
        return $this;
    }

    /**
     * @return EntityProviderInterface
     */
    public function release(): EntityProviderInterface
    {
        $this->items = [];
        $this->collection->clear();
        $this->collection = null;
        return $this;
    }

    /**
     * @param array $ids
     * @return EntityProviderInterface
     */
    public function withIds(array $ids): EntityProviderInterface
    {
        if (empty($ids)) {
            return $this;
        }

        $this->getCollection()->addFieldToFilter('entity_id', ['in' => $ids]);
        return $this;
    }
}
