<?php
declare(strict_types=1);

namespace PpPhp\Core\Platform\DI\Integration;

use PpPhp\Core\Platform\Bootstrap\PlatformBootstrap;
use PpPhp\Core\Platform\DI\Container;
use ReflectionClass;
use Throwable;

final class PlatformContainerFactory
{
    private array $warnings = [];
    private array $registered = [];

    public function create(string $basePath): Container
    {
        $container = new Container();

        foreach ($this->discoverClasses($basePath) as $className) {
            if (!$this->isEligible($className)) {
                continue;
            }

            $container->register($className)->tag('platform.runtime')->metadata('source', 'classmap');
            $this->registered[] = $className;
        }

        $container->value('platform.base_path', $basePath);
        $container->value('platform.container.registered_count', count($this->registered));

        return $container;
    }

    public function registered(): array
    {
        return $this->registered;
    }

    public function warnings(): array
    {
        return $this->warnings;
    }

    private function discoverClasses(string $basePath): array
    {
        $classes = [];

        $loader = PlatformBootstrap::loader();

        if ($loader && method_exists($loader, 'classMap')) {
            foreach (array_keys($loader->classMap()) as $className) {
                if (str_starts_with($className, 'PpPhp\\Core\\Platform\\') || str_starts_with($className, 'PpPhp\\Modules\\')) {
                    $classes[] = $className;
                }
            }
        }

        if ($classes !== []) {
            return array_values(array_unique($classes));
        }

        // Fallback for older environments: scan PHP files and infer classes from namespace/class declarations.
        foreach (['core/Platform', 'modules'] as $root) {
            $path = rtrim($basePath, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $root;
            if (!is_dir($path)) {
                continue;
            }

            $iterator = new \RecursiveIteratorIterator(
                new \RecursiveDirectoryIterator($path, \FilesystemIterator::SKIP_DOTS)
            );

            foreach ($iterator as $file) {
                if (!$file instanceof \SplFileInfo || !$file->isFile() || strtolower($file->getExtension()) !== 'php') {
                    continue;
                }

                $class = $this->extractClassName($file->getPathname());
                if ($class !== null) {
                    $classes[] = $class;
                }
            }
        }

        return array_values(array_unique($classes));
    }

    private function extractClassName(string $file): ?string
    {
        $content = (string) file_get_contents($file);
        $namespace = '';

        if (preg_match('/^\s*namespace\s+([^;]+);/m', $content, $m)) {
            $namespace = trim($m[1]);
        }

        if (!preg_match('/^\s*(?:final\s+|abstract\s+)?class\s+([A-Za-z_][A-Za-z0-9_]*)/m', $content, $m)) {
            return null;
        }

        return $namespace !== '' ? $namespace . '\\' . $m[1] : $m[1];
    }

    private function isEligible(string $className): bool
    {
        try {
            if (!class_exists($className)) {
                return false;
            }

            $reflection = new ReflectionClass($className);

            if (!$reflection->isInstantiable()) {
                return false;
            }

            if ($reflection->isAnonymous()) {
                return false;
            }

            return true;
        } catch (Throwable $e) {
            $this->warnings[] = [
                'class' => $className,
                'message' => $e->getMessage(),
            ];
            return false;
        }
    }
}
