#!/usr/bin/env php
<?php

declare(strict_types=1);

/*
 * Iglubox Backup for cPanel & WHM 1.10.0 — the root agent.
 *
 *   iglubox-backup connect <api-url>        connect this server (prints a code to approve in Iglubox)
 *   iglubox-backup status                   connection, schedule, accounts, the last backups
 *   iglubox-backup run [--account USER]     back up now (every chosen account, or one)
 *   iglubox-backup cron                     the timer: the scheduled backup when due, then the queued restores
 *   iglubox-backup snapshots                the snapshots in Iglubox
 *   iglubox-backup restore --user U --run ID [--type files|mail|database|account] [--db NAME] [--path P]... [--inplace]
 *   iglubox-backup restore-as-user          (internal: a file restore running as the account's user)
 */

// warnings never mix with the JSON this command prints (the root agent reads the output of restore-as-user)
ini_set('display_errors', 'stderr');

spl_autoload_register(static function (string $class): void {
    $base = dirname(__DIR__);
    foreach (['IgluboxCp\\Lib\\' => "$base/lib/", 'IgluboxCp\\' => "$base/src/"] as $prefix => $dir) {
        if (strpos($class, $prefix) === 0) {
            $f = $dir . str_replace('\\', '/', substr($class, strlen($prefix))) . '.php';
            if (is_file($f)) {
                require $f;
            }
            return;
        }
    }
});

use IgluboxCp\Agent;
use IgluboxCp\Config;

$args = array_slice($argv, 1);
$cmd = array_shift($args) ?? 'help';

/** @return array<string, string[]> */
function options(array $args): array
{
    $o = [];
    for ($i = 0; $i < count($args); $i++) {
        if (strpos($args[$i], '--') === 0) {
            $k = substr($args[$i], 2);
            $v = isset($args[$i + 1]) && strpos($args[$i + 1], '--') !== 0 ? $args[++$i] : '1';
            $o[$k][] = $v;
        }
    }
    return $o;
}

try {
    if ($cmd === 'restore-as-user') {
        echo json_encode(Agent::restoreAsUser((string) stream_get_contents(STDIN)));
        exit(0);
    }
    if (function_exists('posix_geteuid') && posix_geteuid() !== 0 && !getenv('IGLUBOX_BACKUP_ALLOW_NON_ROOT')) {
        fwrite(STDERR, "Run iglubox-backup as root.\n");
        exit(1);
    }
    $config = new Config();
    $agent = new Agent($config);
    $o = options($args);
    switch ($cmd) {
        case 'connect':
            $start = $agent->connectStart((string) ($args[0] ?? ''), (string) gethostname());
            echo "Open {$start['verificationUrlComplete']} and approve the code {$start['code']}.\n";
            for ($i = 0; $i < 200; $i++) {
                sleep((int) $start['interval']);
                $r = $agent->connectPoll();
                if ($r['status'] === 'connected') {
                    echo 'Connected to ' . $config->get('account') . "\n";
                    exit(0);
                }
                if (in_array($r['status'], ['denied', 'expired', 'consumed'], true)) {
                    throw new RuntimeException('The request was ' . $r['status']);
                }
            }
            throw new RuntimeException('No approval came in time');
        case 'status':
            echo json_encode(['connected' => $config->connected(), 'url' => $config->get('url'), 'account' => $config->get('account'), 'schedule' => $agent->scheduleText(), 'accounts' => array_column($agent->accounts(), 'user'), 'backup' => $agent->job()->progress()], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES) . "\n";
            break;
        case 'run':
            $p = $agent->run('manual', isset($o['account']) ? $o['account'] : null);
            echo json_encode($p, JSON_UNESCAPED_SLASHES) . "\n";
            exit(empty($p['done']) ? 1 : 0);
        case 'cron':
            echo json_encode($agent->cron(), JSON_UNESCAPED_SLASHES) . "\n";
            break;
        case 'snapshots':
            foreach ($agent->repo()->snapshots() as $id) {
                echo $id . '  ' . gmdate('Y-m-d H:i', Agent::ulidTime($id)) . " UTC\n";
            }
            break;
        case 'restore':
            $req = ['type' => $o['type'][0] ?? 'files', 'user' => $o['user'][0] ?? '', 'run' => $o['run'][0] ?? '', 'db' => $o['db'][0] ?? null, 'paths' => $o['path'] ?? [], 'target' => isset($o['inplace']) ? 'inplace' : 'folder'];
            echo json_encode($agent->restore($req), JSON_UNESCAPED_SLASHES) . "\n";
            break;
        default:
            echo "iglubox-backup connect|status|run|cron|snapshots|restore (see the head of this file)\n";
            exit($cmd === 'help' ? 0 : 2);
    }
} catch (Throwable $e) {
    fwrite(STDERR, 'iglubox-backup: ' . $e->getMessage() . "\n");
    exit(1);
}
