#!/usr/bin/env php
<?php
declare(strict_types=1);
ini_set('serialize_precision', '-1');
if (($argv[1] ?? '') === 'compatibility') { array_splice($argv, 1, 1); require __DIR__.'/compatibility.php'; exit; }
require dirname(__DIR__).'/vendor/autoload.php';
use Icom\Application;
use Icom\Config;
use Icom\Database\{Database, Migrator};
use Icom\Http\Response;
use Nyholm\Psr7\ServerRequest;
$root = dirname(__DIR__);
$command = $argv[1] ?? 'help';
try {
    switch ($command) {
        case 'help':
        case '--help':
            echo "ICOM Framework ".Application::VERSION." (developer preview)\n\n";
            echo "  about                  Runtime and release information\n  compatibility         Preflight PHP/extensions; --production --pdo=sqlite|mysql --oidc\n  key:generate           Set an empty APP_KEY without printing it\n  config:check           Validate private application config; --production\n  routes                 List registered application routes\n  api:spec               Export selected public OpenAPI 3.1.2 description\n  api:check              Check documented method/path registrations\n  make:module Name       Scaffold an explicitly registered module\n  modules:list           Validate and list module dependency order\n  architecture:check     Check declared module boundaries (dev dependencies)\n  make:controller Name   Create a controller; never overwrite\n  backup:create          Snapshot SQLite; --output=/private/new.sqlite\n  backup:verify FILE     Verify a private standalone SQLite snapshot\n  migrate:status         Inspect migration ledger without executing files\n  ops:check [queue]      Inspect dependencies and background-work alerts\n  ops:metrics [queue]    Emit private Prometheus text gauges\n  migrate                Apply pending database migrations\n  cache:clear            Clear application cache records\n  test                   Run the regression suite\n  benchmark [iterations] In-memory kernel microbenchmark\n  user:create            Provision account using --password-stdin\n  user:disable ID        Disable account and revoke sessions\n  user:roles ID roles    Set comma-separated role names\n  sessions:prune         Remove expired sessions\n  security:prune         Remove expired identity challenges\n  password:issue-reset   Save a reset token using --output\n  oidc:link ID           Link a verified subject using --subject-stdin\n  oidc:unlink ID         Unlink subject and revoke account sessions\n  audit:recent [id] [n]   Read bounded identity audit events\n  queue:push handler {}  Enqueue a registered job\n  queue:work [q] [n] [s] Run bounded worker; --stop-when-empty --lease=60 --memory=128\n  queue:status           Count pending/reserved/failed jobs\n  queue:failed           List failed jobs without payloads\n  queue:retry ID         Retry a failed job\n  outbox:relay [n]       Atomically hand off a bounded batch to SQL queue\n  outbox:status          Count pending/published/failed messages\n  outbox:failed [n]      Inspect failures without payloads\n  outbox:retry ID        Retry a repaired failed message\n  outbox:prune [days] [n] Remove published deduplication tombstones\n  schedule:list         Inspect UTC schedules and persisted slots\n  schedule:run          Record the latest due occurrences\n  maintenance:run       Schedule, relay and run maintenance queue\n";
            break;
        case 'about':
            echo json_encode(['framework' => 'ICOM', 'version' => Application::VERSION, 'php' => PHP_VERSION, 'sapi' => PHP_SAPI, 'preview' => true], JSON_PRETTY_PRINT)."\n";
            break;
        case 'key:generate':
            $file = $root.'/.env';
            $content = is_file($file) ? file_get_contents($file) : file_get_contents($root.'/.env.example');
            if (preg_match('/^APP_KEY=(.+)$/m', $content)) throw new RuntimeException('APP_KEY already exists. Key rotation requires a planned migration.');
            $line = 'APP_KEY='.base64_encode(random_bytes(32));
            $content = preg_match('/^APP_KEY=/m', $content) ? preg_replace('/^APP_KEY=.*$/m', $line, $content) : $content."\n".$line."\n";
            $temp = tempnam($root, '.env-');
            if ($temp === false) throw new RuntimeException('Cannot create configuration.');
            try {
                chmod($temp, 0600);
                if (file_put_contents($temp, $content) !== strlen($content) || !rename($temp, $file)) throw new RuntimeException('Cannot save configuration.');
            } finally { if (is_file($temp)) unlink($temp); }
            echo "Application key generated in .env (value not displayed).\n";
            break;
        case 'routes':
            $app = require $root.'/bootstrap.php';
            foreach ($app->router->all() as $route) printf("%-7s %-32s %s\n", $route->method, $route->path, $route->routeName ?? '');
            break;
        case 'make:controller':
            $name = $argv[2] ?? '';
            if (!preg_match('/^[A-Z][A-Za-z0-9]*Controller$/D', $name)) throw new InvalidArgumentException('Use a class name such as ExampleController.');
            $file = fopen($root.'/app/'.$name.'.php', 'x');
            if (!$file) throw new RuntimeException('Controller exists or destination is unavailable.');
            $code = "<?php\ndeclare(strict_types=1);\nnamespace App;\nuse Icom\\Http\\Response;\nuse Psr\\Http\\Message\\ResponseInterface;\nfinal class $name\n{\n    public function __invoke(): ResponseInterface\n    { return Response::json(['message' => 'Hello from $name']); }\n}\n";
            try { if (fwrite($file, $code) !== strlen($code)) throw new RuntimeException('Controller write failed.'); }
            finally { fclose($file); }
            echo "Created app/$name.php. Register it in routes/web.php.\n";
            break;
        case 'migrate':
            $app = require $root.'/bootstrap.php';
            $scope = $app->container->scope();
            try {
                $migrator = new Migrator($scope->get(Database::class), $root.'/migrations', $root.'/storage/migrations.lock');
                $ran = $migrator->run();
                echo $ran === [] ? "No pending migrations.\n" : implode("\n", $ran)."\n";
            } finally { $scope->clear(); }
            break;
        case 'cache:clear':
            $app = require $root.'/bootstrap.php';
            if (!$app->container->get(\Psr\SimpleCache\CacheInterface::class)->clear()) throw new RuntimeException('Some cache records could not be cleared.');
            echo "Cache records cleared. Rate-limit locks were preserved.\n";
            break;
        case 'test':
            require $root.'/tests/run.php';
            break;
        case 'benchmark':
            $iterations = filter_var($argv[2] ?? '10000', FILTER_VALIDATE_INT);
            if ($iterations === false || $iterations < 100 || $iterations > 100000) throw new InvalidArgumentException('Iterations must be 100–100000.');
            $app = new Application();
            $app->get('/hello/{name}', static fn (string $name) => Response::json(['hello' => $name]));
            $request = new ServerRequest('GET', 'http://localhost/hello/Developer');
            for ($i = 0; $i < 1000; $i++) $app->handle($request);
            $samples = []; $start = hrtime(true);
            for ($i = 0; $i < $iterations; $i++) {
                $t = hrtime(true); $app->handle($request); $samples[] = (hrtime(true) - $t) / 1000;
            }
            $seconds = (hrtime(true) - $start) / 1e9; sort($samples);
            echo json_encode(['workload' => 'In-memory GET /hello/{name}; no network, DB or production middleware', 'php' => PHP_VERSION, 'sapi' => PHP_SAPI, 'os' => PHP_OS_FAMILY, 'opcache_cli' => ini_get('opcache.enable_cli'), 'concurrency' => 1, 'warmup' => 1000, 'iterations' => $iterations, 'elapsed_seconds' => round($seconds, 6), 'dispatches_per_second' => round($iterations / $seconds), 'p50_us' => round($samples[(int)floor(($iterations - 1) * .5)], 3), 'p95_us' => round($samples[(int)floor(($iterations - 1) * .95)], 3), 'p99_us' => round($samples[(int)floor(($iterations - 1) * .99)], 3), 'peak_php_bytes' => memory_get_peak_usage(true), 'comparative_claim' => false], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES)."\n";
            break;
        default: if (!(require __DIR__.'/backup.php') && !(require __DIR__.'/configuration.php') && !(require __DIR__.'/api.php') && !(require __DIR__.'/operations.php') && !(require __DIR__.'/modules.php') && !(require __DIR__.'/background.php') && !(require __DIR__.'/extensions.php')) throw new InvalidArgumentException('Unknown command. Run php bin/icom help.');
    }
} catch (Throwable $e) { fwrite(STDERR, 'Error: '.$e->getMessage()."\n"); exit(1); }
