<?php

namespace NoahVet\Reef\DependencyInjection\Compiler;

use NoahVet\Reef\Domain\Security\Model\ResourceType;
use NoahVet\Reef\Domain\Security\Policy\BSM\AbstractManufacturerWithTeamPolicy;
use NoahVet\Reef\Domain\Security\Policy\BSM\AbstractPublisherWithTeamPolicy;
use NoahVet\Reef\Domain\Security\Policy\BSM\AbstractVeterinaryEstablishmentWithTeamPolicy;
use NoahVet\Reef\Domain\Security\Policy\BSM\AbstractVeterinaryGroupWithTeamPolicy;
use NoahVet\Reef\Domain\Security\Policy\BSM\WithTeamPolicyInterface;
use NoahVet\Reef\Infrastructure\Security\BSM\ManufacturerWithTeamFactory;
use NoahVet\Reef\Infrastructure\Security\BSM\ManufacturerWithTeamResourceFinder;
use NoahVet\Reef\Infrastructure\Security\BSM\PublisherWithTeamFactory;
use NoahVet\Reef\Infrastructure\Security\BSM\PublisherWithTeamResourceFinder;
use NoahVet\Reef\Infrastructure\Security\BSM\VeterinaryEstablishmentWithTeamFactory;
use NoahVet\Reef\Infrastructure\Security\BSM\VeterinaryEstablishmentWithTeamResourceFinder;
use NoahVet\Reef\Infrastructure\Security\BSM\VeterinaryGroupWithTeamFactory;
use NoahVet\Reef\Infrastructure\Security\BSM\VeterinaryGroupWithTeamResourceFinder;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Reference;

/**
 * Enregistre automatiquement les ResourceFinders WithTeam dans le container
 * Symfony lorsqu'un développeur implémente une des policies abstraites BSM.
 *
 * Pour chaque policy taggée 'reef.iam.policy' qui étend une des classes abstraites
 * WithTeam, le CompilerPass crée et configure le ResourceFinder correspondant avec
 * le slug IAM fourni par {@see AbstractVeterinaryEstablishmentWithTeamPolicy::getResourceTypeSlug()}.
 */
class WithTeamPoliciesCompilerPass implements CompilerPassInterface
{
    /**
     * Correspondance : classe abstraite de policy → classe concrète de ResourceFinder.
     */
    private const FINDER_MAP = [
        AbstractVeterinaryEstablishmentWithTeamPolicy::class => VeterinaryEstablishmentWithTeamResourceFinder::class,
        AbstractVeterinaryGroupWithTeamPolicy::class => VeterinaryGroupWithTeamResourceFinder::class,
        AbstractManufacturerWithTeamPolicy::class => ManufacturerWithTeamResourceFinder::class,
        AbstractPublisherWithTeamPolicy::class => PublisherWithTeamResourceFinder::class,
    ];

    /**
     * Correspondance : classe concrète de ResourceFinder → factory requise.
     */
    private const FACTORY_MAP = [
        VeterinaryEstablishmentWithTeamResourceFinder::class => VeterinaryEstablishmentWithTeamFactory::class,
        VeterinaryGroupWithTeamResourceFinder::class => VeterinaryGroupWithTeamFactory::class,
        ManufacturerWithTeamResourceFinder::class => ManufacturerWithTeamFactory::class,
        PublisherWithTeamResourceFinder::class => PublisherWithTeamFactory::class,
    ];

    #[\Override]
    public function process(ContainerBuilder $container): void
    {
        // Pas de client BSM configuré — les ResourceFinders ne peuvent pas fonctionner
        if (!$container->hasDefinition('bsm_service_client')) {
            return;
        }

        foreach ($container->findTaggedServiceIds('reef.iam.policy') as $serviceId => $tags) {
            $class = $container->getDefinition($serviceId)->getClass();
            if (null === $class) {
                continue;
            }

            // Pré-filtre rapide : seules les policies WithTeam BSM sont concernées
            if (!\is_subclass_of($class, WithTeamPolicyInterface::class)) {
                continue;
            }

            foreach (self::FINDER_MAP as $abstractClass => $finderClass) {
                if (!\is_subclass_of($class, $abstractClass)) {
                    continue;
                }

                // Un seul ResourceFinder par type d'entité, même si plusieurs policies l'étendent
                if ($container->hasDefinition($finderClass)) {
                    break;
                }

                $slug = $class::getResourceTypeSlug();

                $resourceTypeDef = (new Definition(ResourceType::class))
                    ->setFactory([ResourceType::class, 'fromString'])
                    ->setArguments([$slug])
                ;

                $finderDef = (new Definition($finderClass))
                    ->setAutowired(true)
                    ->setArgument('$client', new Reference('bsm_service_client'))
                    ->setArgument('$factory', new Reference(self::FACTORY_MAP[$finderClass]))
                    ->setArgument('$resourceType', $resourceTypeDef)
                    ->addTag('reef.iam.finder')
                ;

                $container->setDefinition($finderClass, $finderDef);

                break;
            }
        }
    }
}
