#!/usr/bin/env php
<?php
/**
 * ORION-LOGISTICS command line tool.
 *   php bin/console migrate                 create / update the database schema
 *   php bin/console seed [--force]          load demo data (+ an admin account)
 *   php bin/console user:create <username> <email> <role> [password]
 *   php bin/console key:generate <label> [read|write]
 *   php bin/console password:hash <password>
 *   php bin/console cron [--dry]            run scheduled jobs (same as cron.php)
 *   php bin/console serve [port]            dev server on 127.0.0.1 (needs APP_ENV=development)
 */
if (PHP_SAPI !== 'cli') { http_response_code(404); exit; }
define('BASE_URL', ''); define('BASE_DIR', dirname(__DIR__));
require_once BASE_DIR . '/config/db.php';
$db = getDB(); $argv = $_SERVER['argv']; $cmd = $argv[1] ?? 'help';
$line = fn(string $s) => fwrite(STDOUT, $s . "\n");

/** Split a SQL script into statements (schema files contain no semicolons inside literals). */
function sql_statements(string $sql): array {
    $sql = preg_replace('/^\s*--.*$/m', '', $sql);
    return array_values(array_filter(array_map('trim', explode(";\n", $sql . "\n")), fn($s) => $s !== ''));
}
function to_sqlite(string $s): string {
    $s = preg_replace('/\b(?:BIG)?INT\s+AUTO_INCREMENT\s+PRIMARY\s+KEY/i', 'INTEGER PRIMARY KEY AUTOINCREMENT', $s);
    $s = preg_replace('/\)\s*ENGINE=[^;]*$/i', ')', $s);
    return $s;
}
function run_script(PDO $db, string $sql): int {
    $n = 0;
    foreach (sql_statements($sql) as $st) {
        if (Database::isSqlite()) $st = to_sqlite($st);
        try { $db->exec($st); $n++; }
        catch (Throwable $e) {
            if (preg_match('/already exists|Duplicate key name|Duplicate column/i', $e->getMessage())) continue;
            fwrite(STDERR, "SQL failed: " . $e->getMessage() . "\n  " . substr($st, 0, 120) . "\n"); exit(1);
        }
    }
    return $n;
}
function pw(int $len = 14): string { $c = 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz23456789'; $o = ''; for ($i = 0; $i < $len; $i++) $o .= $c[random_int(0, strlen($c) - 1)]; return $o . 'a1A'; }

switch ($cmd) {
case 'migrate':
    $db->exec("CREATE TABLE IF NOT EXISTS orion_migrations (id " . (Database::isSqlite() ? "INTEGER PRIMARY KEY AUTOINCREMENT" : "INT AUTO_INCREMENT PRIMARY KEY") . ", migration VARCHAR(191) NOT NULL UNIQUE, applied_at DATETIME NOT NULL)");
    $files = ['000_base_schema' => BASE_DIR . '/database/schema.sql'];
    foreach (glob(BASE_DIR . '/migrations/*.sql') ?: [] as $f) $files[basename($f, '.sql')] = $f;
    ksort($files); $applied = array_column(qrows($db, "SELECT migration FROM orion_migrations"), 'migration'); $did = 0;
    foreach ($files as $name => $f) {
        if (in_array($name, $applied, true)) continue;
        $line("Applying $name …"); run_script($db, file_get_contents($f));
        $db->prepare("INSERT INTO orion_migrations(migration,applied_at) VALUES(?,?)")->execute([$name, date('Y-m-d H:i:s')]); $did++;
    }
    $line($did ? "Done ($did applied)." : 'Database is up to date.'); break;

case 'seed':
    if (qval($db, "SELECT COUNT(*) FROM orion_users") && !in_array('--force', $argv, true)) { $line('Users already exist — refusing to seed. Use --force to add demo data anyway.'); exit(1); }
    require __DIR__ . '/seed.php'; break;

case 'user:create':
    [$u, $e, $r] = [$argv[2] ?? '', $argv[3] ?? '', $argv[4] ?? ''];
    if (!$u || !$e || !isset(ROLES[$r])) { $line('Usage: user:create <username> <email> <role> [password]  roles: ' . implode(', ', array_keys(ROLES))); exit(1); }
    $p = $argv[5] ?? pw();
    $db->prepare("INSERT INTO orion_users(first_name,last_name,username,email,password,role,is_active,must_reset,created_at) VALUES(?,?,?,?,?,?,1,1,?)")->execute([ucfirst($u), '', $u, $e, password_hash($p, PASSWORD_DEFAULT), $r, date('Y-m-d H:i:s')]);
    $line("Created $r '$u'. Temporary password: $p (must be changed at first sign-in)."); break;

case 'key:generate':
    $label = $argv[2] ?? 'cli key'; $sc = ($argv[3] ?? 'read') === 'write' ? 'read,write' : 'read'; $raw = 'orl_' . bin2hex(random_bytes(24));
    $db->prepare("INSERT INTO orion_api_keys(label,key_prefix,key_hash,scopes,is_active,created_at) VALUES(?,?,?,?,1,?)")->execute([$label, substr($raw, 0, 8), hash('sha256', $raw), $sc, date('Y-m-d H:i:s')]);
    $line("API key ($sc): $raw   — store it now, it cannot be shown again."); break;

case 'password:hash': $line(password_hash($argv[2] ?? '', PASSWORD_DEFAULT)); break;
case 'cron': $_SERVER['argv'] = array_merge([$argv[0]], array_slice($argv, 2)); require BASE_DIR . '/cron.php'; break;
case 'serve':
    $port = (int)($argv[2] ?? 8000); $line("Serving on http://127.0.0.1:$port  (Ctrl+C to stop)");
    passthru(escapeshellarg(PHP_BINARY) . ' -S 127.0.0.1:' . $port . ' -t ' . escapeshellarg(BASE_DIR) . ' ' . escapeshellarg(BASE_DIR . '/bin/router.php')); break;
default: $line(trim(substr(file_get_contents(__FILE__), 20, 700), "/* \n")); }
