

import { CredoError } from "../../../error/CredoError.mjs";
import "../../../error/index.mjs";
import { KeyManagementError } from "../error/KeyManagementError.mjs";
import { TypedArrayEncoder } from "../../../utils/TypedArrayEncoder.mjs";
import { MultiBaseEncoder } from "../../../utils/MultiBaseEncoder.mjs";
import { VarintEncoder } from "../../../utils/VarintEncoder.mjs";
import "../../../utils/index.mjs";
import { getJwkHumanDescription } from "./humanDescription.mjs";
import { assymetricPublicJwkMatches } from "./equals.mjs";
import { zParseWithErrorHandling } from "../../../utils/zod.mjs";
import { assertJwkAsymmetric, publicJwkFromPrivateJwk, zKmsJwkPublic } from "./knownJwk.mjs";
import { P256PublicJwk } from "./kty/ec/P256PublicJwk.mjs";
import { P384PublicJwk } from "./kty/ec/P384PublicJwk.mjs";
import { P521PublicJwk } from "./kty/ec/P521PublicJwk.mjs";
import { Secp256k1PublicJwk } from "./kty/ec/Secp256k1PublicJwk.mjs";
import { X25519PublicJwk } from "./kty/okp/X25519PublicJwk.mjs";
import { Ed25519PublicJwk } from "./kty/okp/Ed25519PublicJwk.mjs";
import { RsaPublicJwk } from "./kty/rsa/RsaPublicJwk.mjs";
import "./kty/index.mjs";
import { legacyKeyIdFromPublicJwk } from "../legacy.mjs";
import { calculateJwkThumbprint } from "./jwkThumbprint.mjs";

