<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\MainBundle\CRUD\CompilerPass;

use Chill\MainBundle\CRUD\Controller\ApiController;
use Chill\MainBundle\CRUD\Controller\CRUDController;
use Chill\MainBundle\CRUD\Exception\InvalidCrudConfiguration;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;

class CRUDControllerCompilerPass implements CompilerPassInterface
{
    public function process(ContainerBuilder $container)
    {
        $crudConfig = $container->getParameter('chill_main_crud_route_loader_config');
        $apiConfig = $container->getParameter('chill_main_api_route_loader_config');

        foreach ($crudConfig as $crudEntry) {
            $this->configureCrudController($container, $crudEntry, 'crud');
        }

        foreach ($apiConfig as $crudEntry) {
            $this->configureCrudController($container, $crudEntry, 'api');
        }
    }

    /**
     * Add a controller for each definition, and add a methodCall to inject crud configuration to controller.
     */
    private function configureCrudController(ContainerBuilder $container, array $crudEntry, string $apiOrCrud): void
    {
        $controllerClass = $crudEntry['controller'];
        if (ApiController::class === $controllerClass || CRUDController::class === $controllerClass) {
            throw InvalidCrudConfiguration::configurationRequiresControllerDefinition($crudEntry['class'], $apiOrCrud);
        }
        $controllerServiceName = 'cs'.$apiOrCrud.'_'.$crudEntry['name'].'_controller';

        // create config parameter in container
        $param = 'chill_main_'.$apiOrCrud.'_config_'.$crudEntry['name'];
        $container->setParameter($param, $crudEntry);

        if ($container->hasDefinition($controllerClass)) {
            // create an alias to not to re-create the service
            $alias = new Alias($controllerClass, true);
            $container->setAlias($controllerServiceName, $alias);

            // add the "addMethodCall"
            $container->getDefinition($controllerClass)
                ->addMethodCall('setCrudConfig', ['%'.$param.'%']);
        } else {
            $controller = new Definition($controllerClass);

            $controller->addTag('controller.service_arguments');
            $controller->setAutoconfigured(true);
            $controller->setPublic(true);

            $controller->addMethodCall('setCrudConfig', ['%'.$param.'%']);

            $container->setDefinition($controllerServiceName, $controller);
        }
    }
}
