<?php

declare(strict_types=1);

namespace FastOg;

/**
 * FastOG — official signer SDK (PHP).
 *
 * Generates HMAC-SHA256 content-signed OG image URLs for the FastOG API.
 * No framework dependency. Runs on the CLIENT'S SERVER only — never expose
 * the hmac secret to a browser.
 *
 * Contract (mirrors the FastOG server, App\Support\HmacSignature):
 *   canonical = every query param except `s` (including `key`), keys sorted,
 *               array values sorted, each pair `rawurlencode(key)=rawurlencode(value)`
 *               joined with "&"
 *   message   = "GET/api/v1/og" . "\n" . canonical
 *   signature = hex(HMAC-SHA256(message, secret))
 */
final class FastOg
{
    public const DEFAULT_BASE_URL = 'https://fastog.com/api/v1/og';

    /**
     * Canonical query string the server verifies.
     *
     * @param  array<string, mixed>  $params
     */
    public static function canonicalize(array $params, string $apiKey): string
    {
        $pairs = [];
        foreach (array_merge($params, ['key' => $apiKey]) as $k => $v) {
            $values = is_array($v) ? $v : [$v];
            sort($values, SORT_STRING);
            foreach ($values as $vv) {
                $pairs[] = rawurlencode((string) $k) . '=' . rawurlencode((string) $vv);
            }
        }
        sort($pairs, SORT_STRING);

        return implode('&', $pairs);
    }

    /**
     * HMAC-SHA256 hex signature of `GET/api/v1/og\n<canonical>`.
     *
     * @param  array<string, mixed>  $params
     */
    public static function sign(array $params, string $apiKey, string $hmacSecret): string
    {
        return hash_hmac('sha256', 'GET/api/v1/og' . "\n" . self::canonicalize($params, $apiKey), $hmacSecret);
    }

    /**
     * Build a ready-to-use signed OG image URL.
     *
     * Array params are encoded as `key[0]=`/`key[1]=` (PHP bracket syntax) so
     * the server's query parser reconstructs them as arrays.
     *
     * @param  array<string, mixed>  $params
     */
    public static function signedUrl(
        array $params,
        string $apiKey,
        string $hmacSecret,
        string $baseUrl = self::DEFAULT_BASE_URL,
    ): string {
        $all = array_merge($params, [
            'key' => $apiKey,
            's' => self::sign($params, $apiKey, $hmacSecret),
        ]);

        return $baseUrl . '?' . http_build_query($all, '', '&', PHP_QUERY_RFC3986);
    }
}
