"""Ed25519 signing and verification for drift attestations.

Key and signature format: "ed25519:<hex>"
Matches the parent kredo package convention.
"""

from __future__ import annotations

from nacl.signing import SigningKey, VerifyKey
from nacl.exceptions import BadSignatureError

from kredo_drift.canonical import canonical_json
from kredo_drift.models import DriftAttestation


def generate_keypair() -> tuple[SigningKey, str]:
    """Generate a new Ed25519 keypair.

    Returns:
        (signing_key, pubkey_string) where pubkey_string is "ed25519:<hex>".
    """
    sk = SigningKey.generate()
    pubkey_hex = sk.verify_key.encode().hex()
    return sk, f"ed25519:{pubkey_hex}"


def sign_attestation(
    attestation: DriftAttestation,
    signing_key: SigningKey,
) -> DriftAttestation:
    """Sign an attestation with an Ed25519 key.

    Args:
        attestation: The unsigned attestation.
        signing_key: The Ed25519 signing key.

    Returns:
        A new DriftAttestation with the signature field populated.
    """
    payload = canonical_json(attestation.signing_payload())
    signed = signing_key.sign(payload)
    sig_hex = signed.signature.hex()

    return attestation.model_copy(
        update={"signature": f"ed25519:{sig_hex}"},
    )


def verify_attestation(attestation: DriftAttestation) -> bool:
    """Verify an attestation's Ed25519 signature.

    Args:
        attestation: The signed attestation.

    Returns:
        True if the signature is valid, False otherwise.
    """
    if not attestation.signature or not attestation.signature.startswith("ed25519:"):
        return False

    pubkey_str = attestation.subject.get("pubkey", "")
    if not pubkey_str.startswith("ed25519:"):
        return False

    try:
        sig_bytes = bytes.fromhex(attestation.signature.removeprefix("ed25519:"))
        pubkey_bytes = bytes.fromhex(pubkey_str.removeprefix("ed25519:"))
        verify_key = VerifyKey(pubkey_bytes)

        payload = canonical_json(attestation.signing_payload())
        verify_key.verify(payload, sig_bytes)
        return True
    except (BadSignatureError, ValueError, Exception):
        return False
