"""
Utility helpers for working with Ed25519 keys and fingerprints.
"""

from __future__ import annotations

import base64
import hashlib
import re
from typing import Tuple

from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.serialization import load_der_public_key
from cryptography.hazmat.primitives.asymmetric import ed25519


def generate_ed25519_keypair() -> Tuple[ed25519.Ed25519PrivateKey, bytes]:
    """
    Generate a new Ed25519 keypair.

    Returns the private key object and the public key encoded as SubjectPublicKeyInfo DER bytes.
    """

    private_key = ed25519.Ed25519PrivateKey.generate()
    public_key = private_key.public_key().public_bytes(
        encoding=serialization.Encoding.DER,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    )
    return private_key, public_key


def normalize_base64(data: str) -> str:
    """
    Collapse whitespace and normalise URL-safe encodings so we can reliably decode.
    """

    cleaned = re.sub(r"\\s+", "", data or "")
    return cleaned.replace("-", "+").replace("_", "/")


def spki_der_from_base64(spki_b64: str) -> bytes:
    return base64.b64decode(normalize_base64(spki_b64), validate=True)


def base64_from_spki_der(spki_der: bytes) -> str:
    return base64.b64encode(spki_der).decode("ascii")


def fingerprint_from_spki_der(spki_der: bytes) -> str:
    digest = hashlib.sha256(spki_der).hexdigest()
    return digest.lower()


def fingerprint_from_base64_spki(spki_b64: str) -> str:
    return fingerprint_from_spki_der(spki_der_from_base64(spki_b64))


def private_key_to_pem(private_key: ed25519.Ed25519PrivateKey) -> bytes:
    return private_key.private_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PrivateFormat.PKCS8,
        encryption_algorithm=serialization.NoEncryption(),
    )


def public_key_to_pem(public_spki_der: bytes) -> bytes:
    public_key = load_der_public_key(public_spki_der)
    return public_key.public_bytes(
        encoding=serialization.Encoding.PEM,
        format=serialization.PublicFormat.SubjectPublicKeyInfo,
    )
