import { AuthInvalidated, Unauthorized } from "../../../zero-protocol/src/error-kind-enum.js";
import { ZeroCache } from "../../../zero-protocol/src/error-origin-enum.js";
import "../../../zero-protocol/src/error-reason-enum.js";
import { ProtocolError, isProtocolError } from "../../../zero-protocol/src/error.js";
//#region ../zero-cache/src/auth/auth.ts
function isProvidedAuth(wireAuth) {
	return wireAuth !== void 0 && wireAuth !== "";
}
function authEquals(a, b) {
	if (a === b) return true;
	if (!a || !b) return false;
	return a.type === b.type && a.raw === b.raw;
}
/**
* Resolves one auth snapshot transition without binding it to a client group.
*/
async function resolveAuth(lc, previousAuth, userID, wireAuth, validateLegacyJWT) {
	try {
		const hasProvidedAuth = isProvidedAuth(wireAuth);
		if (previousAuth) lc.debug?.(`Attempting to update auth from previous value`);
		else lc.debug?.(`Attempting to initialize auth`);
		if (!hasProvidedAuth && previousAuth) throw new ProtocolError({
			kind: Unauthorized,
			message: "No token provided. An unauthenticated client cannot connect to an authenticated client group.",
			origin: ZeroCache
		});
		if (!hasProvidedAuth) {
			lc.debug?.(`Cleared auth`);
			return;
		}
		if (userID === void 0) throw new ProtocolError({
			kind: Unauthorized,
			message: "Authenticated connections require a userID.",
			origin: ZeroCache
		});
		if (validateLegacyJWT !== void 0) {
			const nextAuth = pickToken(lc, previousAuth, await validateLegacyJWT(wireAuth, { userID }));
			lc.debug?.(`Updated auth with JWT`);
			return nextAuth;
		}
		if (previousAuth?.type === "jwt") throw new ProtocolError({
			kind: Unauthorized,
			message: "Token type cannot change from JWT to opaque. Connections are pinned to a single token type.",
			origin: ZeroCache
		});
		if (previousAuth?.type === "opaque" && previousAuth.raw === wireAuth) {
			lc.debug?.(`Opaque auth unchanged, reusing previous snapshot`);
			return previousAuth;
		}
		lc.debug?.(`Updated auth with opaque token`);
		return {
			type: "opaque",
			raw: wireAuth
		};
	} catch (e) {
		if (isProtocolError(e)) throw e;
		throw new ProtocolError({
			kind: AuthInvalidated,
			message: `Failed to decode auth token: ${String(e)}`,
			origin: ZeroCache
		});
	}
}
/** @deprecated used only in old JWT validation/rotation auth */
function pickToken(lc, previousToken, newToken) {
	if (newToken === null) return;
	if (previousToken?.type && newToken?.type && previousToken?.type !== newToken?.type) throw new ProtocolError({
		kind: Unauthorized,
		message: "Token type cannot change. Client groups are pinned to a single token type.",
		origin: ZeroCache
	});
	if (previousToken === void 0) {
		lc.debug?.(`No previous token, using new token`);
		return newToken;
	}
	if (newToken?.type === "opaque") return newToken;
	if (previousToken.type === "opaque") throw new ProtocolError({
		kind: Unauthorized,
		message: "Token type cannot change from opaque to JWT. Client groups are pinned to a single token type.",
		origin: ZeroCache
	});
	if (newToken) {
		if (previousToken.decoded.sub !== newToken.decoded.sub) throw new ProtocolError({
			kind: Unauthorized,
			message: "The user id in the new token does not match the previous token. Client groups are pinned to a single user.",
			origin: ZeroCache
		});
		if (previousToken.decoded.iat === void 0) {
			lc.debug?.(`No issued at time for the existing token, using new token`);
			return newToken;
		}
		if (newToken.decoded.iat === void 0) throw new ProtocolError({
			kind: Unauthorized,
			message: "The new token does not have an issued at time but the prior token does. Tokens for a client group must either all have issued at times or all not have issued at times",
			origin: ZeroCache
		});
		if (previousToken.decoded.iat < newToken.decoded.iat) {
			lc.debug?.(`New token is newer, using it`);
			return newToken;
		}
		lc.debug?.(`New token is older or the same, using existing token`);
		return previousToken;
	}
	throw new ProtocolError({
		kind: Unauthorized,
		message: "No token provided. An unauthenticated client cannot connect to an authenticated client group.",
		origin: ZeroCache
	});
}
function isAuthErrorBody(ex) {
	if (typeof ex !== "object" || ex === null) return false;
	if ("error" in ex) return ex.error === "http" && "status" in ex && (ex.status === 401 || ex.status === 403);
	if (!("kind" in ex)) return false;
	if (ex.kind === "AuthInvalidated" || ex.kind === "Unauthorized") return true;
	return (ex.kind === "PushFailed" || ex.kind === "TransformFailed") && "reason" in ex && ex.reason === "http" && "status" in ex && (ex.status === 401 || ex.status === 403);
}
//#endregion
export { authEquals, isAuthErrorBody, resolveAuth };

//# sourceMappingURL=auth.js.map