<?php
declare(strict_types=1);

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

use PpPhp\Core\Platform\DI\Compiler\CompilerContext;
use PpPhp\Core\Platform\DI\Compiler\CompilerStageInterface;
use PpPhp\Core\Platform\DI\Compiler\Factory\FactoryGenerationSummary;
use PpPhp\Core\Platform\DI\Compiler\Factory\FactoryGenerator;
use PpPhp\Core\Platform\DI\Definition\ClassDefinition;

final class FactoryGenerationStage implements CompilerStageInterface
{
    public function __construct(private readonly FactoryGenerator $generator = new FactoryGenerator()) {}

    public function name(): string
    {
        return 'factory-generation';
    }

    public function process(CompilerContext $context): void
    {
        $results = [];

        foreach ($context->definitions()->all() as $definition) {
            if (!$definition instanceof ClassDefinition) {
                continue;
            }

            if (!class_exists($definition->className())) {
                $context->warning('Cannot generate factory for missing class.', [
                    'serviceId' => $definition->id(),
                    'className' => $definition->className(),
                ]);
                continue;
            }

            $result = $this->generator->generate($definition, $context->basePath());
            $results[] = $result;

            foreach ($result->warnings() as $warning) {
                $context->warning($warning, ['serviceId' => $definition->id()]);
            }
        }

        $generated = count(array_filter($results, static fn ($r): bool => $r->generated()));
        $summary = new FactoryGenerationSummary(count($results), $generated, count($results) - $generated, $results);
        $context->setMetadata('factoryGeneration', $summary->toArray());
    }
}
