package wang.yaojia.webterm.api.enroll

/**
 * B4 · The signing key abstraction the PKCS#10 CSR encoder ([CertificateSigningRequest]) drives —
 * the Android analogue of iOS `P256HardwareKey`.
 *
 * In production this is backed by a NON-EXPORTABLE P-256 key living inside AndroidKeyStore
 * (StrongBox → TEE), so `sign` runs inside secure hardware and the private key never leaves it
 * (`:client-tls-android` `HardwareBackedKey`). In JVM unit tests it is backed by a software P-256
 * key via the SAME `Signature("SHA256withECDSA")` path, so the CSR-encoding bytes are exercised
 * identically without an emulator.
 */
public interface CsrSigner {
    /**
     * The public key in ANSI X9.63 uncompressed form: `0x04 || X(32) || Y(32)` (65 bytes for
     * P-256). This is exactly what wraps into the CSR's `SubjectPublicKeyInfo` BIT STRING.
     */
    public fun publicKeyX963(): ByteArray

    /**
     * ECDSA-sign `message` over SHA-256, returning the X9.62 DER signature
     * (`SEQUENCE { r INTEGER, s INTEGER }`) — exactly the shape a PKCS#10 `signature` BIT STRING
     * and the server's `verifyCsrPoPEc` expect. The digest is computed by the algorithm
     * (`SHA256withECDSA`), so callers pass the raw message (the DER of `CertificationRequestInfo`),
     * NOT a pre-hash.
     */
    public fun sign(message: ByteArray): ByteArray
}

/** Structural failures building a CSR — the client refuses to emit a malformed request. */
public sealed class CsrException(message: String) : Exception(message) {
    /** The signer's public key was not the expected 65-byte X9.63 uncompressed P-256 point. */
    public data object InvalidPublicKey : CsrException("CSR public key is not a 65-byte X9.63 P-256 point")

    /** The subject CN was empty (not encodable / rejected by the server). */
    public data object InvalidSubject : CsrException("CSR subject common name must not be empty")
}
