"""
Credential and proof verification.

Used by the game backend to verify that a player's credential is genuine
(signed by a trusted issuer) and that the player proving ownership is the
real credential holder (challenge-response with device-bound key).
"""

from __future__ import annotations

import base64
import json
import logging

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from cryptography.exceptions import InvalidSignature

from .exceptions import SignatureError

logger = logging.getLogger(__name__)


def verify_credential_signature(
    credential_body: dict,
    signature_b64: str,
    issuer_public_key: Ed25519PublicKey,
) -> bool:
    """
    Verify that a credential was signed by the trusted issuer.

    Args:
        credential_body: The credential dict (without signature).
        signature_b64: Base64-encoded Ed25519 signature.
        issuer_public_key: The issuer's public key.

    Returns:
        True if the signature is valid.

    Raises:
        SignatureError: If the signature is invalid.
    """
    canonical = json.dumps(credential_body, sort_keys=True).encode()
    signature = base64.b64decode(signature_b64)

    try:
        issuer_public_key.verify(signature, canonical)
        return True
    except InvalidSignature as exc:
        raise SignatureError("Credential signature is invalid") from exc


def verify_challenge_signature(
    challenge: str,
    signature_b64: str,
    user_public_key_pem: str,
) -> bool:
    """
    Verify that the challenge was signed by the credential owner.

    Args:
        challenge: The original challenge string sent to the player.
        signature_b64: Base64-encoded signature from the player.
        user_public_key_pem: PEM-encoded public key from the credential.

    Returns:
        True if the signature is valid.

    Raises:
        SignatureError: If the signature is invalid.
    """
    public_key = serialization.load_pem_public_key(user_public_key_pem.encode())
    signature = base64.b64decode(signature_b64)

    try:
        public_key.verify(signature, challenge.encode())
        return True
    except InvalidSignature as exc:
        raise SignatureError("Challenge signature is invalid — not the credential owner") from exc
