<?php

namespace WordpressModels\DependencyInjection\HookAttributes;

use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Container compiler pass to register hooks from attributes to the {@see ContainerHookRegistry}.
 *
 * This compiler pass registers all services with the 'action', 'filter' and 'ajax_action' tags to the
 * {@see ContainerHookRegistry} service. This is done by adding a method call to the {@see ContainerHookRegistry}
 * service for each tagged service.
 */
class HookAttributesCompilerPass implements CompilerPassInterface
{

    public function process(ContainerBuilder $container)
    {
        if (!$container->hasDefinition(ContainerHookRegistry::class)) {
            return;
        }

        $service = $container->getDefinition(ContainerHookRegistry::class);

        // find all services with the action and filter tags
        foreach ($container->findTaggedServiceIds('action') as $id => $tags) {
            foreach ($tags as $tag) {
                // create the callable reference
                $callable = [new Reference($id), $tag['method']];

                if (!$tag['admin'] || is_admin()) {
                    // add the method call
                    $service->addMethodCall('addHook', [
                        $id,
                        'action',
                        $callable,
                        $tag['hook'],
                        $tag['priority'],
                        $tag['accepted_args'],
                        $tag['when'],
                        $tag['admin']
                    ]);
                }
            }
        }
        foreach ($container->findTaggedServiceIds('filter') as $id => $tags) {
            foreach ($tags as $tag) {
                // create the callable reference
                $callable = [new Reference($id), $tag['method']];

                if (!$tag['admin'] || is_admin()) {
                    // add the method call
                    $service->addMethodCall('addHook', [
                        $id,
                        'filter',
                        $callable,
                        $tag['hook'],
                        $tag['priority'],
                        $tag['accepted_args'],
                        $tag['when'],
                        $tag['admin']
                    ]);
                }
            }
        }

        // ajax actions
        foreach ($container->findTaggedServiceIds('ajax_action') as $id => $tags) {
            foreach ($tags as $tag) {
                $method = $tag['method'];
                unset($tag['method']);
                $handler = [new Reference($id), $method];

                // prepare for NamedArgumentResolver
                $args = ['$handler' => $handler];
                foreach ($tag as $key => $value) {
                    $args['$' . $key] = $value;
                }

                // add the method call
                $service->addMethodCall('addAjaxHook', $args);
            }
        }
    }

}