"""Core signature verifiers (§2.3): Ed25519 + ES256, real verification via `cryptography`.

Each is an `IdentityVerifier` adapter behind the one interface; the router/ingress depends only on the
interface. A verifier returns `VerifiedIdentity` (assurance = SIGNED) on success, or `None` fail-closed —
the caller never reads a failed verification as a higher assurance level (A3). `key_ref` is the raw public
key as hex: Ed25519 = 32-byte raw key; ES256 = the SEC1 uncompressed point (0x04‖X‖Y, 65 bytes).
"""

from __future__ import annotations

from typing import Optional

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.asymmetric import ec
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey
from cryptography.hazmat.primitives.asymmetric.utils import encode_dss_signature

from cl.interfaces.identity import AssuranceLevel, IdentityVerifier, VerifiedIdentity


class Ed25519Verifier(IdentityVerifier):
    def method(self) -> str:
        return "ed25519"

    def verify(self, signing_input: bytes, signature: bytes, key_ref: str) -> Optional[VerifiedIdentity]:
        try:
            pub = Ed25519PublicKey.from_public_bytes(bytes.fromhex(key_ref))
            pub.verify(signature, signing_input)  # raises InvalidSignature on mismatch
        except (InvalidSignature, ValueError):
            return None
        return VerifiedIdentity(
            subject_ref=f"key:ed25519:{key_ref}", method="ed25519", assurance=AssuranceLevel.SIGNED
        )


class Es256Verifier(IdentityVerifier):
    """ECDSA P-256 / SHA-256. The signature is JOSE form `r‖s` (64 bytes), converted to DER for verification —
    the interoperable form used by JWS/COSE ES256."""

    def method(self) -> str:
        return "es256"

    def verify(self, signing_input: bytes, signature: bytes, key_ref: str) -> Optional[VerifiedIdentity]:
        try:
            pub = ec.EllipticCurvePublicKey.from_encoded_point(ec.SECP256R1(), bytes.fromhex(key_ref))
            if len(signature) != 64:
                return None  # ES256 JOSE signatures are exactly 64 bytes (r‖s)
            r = int.from_bytes(signature[:32], "big")
            s = int.from_bytes(signature[32:], "big")
            pub.verify(encode_dss_signature(r, s), signing_input, ec.ECDSA(hashes.SHA256()))
        except (InvalidSignature, ValueError):
            return None
        return VerifiedIdentity(
            subject_ref=f"key:es256:{key_ref}", method="es256", assurance=AssuranceLevel.SIGNED
        )
