"""Ed25519 proof-of-ownership for client wallet binding (ADR-0017 §5, issue C6).

Wallet addresses are base58-encoded Solana ed25519 public keys, the same
format used by ``packages/node/meshnet_node/wallet.py``. Binding a wallet to
an API key requires a signature over a message that embeds the api_key, so a
captured (wallet, signature) pair cannot be replayed to bind a different key.

No Solana RPC dependency is needed for verification, so this stays on plain
``cryptography`` rather than pulling in ``solders`` on the tracker.
"""

from __future__ import annotations

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

_B58_ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"
_B58_INDEX = {char: index for index, char in enumerate(_B58_ALPHABET)}


def b58decode(value: str) -> bytes:
    """Decode a base58 string (Solana/Bitcoin alphabet) to bytes."""
    n = 0
    for char in value:
        digit = _B58_INDEX.get(char)
        if digit is None:
            raise ValueError(f"invalid base58 character: {char!r}")
        n = n * 58 + digit
    body = n.to_bytes((n.bit_length() + 7) // 8, "big") if n else b""
    leading_zeros = len(value) - len(value.lstrip("1"))
    return b"\x00" * leading_zeros + body


def binding_message(api_key: str, wallet: str) -> bytes:
    """Message a wallet owner must sign to bind ``wallet`` to ``api_key``."""
    return f"meshnet-wallet-bind:{api_key}:{wallet}".encode()


def verify_wallet_signature(wallet: str, message: bytes, signature_hex: str) -> bool:
    """True if ``signature_hex`` is a valid ed25519 signature by ``wallet`` over ``message``."""
    try:
        pubkey_bytes = b58decode(wallet)
        if len(pubkey_bytes) != 32:
            return False
        signature = bytes.fromhex(signature_hex)
        Ed25519PublicKey.from_public_bytes(pubkey_bytes).verify(signature, message)
        return True
    except (ValueError, InvalidSignature):
        return False
