<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\Event\Compiler;

use PpPhp\Core\Platform\Event\Compiler\Stages\AttributeMetadataCompileStage;
use PpPhp\Core\Platform\Event\Compiler\Stages\DispatchTableCompileStage;
use PpPhp\Core\Platform\Event\Compiler\Stages\EventManifestCompileStage;
use PpPhp\Core\Platform\Event\Compiler\Stages\ListenerMetadataCompileStage;

final class EventCompilerPipeline
{
    private array $stages = [];

    public static function default(): self
    {
        $pipeline = new self();
        $pipeline->add(new EventManifestCompileStage());
        $pipeline->add(new ListenerMetadataCompileStage());
        $pipeline->add(new AttributeMetadataCompileStage());
        $pipeline->add(new DispatchTableCompileStage());
        return $pipeline;
    }

    public function add(EventCompilerStageInterface $stage): void { $this->stages[] = $stage; }

    public function stageNames(): array
    {
        return array_map(static fn (EventCompilerStageInterface $stage): string => $stage->name(), $this->stages);
    }

    public function compile(string $basePath): EventCompilerReport
    {
        $context = new EventCompilerContext($basePath);
        $timings = [];
        foreach ($this->stages as $stage) {
            $start = microtime(true);
            $stage->compile($context);
            $timings[$stage->name()] = round((microtime(true) - $start) * 1000, 3);
        }
        $context->setMetadata('timingsMs', $timings);
        return new EventCompilerReport(date('c'), $this->stageNames(), $context->artifacts(), $context->warnings(), $context->metadata());
    }
}
