import base64
import hashlib
import json
from nacl.signing import SigningKey, VerifyKey
from nacl.encoding import HexEncoder


def generate_keypair() -> tuple[str, str]:
    """Generate a new Ed25519 keypair. Returns (private_key_hex, public_key_hex)."""
    signing_key = SigningKey.generate()
    private_key = signing_key.encode(encoder=HexEncoder).decode()
    public_key = signing_key.verify_key.encode(encoder=HexEncoder).decode()
    return private_key, public_key


def canonical_json(obj: dict) -> str:
    """Create canonical JSON with sorted keys."""
    return json.dumps(obj, sort_keys=True, separators=(',', ':'))


def sha256_hex(data: str) -> str:
    """SHA-256 hash of string, returned as hex."""
    return hashlib.sha256(data.encode()).hexdigest()


def sign_message(private_key_hex: str, message: str) -> str:
    """Sign a message with Ed25519, return signature as base64url (no padding).

    The message is UTF-8 encoded before signing, matching the TypeScript
    implementation which uses TextEncoder.encode(message).
    """
    signing_key = SigningKey(bytes.fromhex(private_key_hex))
    msg_bytes = message.encode('utf-8')
    signed = signing_key.sign(msg_bytes)
    return base64.urlsafe_b64encode(signed.signature).rstrip(b'=').decode()


def verify_message(public_key_hex: str, message: str, signature_b64url: str) -> bool:
    """Verify an Ed25519 signature (base64url) against a UTF-8 message."""
    try:
        verify_key = VerifyKey(bytes.fromhex(public_key_hex))
        msg_bytes = message.encode('utf-8')
        # Add padding back for base64url decode
        padded = signature_b64url + '=' * (-len(signature_b64url) % 4)
        sig_bytes = base64.urlsafe_b64decode(padded)
        verify_key.verify(msg_bytes, sig_bytes)
        return True
    except Exception:
        return False
