import { logger } from "../util/logger.js";
import { decryptAesEcb } from "./aes-ecb.js";
import { buildCdnDownloadUrl } from "./cdn-url.js";
//#region extensions/weixin/src/cdn/pic-decrypt.ts
/**
* Download raw bytes from the CDN (no decryption).
*/
async function fetchCdnBytes(url, label) {
	let res;
	try {
		res = await fetch(url);
	} catch (err) {
		const cause = err.cause ?? err.code ?? "(no cause)";
		logger.error(`${label}: fetch network error url=${url} err=${String(err)} cause=${String(cause)}`);
		throw err;
	}
	logger.debug(`${label}: response status=${res.status} ok=${res.ok}`);
	if (!res.ok) {
		const body = await res.text().catch(() => "(unreadable)");
		const msg = `${label}: CDN download ${res.status} ${res.statusText} body=${body}`;
		logger.error(msg);
		throw new Error(msg);
	}
	return Buffer.from(await res.arrayBuffer());
}
/**
* Parse CDNMedia.aes_key into a raw 16-byte AES key.
*
* Two encodings are seen in the wild:
*   - base64(raw 16 bytes)          → images (aes_key from media field)
*   - base64(hex string of 16 bytes) → file / voice / video
*
* In the second case, base64-decoding yields 32 ASCII hex chars which must
* then be parsed as hex to recover the actual 16-byte key.
*/
function parseAesKey(aesKeyBase64, label) {
	const decoded = Buffer.from(aesKeyBase64, "base64");
	if (decoded.length === 16) return decoded;
	if (decoded.length === 32 && /^[0-9a-fA-F]{32}$/.test(decoded.toString("ascii"))) return Buffer.from(decoded.toString("ascii"), "hex");
	const msg = `${label}: aes_key must decode to 16 raw bytes or 32-char hex string, got ${decoded.length} bytes (base64="${aesKeyBase64}")`;
	logger.error(msg);
	throw new Error(msg);
}
/**
* Download and AES-128-ECB decrypt a CDN media file. Returns plaintext Buffer.
* aesKeyBase64: CDNMedia.aes_key JSON field (see parseAesKey for supported formats).
*/
async function downloadAndDecryptBuffer(encryptedQueryParam, aesKeyBase64, cdnBaseUrl, label, fullUrl) {
	const key = parseAesKey(aesKeyBase64, label);
	let url;
	if (fullUrl) url = fullUrl;
	else url = buildCdnDownloadUrl(encryptedQueryParam, cdnBaseUrl);
	logger.debug(`${label}: fetching url=${url}`);
	const encrypted = await fetchCdnBytes(url, label);
	logger.debug(`${label}: downloaded ${encrypted.byteLength} bytes, decrypting`);
	const decrypted = decryptAesEcb(encrypted, key);
	logger.debug(`${label}: decrypted ${decrypted.length} bytes`);
	return decrypted;
}
/**
* Download plain (unencrypted) bytes from the CDN. Returns the raw Buffer.
*/
async function downloadPlainCdnBuffer(encryptedQueryParam, cdnBaseUrl, label, fullUrl) {
	let url;
	if (fullUrl) url = fullUrl;
	else url = buildCdnDownloadUrl(encryptedQueryParam, cdnBaseUrl);
	logger.debug(`${label}: fetching url=${url}`);
	return fetchCdnBytes(url, label);
}
//#endregion
export { downloadAndDecryptBuffer, downloadPlainCdnBuffer };

//# sourceMappingURL=pic-decrypt.js.map