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

declare(strict_types=1);

use App\App\Container;
use App\Domain\Auth\Role;
use App\Domain\Auth\TokenHasher;
use App\Domain\Auth\TokenIssuer;
use App\Domain\Auth\TokenKind;
use App\Infrastructure\Auth\ServiceTokenBootstrap;
use App\Infrastructure\Auth\TokenRecord;
use App\Infrastructure\Auth\TokenRepository;

require __DIR__ . '/../vendor/autoload.php';

$argv = $_SERVER['argv'] ?? [];
$command = $argv[1] ?? null;

$phinxBin = __DIR__ . '/../vendor/bin/phinx';
$phinxConfig = __DIR__ . '/../config/phinx.php';

$run = static function (string $phinxCommand) use ($phinxBin, $phinxConfig): never {
    $cmd = sprintf(
        '%s %s --configuration=%s',
        escapeshellarg($phinxBin),
        $phinxCommand,
        escapeshellarg($phinxConfig)
    );
    passthru($cmd, $exitCode);
    exit($exitCode);
};

/**
 * @param array<int, string> $argv
 */
$flag = static function (array $argv, string $name): ?string {
    $prefix = '--' . $name . '=';
    foreach ($argv as $arg) {
        if (str_starts_with($arg, $prefix)) {
            return substr($arg, strlen($prefix));
        }
    }

    return null;
};

/**
 * @param array<int, string> $argv
 */
$hasFlag = static function (array $argv, string $name): bool {
    return in_array('--' . $name, $argv, true);
};

switch ($command) {
    case 'db:migrate':
        $run('migrate');
        // no break
    case 'db:rollback':
        $run('rollback');
        // no break
    case 'db:seed':
        $run('seed:run');
        // no break

    case 'auth:bootstrap-service-token':
        $container = Container::build();
        /** @var ServiceTokenBootstrap $boot */
        $boot = $container->get(ServiceTokenBootstrap::class);
        /** @var string $rawToken */
        $rawToken = $container->get('settings.ui_service_token');
        $boot->bootstrap($rawToken);
        exit(0);

    case 'auth:create-token':
        $kindArg = $flag($argv, 'kind') ?? '';
        $roleArg = $flag($argv, 'role');
        $quiet = $hasFlag($argv, 'quiet');

        $kind = TokenKind::tryFrom($kindArg);
        if ($kind === null) {
            fwrite(STDERR, "Unknown --kind: {$kindArg}. Admin tokens are the only kind supported here.\n");
            exit(1);
        }
        if ($kind === TokenKind::Service) {
            fwrite(STDERR, "Refusing to create a service token via this command. Use UI_SERVICE_TOKEN + auth:bootstrap-service-token.\n");
            exit(1);
        }
        if ($kind === TokenKind::Reporter || $kind === TokenKind::Consumer) {
            fwrite(STDERR, "Reporter/consumer tokens are bound to records and are issued via M04 endpoints, not this CLI.\n");
            exit(1);
        }

        // kind=admin from here on.
        $role = $roleArg !== null ? Role::tryFrom(strtolower($roleArg)) : null;
        if ($role === null) {
            fwrite(STDERR, "Admin tokens require --role=viewer|operator|admin.\n");
            exit(1);
        }

        $container = Container::build();
        /** @var TokenIssuer $issuer */
        $issuer = $container->get(TokenIssuer::class);
        /** @var TokenHasher $hasher */
        $hasher = $container->get(TokenHasher::class);
        /** @var TokenRepository $repo */
        $repo = $container->get(TokenRepository::class);

        $raw = $issuer->issue(TokenKind::Admin);
        $hash = $hasher->hash($raw);
        $repo->create(new TokenRecord(
            id: null,
            kind: TokenKind::Admin,
            hash: $hash,
            prefix: substr($raw, 0, 8),
            reporterId: null,
            consumerId: null,
            role: $role,
            expiresAt: null,
            revokedAt: null,
            lastUsedAt: null,
        ));

        if ($quiet) {
            fwrite(STDOUT, $raw);
        } else {
            fwrite(STDOUT, $raw . "\n");
            fwrite(STDERR, "Created admin token (role={$role->value}). The token is only shown once.\n");
        }
        exit(0);

    case null:
    case '--help':
    case '-h':
        fwrite(STDOUT, <<<TXT
            Usage: console <command>

            Commands:
              db:migrate                          Run Phinx migrations
              db:rollback                         Roll back the most recent migration
              db:seed                             Run all seeders idempotently
              auth:bootstrap-service-token        Provision UI_SERVICE_TOKEN row in api_tokens
              auth:create-token --kind=admin --role=admin|operator|viewer [--quiet]
                                                  Create an admin token; raw token printed to stdout

            TXT);
        exit(0);

    default:
        fwrite(STDERR, "Unknown command: {$command}\n");
        exit(1);
}
