<?php

declare(strict_types=1);

namespace PpPhp\Core\Licensing;

/**
 * The licence-server public key this copy of PPPHP trusts.
 *
 * Why this file exists: an activation code carries the server URL and its public
 * key, which alone would be trust-on-first-use — anyone could point an install at
 * their own "licence server" and mint themselves a lease. Stamping the vendor's
 * real key into the shipped source closes that door: a client refuses any
 * activation code whose key is not this one.
 *
 * The owner stamps it once (Licensing → Signing key → "Stamp into source") and it
 * then travels inside every bundle. Left empty during development, activation
 * falls back to trust-on-first-use so a local server can be used freely.
 *
 * PUBLIC_KEY is base64 of a 32-byte Ed25519 public key. It is not a secret.
 */
final class LicenseTrust
{
    public const PUBLIC_KEY = 'ehmy4rzaOj528EkZQBxHK+PNFAMdOubGpOVVj6X8Tr4=';

    /** Raw trusted key, or '' when this build is unstamped (development). */
    public static function key(): string
    {
        $k = trim(self::PUBLIC_KEY);
        if ($k === '') return '';
        // The key length is an Ed25519 constant from the PHP `sodium` extension.
        // On a host without sodium that constant is undefined and would fatal —
        // degrade to "unstamped" so callers handle it, never crash. (Installers
        // separately refuse to run without sodium and say so plainly.)
        if (!defined('SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES')) return '';
        $raw = base64_decode($k, true);
        return (is_string($raw) && strlen($raw) === SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES) ? $raw : '';
    }

    public static function isStamped(): bool
    {
        return self::key() !== '';
    }

    /**
     * Rewrite this file with a new trusted key. Owner-only, and deliberately a
     * source edit rather than a setting: a value in the database could be
     * changed by anyone who reaches the database, which is exactly the attack
     * pinning is meant to stop.
     */
    public static function stamp(string $publicKeyB64): bool
    {
        $raw = base64_decode(trim($publicKeyB64), true);
        if (!is_string($raw) || strlen($raw) !== SODIUM_CRYPTO_SIGN_PUBLICKEYBYTES) {
            return false;
        }
        $file = __FILE__;
        $src  = (string) @file_get_contents($file);
        if ($src === '') return false;

        $new = preg_replace(
            "/public const PUBLIC_KEY = '[^']*';/",
            "public const PUBLIC_KEY = '" . trim($publicKeyB64) . "';",
            $src,
            1,
            $count
        );
        if (!is_string($new) || $count !== 1) return false;

        return @file_put_contents($file, $new, LOCK_EX) !== false;
    }
}
