# media_tokens.py
import base64
import hashlib
import hmac
import json
import time
from typing import Any, Dict, Optional


def _b64url_encode(b: bytes) -> str:
    return base64.urlsafe_b64encode(b).decode("ascii").rstrip("=")


def _b64url_decode(s: str) -> bytes:
    # restaurar padding
    pad = "=" * ((4 - (len(s) % 4)) % 4)
    return base64.urlsafe_b64decode((s + pad).encode("ascii"))


def make_media_token(*, filename: str, secret: str, ttl_seconds: int) -> str:
    """
    Token = <payload_b64>.<sig_b64>
    payload = {"f": filename, "exp": unix_ts}
    sig = HMAC-SHA256(secret, payload_b64)
    """
    if not filename or "/" in filename or "\\" in filename or ".." in filename:
        raise ValueError("invalid_filename")

    now = int(time.time())
    exp = now + max(1, int(ttl_seconds))

    payload = {"f": filename, "exp": exp}
    payload_json = json.dumps(payload, separators=(",", ":"), sort_keys=True).encode("utf-8")
    payload_b64 = _b64url_encode(payload_json)

    mac = hmac.new(secret.encode("utf-8"), payload_b64.encode("ascii"), hashlib.sha256).digest()
    sig_b64 = _b64url_encode(mac)

    return f"{payload_b64}.{sig_b64}"


def verify_media_token(token: str, secret: str) -> Optional[Dict[str, Any]]:
    """
    Devuelve payload dict si OK; None si inválido/caducado.
    """
    if not token or "." not in token:
        return None

    try:
        payload_b64, sig_b64 = token.split(".", 1)
    except ValueError:
        return None

    # recalcular firma
    mac = hmac.new(secret.encode("utf-8"), payload_b64.encode("ascii"), hashlib.sha256).digest()
    expected_sig_b64 = _b64url_encode(mac)

    # comparación constante
    if not hmac.compare_digest(expected_sig_b64, sig_b64):
        return None

    # decodificar payload
    try:
        payload_json = _b64url_decode(payload_b64)
        payload = json.loads(payload_json.decode("utf-8"))
    except Exception:
        return None

    # validar exp
    exp = int(payload.get("exp") or 0)
    if exp <= 0 or int(time.time()) > exp:
        return None

    # validar filename
    f = payload.get("f")
    if not f or "/" in f or "\\" in f or ".." in f:
        return None

    return payload
