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

declare(strict_types=1);

use NetBoxStore\Config;
use NetBoxStore\Database\RepositoryFactory;
use NetBoxStore\Security\Auth;
use NetBoxStore\Security\HttpClient;
use NetBoxStore\Security\SsrfGuard;
use NetBoxStore\Sync\SyncService;

$root = dirname(__DIR__);
require $root . '/vendor/autoload.php';

$command = $argv[1] ?? '';
if ($command === 'hash-password') {
    try {
        $password = $argv[2] ?? getenv('STORE_ADMIN_PASSWORD_TO_HASH') ?: '';
        if ($password === '') {
            throw new RuntimeException("Usage: php bin/console hash-password 'a-long-random-password'");
        }
        fwrite(STDOUT, Auth::passwordHash($password) . PHP_EOL);
        exit(0);
    } catch (Throwable $exception) {
        fwrite(STDERR, $exception->getMessage() . PHP_EOL);
        exit(1);
    }
}
if (!in_array($command, ['sync', 'bootstrap'], true)) {
    fwrite(STDERR, "Usage: php bin/console <hash-password|bootstrap|sync> [--watch] [--source=slug] [--interval=900] [--fail-fast]" . PHP_EOL);
    exit(1);
}

try {
    $config = Config::load($root);
    $repository = RepositoryFactory::create($config);
    $repository->initialize();
    $guard = new SsrfGuard($config);
    $http = new HttpClient($config, $guard);
    $service = new SyncService($repository, $config, $http, $guard);
    if (!in_array('--no-bootstrap', $argv, true)) {
        $bootstrapped = $service->ensureDefaultSource();
        if ($bootstrapped['created']) {
            fwrite(STDOUT, 'Default source created: ' . $bootstrapped['source']['slug'] . PHP_EOL);
        }
    }
    if ($command === 'bootstrap') {
        exit(0);
    }
    $watch = in_array('--watch', $argv, true);
    $failFast = in_array('--fail-fast', $argv, true);
    $sources = [];
    $interval = $config->scheduler['interval'];
    foreach ($argv as $argument) {
        if (str_starts_with($argument, '--source=')) {
            $sources[] = substr($argument, 9);
        } elseif (str_starts_with($argument, '--interval=')) {
            $interval = max(30, min(604_800, (int) substr($argument, 11)));
        }
    }
    $stopped = false;
    if (function_exists('pcntl_async_signals')) {
        pcntl_async_signals(true);
        pcntl_signal(SIGINT, static function () use (&$stopped): void { $stopped = true; });
        pcntl_signal(SIGTERM, static function () use (&$stopped): void { $stopped = true; });
    }
    do {
        try {
            $runs = $service->syncAll($sources === [] ? null : $sources, $failFast, $watch ? 'scheduled' : 'command');
            fwrite(STDOUT, json_encode($runs, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR) . PHP_EOL);
            if (!$watch && array_filter($runs, static fn (array $run): bool => $run['status'] === 'failed')) {
                exit(1);
            }
        } catch (Throwable $exception) {
            fwrite(STDERR, 'Sync failed: ' . $exception->getMessage() . PHP_EOL);
            if (!$watch) {
                exit(1);
            }
        }
        if ($watch && !$stopped) {
            for ($second = 0; $second < $interval && !$stopped; $second++) {
                sleep(1);
            }
        }
    } while ($watch && !$stopped);
    exit(0);
} catch (Throwable $exception) {
    fwrite(STDERR, $exception->getMessage() . PHP_EOL);
    exit(1);
}
