<?php

declare(strict_types=1);

namespace FiloBlu\Refilo\Helper;

use FiloBlu\Core\Model\Configuration;
use FiloBlu\Refilo\Model\Indexer\Locator\SnapshotMViewStateTable;
use FiloBlu\Refilo\Remote\Entity\Product;
use Magento\Bundle\Model\ResourceModel\Selection;
use Magento\Catalog\Api\Data\ProductInterface;
use Magento\ConfigurableProduct\Model\ResourceModel\Product\Type\Configurable;
use Magento\Framework\App\Config\ScopeConfigInterface;
use Magento\Framework\App\ResourceConnection;
use Magento\Framework\DB\Adapter\AdapterInterface;
use Magento\Framework\EntityManager\MetadataPool;
use Magento\Framework\Exception\LocalizedException;
use Magento\Framework\Mview\View\CollectionFactory;
use Magento\Framework\Mview\ViewInterface;
use Magento\Store\Api\Data\StoreInterface;
use Magento\Store\Api\Data\WebsiteInterface;
use Magento\Store\Model\ScopeInterface;


/**
 * Class Indexer
 * @package FiloBlu\Refilo\Helper
 */
class Indexer
{
    /** @var string */
    public const XML_SYNC_DATA_INDEX_BULK_SIZE = 'sync/data/index_bulk_size';

    /** @var string */
    public const XML_SYNC_DATA_ALLOW_INDEX_DELETION = 'sync/data/allow_index_deletion';

    /** @var string */
    public const XML_SYNC_DATA_FILTERS_WITHOUT_OUT_OF_STOCK = 'sync/data/filters_without_out_of_stock';

    /**
     * @var ResourceConnection
     */
    private $resourceConnection;

    /**
     * @var ScopeConfigInterface
     */
    private $scopeConfig;

    /**
     * @var Configuration
     */
    private $coreConfiguration;

    /**
     * @var AdapterInterface
     */
    private $connection;

    /**
     * @var MetadataPool
     */
    private $metadataPool;
    /**
     * @var CollectionFactory
     */
    private $viewCollectionFactory;
    /**
     * @var SnapshotMViewStateTable
     */
    private $snapShooter;
    /**
     * @var Selection
     */
    private $bundleSelection;
    /**
     * @var Configurable
     */
    private $configurableSelection;

    /**
     * Indexer constructor.
     * @param ResourceConnection $resourceConnection
     * @param ScopeConfigInterface $scopeConfig
     * @param Configuration $coreConfiguration
     * @param MetadataPool $metadataPool
     * @param CollectionFactory $viewCollectionFactory
     * @param SnapshotMViewStateTable $snapShooter
     * @param Selection $bundleSelection
     * @param Configurable $configurableSelection
     */
    public function __construct(
        ResourceConnection      $resourceConnection,
        ScopeConfigInterface    $scopeConfig,
        Configuration           $coreConfiguration,
        MetadataPool            $metadataPool,
        CollectionFactory       $viewCollectionFactory,
        SnapshotMViewStateTable $snapShooter,
        Selection               $bundleSelection,
        Configurable            $configurableSelection
    )
    {
        $this->resourceConnection = $resourceConnection;
        $this->scopeConfig = $scopeConfig;
        $this->coreConfiguration = $coreConfiguration;
        $this->metadataPool = $metadataPool;
        $this->viewCollectionFactory = $viewCollectionFactory;
        $this->snapShooter = $snapShooter;
        $this->bundleSelection = $bundleSelection;
        $this->configurableSelection = $configurableSelection;
    }

    /**
     * @return int
     */
    public function getIndexerBulkSize(): int
    {
        return (int)$this->scopeConfig->getValue(self::XML_SYNC_DATA_INDEX_BULK_SIZE) ?: 500;
    }

    /**
     * @return bool
     * @deprecated
     */
    public function indexerCanDelete(): bool
    {
        return (bool)$this->scopeConfig->isSetFlag(self::XML_SYNC_DATA_ALLOW_INDEX_DELETION);
    }

    /**
     * @return AdapterInterface
     */
    public function getConnection()
    {
        if ($this->connection === null) {
            $this->connection = $this->resourceConnection->getConnection();
        }

        return $this->connection;
    }

    /**
     * @param WebsiteInterface|StoreInterface $scope
     * @return string
     * @throws LocalizedException
     */
    public function getProjectId($scope = null)
    {
        return $this->coreConfiguration->getProjectId($scope);
    }

    /**
     * @param WebsiteInterface|StoreInterface $scope
     * @return bool
     * @throws LocalizedException
     */
    public function hasProjectId($scope = null)
    {
        return $this->coreConfiguration->hasProjectId($scope);
    }

    /**
     * @return Configuration
     */
    public function getCoreConfiguration()
    {
        return $this->coreConfiguration;
    }

    /**
     * @param Product[] $products
     * @param StoreInterface $store
     * @return Product[]
     */
    public function hideOutOfStocks(array $products, StoreInterface $store): array
    {
        if ($this->scopeConfig->isSetFlag(
            \Magento\CatalogInventory\Model\Configuration::XML_PATH_SHOW_OUT_OF_STOCK,
            ScopeInterface::SCOPE_STORE,
            $store
        )) {
            return $products;
        }

        foreach ($products as $product) {
            $inventory = $product->getInventory();

            if (!isset($inventory['in_stock']) || $inventory['in_stock']) {
                continue;
            }

            $product->setData(Product::VISIBLE, '0');
        }

        return $products;
    }

    public function getChangeLogIds($indexer): array
    {
        $viewsCollection = $this->viewCollectionFactory->create();

        /** @var ViewInterface $view */
        foreach ($viewsCollection as $view) {
            if (is_a($indexer, $view->getActionClass(), true)) {
                return $view->getChangelog()->getList($this->snapShooter->getVersionId($view->getId()), $view->getChangelog()->getVersion());
            }
        }
        return [];
    }

    /**
     * Merges the given product IDs with their parent bundle and configurable product IDs.
     *
     * @param array $ids Product IDs to merge.
     * @return array Merged array of product and parent IDs.
     */
    public function mergeWithProductParentIds(array $ids): array
    {
        if(empty($ids)){
            return $ids;
        }

        foreach ($this->bundleSelection->getParentIdsByChild($ids) as $parentId) {
            $ids[] = $parentId;
        }

        foreach ($this->configurableSelection->getParentIdsByChild($ids) as $parentId) {
            $ids[] = $parentId;
        }

        return $ids;
    }
}
