<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Compiler\Stages;

use PpPhp\Core\Platform\Event\Attributes\EventListener;
use PpPhp\Core\Platform\Event\Compiler\EventArtifactWriter;
use PpPhp\Core\Platform\Event\Compiler\EventCompilerContext;
use PpPhp\Core\Platform\Event\Compiler\EventCompilerPaths;
use PpPhp\Core\Platform\Event\Compiler\EventCompilerStageInterface;
use ReflectionClass;
use Throwable;

final class AttributeMetadataCompileStage implements EventCompilerStageInterface
{
    public function __construct(private readonly EventArtifactWriter $writer = new EventArtifactWriter()) {}

    public function name(): string { return 'attribute-metadata'; }

    public function compile(EventCompilerContext $context): void
    {
        $items = [];
        foreach ($this->discoverClasses($context->basePath()) as $className) {
            try {
                if (!class_exists($className)) {
                    continue;
                }
                $reflection = new ReflectionClass($className);
                foreach ($reflection->getAttributes(EventListener::class) as $attribute) {
                    $listener = $attribute->newInstance();
                    $items[] = ['event' => $listener->event, 'class' => $className, 'method' => 'handle', 'priority' => $listener->priority, 'source' => 'class'];
                }
                foreach ($reflection->getMethods() as $method) {
                    foreach ($method->getAttributes(EventListener::class) as $attribute) {
                        $listener = $attribute->newInstance();
                        $items[] = ['event' => $listener->event, 'class' => $className, 'method' => $method->getName(), 'priority' => $listener->priority, 'source' => 'method'];
                    }
                }
            } catch (Throwable $e) {
                $context->warning('Attribute compile warning.', ['class' => $className, 'message' => $e->getMessage()]);
            }
        }
        $data = ['generatedAt' => date('c'), 'count' => count($items), 'attributes' => $items];
        $this->writer->writePhpArray(EventCompilerPaths::cacheFile($context->basePath(), 'compiled-attribute-listeners.php'), $data);
        $context->setArtifact('attributeMetadata', $data);
    }

    private function discoverClasses(string $basePath): array
    {
        $cache = rtrim($basePath, DIRECTORY_SEPARATOR) . '/storage/cache/platform-classmap.json';
        if (!is_file($cache)) {
            return [];
        }
        $data = json_decode((string) file_get_contents($cache), true);
        $classes = [];
        foreach (($data['classes'] ?? $data ?? []) as $key => $value) {
            if (is_string($key) && str_starts_with($key, 'PpPhp\\')) {
                $classes[] = $key;
            } elseif (is_array($value) && isset($value['class'])) {
                $classes[] = (string) $value['class'];
            } elseif (is_string($value) && str_starts_with($value, 'PpPhp\\')) {
                $classes[] = $value;
            }
        }
        return array_values(array_unique($classes));
    }
}