//#region src/modules/kms/jwk/PublicJwk.ts
const SupportedPublicJwks = [
	Ed25519PublicJwk,
	P256PublicJwk,
	P384PublicJwk,
	P521PublicJwk,
	RsaPublicJwk,
	Secp256k1PublicJwk,
	X25519PublicJwk
];
var PublicJwk = class PublicJwk {
	constructor(jwk) {
		this.jwk = jwk;
	}
	static fromUnknown(jwkJson) {
		const publicJwk = publicJwkFromPrivateJwk(zParseWithErrorHandling(zKmsJwkPublic, jwkJson, "jwk is not a valid jwk"));
		assertJwkAsymmetric(publicJwk);
		let jwkInstance;
		if (publicJwk.kty === "RSA") jwkInstance = new RsaPublicJwk(publicJwk);
		else if (publicJwk.kty === "EC") if (publicJwk.crv === "P-256") jwkInstance = new P256PublicJwk({
			...publicJwk,
			crv: publicJwk.crv
		});
		else if (publicJwk.crv === "P-384") jwkInstance = new P384PublicJwk({
			...publicJwk,
			crv: publicJwk.crv
		});
		else if (publicJwk.crv === "P-521") jwkInstance = new P521PublicJwk({
			...publicJwk,
			crv: publicJwk.crv
		});
		else if (publicJwk.crv === "secp256k1") jwkInstance = new Secp256k1PublicJwk({
			...publicJwk,
			crv: publicJwk.crv
		});
		else throw new KeyManagementError(`Unsupported kty '${publicJwk.kty}' with crv '${publicJwk.crv}' for creating jwk instance`);
		else if (publicJwk.crv === "Ed25519") jwkInstance = new Ed25519PublicJwk({
			...publicJwk,
			crv: publicJwk.crv
		});
		else if (publicJwk.crv === "X25519") jwkInstance = new X25519PublicJwk({
			...publicJwk,
			crv: publicJwk.crv
		});
		else throw new KeyManagementError(`Unsupported kty '${publicJwk.kty}' for creating jwk instance`);
		return new PublicJwk(jwkInstance);
	}
	static fromPublicJwk(jwk) {
		return PublicJwk.fromUnknown(jwk);
	}
	toJson({ includeKid = true } = {}) {
		if (includeKid) return this.jwk.jwk;
		const { kid, ...jwk } = this.jwk.jwk;
		return jwk;
	}
	get supportedSignatureAlgorithms() {
		return this.jwk.supportedSignatureAlgorithms ?? [];
	}
	get supportdEncryptionKeyAgreementAlgorithms() {
		return this.jwk.supportdEncryptionKeyAgreementAlgorithms ?? [];
	}
	/**
	* key type as defined in [JWA Specification](https://tools.ietf.org/html/rfc7518#section-6.1)
	*/
	get kty() {
		return this.jwk.jwk.kty;
	}
	/**
	* Get the key id for a public jwk. If the public jwk does not have
	* a key id, an error will be thrown
	*/
	get keyId() {
		if (this.jwk.jwk.kid) return this.jwk.jwk.kid;
		throw new KeyManagementError("Unable to determine keyId for jwk");
	}
	get hasKeyId() {
		return this.jwk.jwk.kid !== void 0;
	}
	set keyId(keyId) {
		this.jwk.jwk.kid = keyId;
	}
	get legacyKeyId() {
		return legacyKeyIdFromPublicJwk(this);
	}
	get publicKey() {
		return this.jwk.publicKey;
	}
	/**
	* Return the compressed public key. If the key type does not support compressed public keys, it will return null
	*/
	get compressedPublicKey() {
		return this.jwk.compressedPublicKey;
	}
	get JwkClass() {
		return this.jwk.constructor;
	}
	/**
	* SHA-256 jwk thumbprint
	*/
	getJwkThumbprint(hashAlgorithm = "sha-256") {
		return calculateJwkThumbprint({
			jwk: this.jwk.jwk,
			hashAlgorithm
		});
	}
	/**
	* Get the signature algorithm to use with this jwk. If the jwk has an `alg` field defined
	* it will use that alg, and otherwise fall back to the first supported signature algorithm.
	*
	* If no algorithm is supported it will throw an error
	*/
	get signatureAlgorithm() {
		if (this.jwk.jwk.alg) {
			if (!this.supportedSignatureAlgorithms.includes(this.jwk.jwk.alg)) throw new KeyManagementError(`${getJwkHumanDescription(this.jwk.jwk)} defines alg '${this.jwk.jwk.alg}' but this alg is not supported.`);
			return this.jwk.jwk.alg;
		}
		const alg = this.supportedSignatureAlgorithms[0];
		if (!alg) throw new KeyManagementError(`${getJwkHumanDescription(this.jwk.jwk)} has no supported signature algorithms`);
		return alg;
	}
	static fromPublicKey(publicKey) {
		let jwkInstance;
		if (publicKey.kty === "RSA") jwkInstance = RsaPublicJwk.fromPublicKey(publicKey);
		else if (publicKey.kty === "EC") if (publicKey.crv === "P-256") jwkInstance = P256PublicJwk.fromPublicKey(publicKey.publicKey);
		else if (publicKey.crv === "P-384") jwkInstance = P384PublicJwk.fromPublicKey(publicKey.publicKey);
		else if (publicKey.crv === "P-521") jwkInstance = P521PublicJwk.fromPublicKey(publicKey.publicKey);
		else if (publicKey.crv === "secp256k1") jwkInstance = Secp256k1PublicJwk.fromPublicKey(publicKey.publicKey);
		else throw new KeyManagementError(`Unsupported kty '${publicKey.kty}' with crv '${publicKey.crv}' for creating jwk instance based on public key bytes`);
		else if (publicKey.crv === "X25519") jwkInstance = X25519PublicJwk.fromPublicKey(publicKey.publicKey);
		else if (publicKey.crv === "Ed25519") jwkInstance = Ed25519PublicJwk.fromPublicKey(publicKey.publicKey);
		else throw new KeyManagementError(`Unsupported kty '${publicKey.kty}' for creating jwk instance based on public key bytes`);
		return new PublicJwk(jwkInstance);
	}
	/**
	* Returns the jwk encoded a Base58 multibase encoded multicodec key
	*/
	get fingerprint() {
		const prefixBytes = VarintEncoder.encode(this.jwk.multicodecPrefix);
		const prefixedPublicKey = new Uint8Array([...prefixBytes, ...this.jwk.multicodec]);
		return `z${TypedArrayEncoder.toBase58(prefixedPublicKey)}`;
	}
	/**
	* Create a jwk instance based on a Base58 multibase encoded multicodec key
	*/
	static fromFingerprint(fingerprint) {
		const { data } = MultiBaseEncoder.decode(fingerprint);
		const [code, byteLength] = VarintEncoder.decode(data);
		const publicKey = data.slice(byteLength);
		const PublicJwkClass = SupportedPublicJwks.find((JwkClass) => JwkClass.multicodecPrefix === code);
		if (!PublicJwkClass) throw new KeyManagementError(`Unsupported multicodec public key with prefix '${code}'`);
		return new PublicJwk(PublicJwkClass.fromMulticodec(publicKey));
	}
	/**
	* Check whether this PublicJwk instance is of a specific type
	*/
	is(jwkType1, jwkType2, jwkType3) {
		return [
			jwkType1,
			jwkType2,
			jwkType3
		].filter(Boolean).some((type) => this.jwk.constructor === type);
	}
	/**
	* Convert the PublicJwk to another type.
	*
	* NOTE: only supportedf or Ed25519 to X25519 at the moment
	*/
	convertTo(type) {
		if (!this.is(Ed25519PublicJwk) || type !== X25519PublicJwk) throw new KeyManagementError("Unsupported key conversion. Only Ed25519 to X25519 is supported.");
		return PublicJwk.fromPublicJwk(this.jwk.toX25519PublicJwk());
	}
	/**
	* Check whether this jwk instance is the same as another jwk instance.
	* It does this by comparing the key types and public keys, not other fields
	* of the JWK such as keyId, use, etc..
	*/
	equals(other) {
		return assymetricPublicJwkMatches(this.toJson(), other.toJson());
	}
	/**
	* Get human description of a jwk type. This does
	* not include the (public) key material
	*/
	get jwkTypehumanDescription() {
		return getJwkHumanDescription(this.toJson());
	}
	static supportedPublicJwkClassForSignatureAlgorithm(alg) {
		const supportedPublicJwkClass = SupportedPublicJwks.find((JwkClass) => JwkClass.supportedSignatureAlgorithms.includes(alg));
		if (!supportedPublicJwkClass) throw new CredoError(`Could not determine supported public jwk class for alg '${alg}'`);
		return supportedPublicJwkClass;
	}
};

//#endregion
export { PublicJwk };
//# sourceMappingURL=PublicJwk.mjs.map