<?php
/**
 * Generate OPcache preload maps (storage/preload_core.php and storage/preload_optional.php).
 *
 * @package Flowaxy\Interface\CLI\Commands
 */

declare(strict_types=1);

namespace Flowaxy\Interface\CLI\Commands;

use Flowaxy\Core\System\Autoloader\PreloadMapGenerator;
use Flowaxy\Core\System\PathResolver;
use Flowaxy\Interface\CLI\Command;

use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;

use function file_exists;
use function is_dir;
use function is_file;
use function str_contains;
use function str_replace;
use function substr;

final class PreloadGenerateCommand extends Command
{
    public function getName(): string
    {
        return 'preload:generate';
    }

    public function getDescription(): string
    {
        return 'Generate OPcache preload maps (core + optional) into storage/';
    }

    public function getHelp(): string
    {
        return "Usage:\n"
            . "  php index.php preload:generate\n";
    }

    protected function handle(array $args): int
    {
        $root = PathResolver::root();
        $flowaxyDir = PathResolver::flowaxy();
        $storageDir = PathResolver::storage();

        if (!is_dir($flowaxyDir) || !is_dir($storageDir)) {
            $this->error('Required directories are missing.');
            return 1;
        }

        $classMap = $this->buildClassMapFromFilesystem($flowaxyDir);
        if ($classMap === []) {
            $this->error('No classes found to generate preload map.');
            return 1;
        }

        $generator = new PreloadMapGenerator();
        $maps = $generator->generate($classMap);

        $coreFile = $storageDir . DS . 'preload_core.php';
        $optionalFile = $storageDir . DS . 'preload_optional.php';

        $okCore = $generator->saveCorePreload($coreFile, $maps['core']);
        $okOptional = $generator->saveOptionalPreload($optionalFile, $maps['optional']);

        if (!$okCore || !$okOptional) {
            $this->error('Failed to write preload files. Check permissions for storage/.');
            return 1;
        }

        $this->output('OK: generated preload maps:');
        $this->output('  - ' . $coreFile);
        $this->output('  - ' . $optionalFile);

        return 0;
    }

    /**
     * Build a naive class map from filesystem paths under flowaxy/.
     * Assumption: class namespace matches file path (Flowaxy\<RelativePathWithoutExt>).
     *
     * @return array<string, string> class => absolute file path
     */
    private function buildClassMapFromFilesystem(string $flowaxyDir): array
    {
        $map = [];

        $it = new RecursiveIteratorIterator(
            new RecursiveDirectoryIterator($flowaxyDir, RecursiveDirectoryIterator::SKIP_DOTS),
            RecursiveIteratorIterator::LEAVES_ONLY
        );

        foreach ($it as $file) {
            if (!$file->isFile() || $file->getExtension() !== 'php') {
                continue;
            }

            $path = (string) $file->getPathname();

            // Skip tests
            if (str_contains($path, DS . 'Support' . DS . 'Tests' . DS)) {
                continue;
            }

            // relative path from flowaxy/
            $relative = str_replace($flowaxyDir . DS, '', $path);
            $relative = str_replace(['/', '\\'], DS, $relative);

            // Remove .php extension
            $relativeNoExt = substr($relative, 0, -4);

            // Namespace
            $class = 'Flowaxy\\' . str_replace(DS, '\\', $relativeNoExt);

            $map[$class] = $path;
        }

        return $map;
    }
}
