<?php
/**
 * WHP Magic Login Token Creator.
 *
 * Replaces `wp login create <user>` with a direct WP bootstrap, eliminating
 * the wp-cli framework boot cost. Wire-compatible with the patched
 * wp-cli-login-server.php mu-plugin (same option/transient/signature shape).
 *
 * Usage (run inside the site's container, as the site user):
 *   php /home/<user>/public_html/wp-content/.whp/whp-magic-login-create.php <username>
 *
 * Outputs the magic-login URL on stdout. Exits non-zero on error with a
 * single-line message on stderr.
 */

if (PHP_SAPI !== 'cli') {
    fwrite(STDERR, "must be run from CLI\n");
    exit(2);
}

$username = $argv[1] ?? null;
if (!$username) {
    fwrite(STDERR, "usage: whp-magic-login-create.php <username>\n");
    exit(2);
}

// We live at wp-content/.whp/whp-magic-login-create.php; wp-load.php is two
// directories up.
$wp_load = dirname(__DIR__, 2) . '/wp-load.php';
if (!is_file($wp_load)) {
    fwrite(STDERR, "wp-load.php not found at $wp_load\n");
    exit(3);
}
define('WP_USE_THEMES', false);
require $wp_load;

if (!function_exists('sodium_crypto_generichash')) {
    fwrite(STDERR, "libsodium required (PHP 7.2+)\n");
    exit(4);
}

$user = get_user_by('login', $username);
if (!$user || !$user->ID) {
    fwrite(STDERR, "user not found: $username\n");
    exit(5);
}

$endpoint     = bin2hex(random_bytes(4));   // 8 hex chars
$public_key   = bin2hex(random_bytes(8));   // 16 hex chars
$expires_at   = time() + 900;               // 15 minutes
$redirect_url = '';                         // mu-plugin defaults to admin_url()

// Mirror the mu-plugin's signature() and validate() exactly:
//   signature = join('|', [public_key, endpoint, host, user_id, expires_at, redirect_url])
//   key       = sodium_crypto_generichash(wp_salt('auth'))
//   private   = sodium_bin2base64(sodium_crypto_generichash($sig, $key), URLSAFE)
$host        = parse_url(home_url(), PHP_URL_HOST);
$signature   = implode('|', [$public_key, $endpoint, $host, $user->ID, $expires_at, $redirect_url]);
$hash_key    = sodium_crypto_generichash(wp_salt('auth'));
$private_bin = sodium_crypto_generichash($signature, $hash_key);
$private     = sodium_bin2base64($private_bin, SODIUM_BASE64_VARIANT_URLSAFE);

// Endpoint pointer in wp_options. The mu-plugin does
// json_decode(get_option('wp_cli_login')) and reads ->endpoint, so we store
// a JSON string (autoload off — the panel reads it once per click).
update_option('wp_cli_login', wp_json_encode([
    'endpoint' => $endpoint,
    'version'  => 'whp1',
    'created'  => gmdate('c'),
]), false);

// Per-token transient. Mirrors the mu-plugin's magicKey():
//   key_hash      = sodium_crypto_generichash(public_key, key)
//   transient_key = 'wp_cli_login/' . sodium_bin2base64(key_hash, URLSAFE)
$key_hash      = sodium_crypto_generichash($public_key, $hash_key);
$transient_key = 'wp_cli_login/' . sodium_bin2base64($key_hash, SODIUM_BASE64_VARIANT_URLSAFE);
set_transient($transient_key, wp_json_encode([
    'user'         => $user->ID,
    'private'      => $private,
    'expires_at'   => $expires_at,
    'redirect_url' => $redirect_url,
]), 900);

// URL shape: <home>/<endpoint>/<public_key>
echo rtrim(home_url(), '/') . "/$endpoint/$public_key\n";
exit(0);
