"""FastOG — official signer SDK (Python).

Generates HMAC-SHA256 content-signed OG image URLs for the FastOG API.
Zero dependencies (stdlib only). Runs on the CLIENT'S SERVER only — never
expose the hmac secret to a browser.

Contract (matches the FastOG server, app/Support/HmacSignature):
  canonical = every query param except `s` (including `key`), keys sorted,
              array values sorted, each pair `enc(key)=enc(value)` RFC-3986
              encoded (unreserved-only), joined with "&"
  message   = "GET/api/v1/og" + "\n" + canonical
  signature = hex(HMAC-SHA256(message, secret))
"""

import hashlib
import hmac
from urllib.parse import quote

DEFAULT_BASE_URL = "https://fastog.com/api/v1/og"


# RFC-3986 percent-encode: keep only unreserved A-Za-z0-9-._~ (space -> %20, not +).
def _enc(value):
    return quote(str(value), safe="-._~")


def canonicalize(params, api_key):
    """Canonical query string the server verifies."""
    all_params = {**params, "key": api_key}
    pairs = []
    for k, v in all_params.items():
        values = sorted(v) if isinstance(v, list) else [v]
        for vv in values:
            pairs.append(f"{_enc(k)}={_enc(vv)}")
    return "&".join(sorted(pairs))


def sign(params, api_key, hmac_secret):
    """HMAC-SHA256 hex signature of `GET/api/v1/og\\n<canonical>`."""
    message = f"GET/api/v1/og\n{canonicalize(params, api_key)}"
    return hmac.new(hmac_secret.encode(), message.encode(), hashlib.sha256).hexdigest()


def signed_url(params, api_key, hmac_secret, base_url=DEFAULT_BASE_URL):
    """Build a ready-to-use signed OG image URL.

    Array params are emitted as `key[0]=`/`key[1]=` bracket syntax so the
    FastOG backend (PHP) decodes them as arrays (`key=a&key=b` would decode
    to a scalar and fail the signature check).
    """
    all_params = {**params, "key": api_key,
                  "s": sign(params, api_key, hmac_secret)}
    pairs = []
    for k, v in all_params.items():
        if isinstance(v, list):
            for i, vv in enumerate(v):
                pairs.append(f"{_enc(f'{k}[{i}]')}={_enc(vv)}")
        else:
            pairs.append(f"{_enc(k)}={_enc(v)}")
    return f"{base_url}?{'&'.join(pairs)}"
