<?php

declare(strict_types=1);

namespace MonsieurBiz\SyliusSearchPlugin\Fixture\Factory;

use Exception;
use MonsieurBiz\SyliusSearchPlugin\Entity\Product\FilterableInterface;
use Sylius\Bundle\CoreBundle\Fixture\Factory\AbstractExampleFactory;
use Sylius\Bundle\CoreBundle\Fixture\OptionsResolver\LazyOption;
use Sylius\Component\Product\Model\ProductAttributeInterface;
use Sylius\Component\Product\Model\ProductOptionInterface;
use Sylius\Component\Resource\Repository\RepositoryInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;

class FilterableFixtureFactory extends AbstractExampleFactory implements FilterableFixtureFactoryInterface
{
    public function __construct(
        private readonly RepositoryInterface $productAttributeRepository,
        private readonly RepositoryInterface $productOptionRepository,
    ) {
    }

    protected function configureOptions(OptionsResolver $resolver): void
    {
        $resolver
            ->setDefault('attribute', null)
                ->setAllowedTypes('attribute', ['null', 'string', ProductAttributeInterface::class])
                ->setNormalizer('attribute', LazyOption::findOneBy($this->productAttributeRepository, 'code'))
            ->setDefault('option', null)
                ->setAllowedTypes('option', ['null', 'string', ProductOptionInterface::class])
                ->setNormalizer('option', LazyOption::findOneBy($this->productOptionRepository, 'code'))
            ->setDefault('filterable', true)
        ;
    }

    public function create(array $options = []): object
    {
        $optionsResolver = new OptionsResolver();
        $this->configureOptions($optionsResolver);
        $options = $optionsResolver->resolve($options);

        if (array_key_exists('attribute', $options) && null !== $options['attribute']) {
            $object = $options['attribute'];
        } elseif (array_key_exists('option', $options) && null !== $options['option']) {
            $object = $options['option'];
        } else {
            throw new Exception('You need to specify an attribute or an option to be filterable.');
        }

        if (!$object instanceof FilterableInterface) {
            throw new Exception(sprintf('Your class "%s" is not an instance of %s', \get_class($object), FilterableInterface::class));
        }

        $object->setFilterable((bool) ($options['filterable'] ?? false));

        return $object;
    }
}
