<?php declare(strict_types=1);

namespace Newland\NeosFiltering\Factory\Override;

use Neos\Flow\ObjectManagement\Exception\InvalidObjectException;
use Newland\Contracts\Neos\Filter\DataSourcedFilterItem;
use Newland\Contracts\Neos\Filter\FilterItem;
use Newland\NeosFiltering\DataSource\DataSourceFilter;
use Newland\NeosFiltering\Factory\OverrideBehaviour;
use Newland\NeosFiltering\Items\ObstructionWrapper;
use Newland\NeosFiltering\Service\DataSourceHelper;

class LimitSelectable implements OverrideBehaviour
{
    public function applyOverride(FilterItem $item, $override, array $configuration): FilterItem
    {
        if (!($item instanceof DataSourcedFilterItem)) {
            throw new \InvalidArgumentException(
                'This override behaviour can only be used with data sourced filter items'
            );
        }

        $numberOfValidOverrides = \count(DataSourceHelper::extractValidDataSourceOptionsBasedOnStateStrings(
            $item->getDataFromDataSource(),
            $override
        ));

        if ($numberOfValidOverrides === 0) {
            return $item;
        }

        if ($numberOfValidOverrides === 1) {
            return $this->applySingleOverride($item, $override);
        }

        return $this->applyMultipleOverrides($item, $override);
    }

    /**
     * If only a single value is preselected, then there is no point in displaying the
     * filter in the frontend.
     *
     * @param string[] $override
     */
    private function applySingleOverride(DataSourcedFilterItem $item, array $override): FilterItem
    {
        $item->setState($override);
        return new ObstructionWrapper($item);
    }

    /**
     * The DataSource filter ensures that only the selected items are displayed in the frontend.
     * The `filterForAllIfNoneSelected` sets the default query state.
     *
     * @param string[] $override
     */
    private function applyMultipleOverrides(DataSourcedFilterItem $item, array $override): FilterItem
    {
        $dataSource = $item->getDataSource();
        if ($dataSource === null) {
            throw new InvalidObjectException(
                'Filter item must have data source before applying overrides'
            );
        }

        $item->filterForAllIfNoneSelected(true);
        $item->setDataSource(new DataSourceFilter($dataSource, $override));

        return $item;
    }
}
