<?php
declare(strict_types=1);

namespace App\Framework\Core\Events;

use App\Framework\Core\AttributeMapper;
use ReflectionClass;
use ReflectionMethod;

/**
 * Mapper für das OnEvent-Attribut
 */
final class EventHandlerMapper implements AttributeMapper
{
    /**
     * Gibt die Attributklasse zurück, die dieser Mapper verarbeitet
     */
    public function getAttributeClass(): string
    {
        return OnEvent::class;
    }

    /**
     * Implementiert die map-Methode aus dem AttributeMapper-Interface
     *
     * @param object $reflectionTarget Das Reflektionsobjekt (ReflectionClass|ReflectionMethod)
     * @param object $attributeInstance Die Attributinstanz
     * @return array|null Die Attributdaten oder null, wenn nicht verarbeitet werden kann
     */
    public function map(object $reflectionTarget, object $attributeInstance): ?array
    {
        if (!($reflectionTarget instanceof ReflectionMethod)) {
            return null;
        }

        $parameters = $reflectionTarget->getParameters();

        // Event-Handler müssen mindestens einen Parameter haben (das Event)
        if (count($parameters) < 1) {
            return null;
        }

        $eventType = $parameters[0]->getType();
        if (!$eventType || $eventType->isBuiltin()) {
            return null;
        }

        $eventClassName = $eventType->getName();

        return [
            'class' => $reflectionTarget->getDeclaringClass()->getName(),
            'method' => $reflectionTarget->getName(),
            'event_class' => $eventClassName,
            #'reflection' => $reflectionTarget,
            'attribute_data' => [
                'priority' => $attributeInstance->priority ?? 0,
                'stopPropagation' => $attributeInstance->stopPropagation ?? false
            ],
        ];
    }

    /**
     * Verarbeitet ein Event-Handler-Attribut
     *
     * @param array $attributeData Array mit Attributdaten aus der Discovery
     * @return array Verarbeitete Attributdaten
     */
    public function process(array $attributeData): array
    {
        // Nach Priorität sortieren (höhere Werte zuerst)
        usort($attributeData, function ($a, $b) {
            $priorityA = $a['attribute']->priority ?? 0;
            $priorityB = $b['attribute']->priority ?? 0;

            return $priorityB <=> $priorityA;
        });

        return $attributeData;
    }
}
