import { d as scrubPII, i as sanitizeChannelInput, n as formatAlert, t as ChannelGuards } from "./index.mjs";
import { createHmac, timingSafeEqual } from "node:crypto";
import { createServer } from "node:http";

//#region src/channels/whatsapp-handlers.ts
const MAX_REQUEST_BODY_BYTES = 1048576;
function isRecord(value) {
	return value !== null && typeof value === "object" && !Array.isArray(value);
}
function isWhatsAppPayload(value) {
	if (!isRecord(value)) return false;
	return value["object"] === "whatsapp_business_account" && Array.isArray(value["entry"]);
}
function handleVerification(req, res, verifyToken, audit) {
	const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
	const mode = url.searchParams.get("hub.mode");
	const token = url.searchParams.get("hub.verify_token");
	const challenge = url.searchParams.get("hub.challenge");
	if (mode === "subscribe" && token === verifyToken && challenge) {
		audit.logAction("whatsapp:webhook_verified", {});
		res.writeHead(200, { "Content-Type": "text/plain" });
		res.end(challenge);
		return;
	}
	audit.logAction("whatsapp:verification_failed", { mode }, { success: false });
	res.writeHead(403).end();
}
function verifySignature(req, rawBody, appSecret) {
	const signatureHeader = req.headers["x-hub-signature-256"];
	if (typeof signatureHeader !== "string") return false;
	const expected = `sha256=${createHmac("sha256", appSecret).update(rawBody).digest("hex")}`;
	if (signatureHeader.length !== expected.length) return false;
	return timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));
}
function processWebhookPayload(payload, deps, guards) {
	const { audit, onInbound, phoneNumberId, pipeline } = deps;
	const entries = payload.entry ?? [];
	for (const entry of entries) for (const change of entry.changes) {
		const { value } = change;
		if (value.metadata.phone_number_id !== phoneNumberId) continue;
		const messages = value.messages ?? [];
		for (const msg of messages) {
			if (msg.type !== "text" || !msg.text?.body) continue;
			if (!guards.tryConsume()) {
				audit.logAction("whatsapp:rate_limited", { from: msg.from });
				continue;
			}
			let sanitized;
			try {
				sanitized = sanitizeChannelInput(msg.text.body);
			} catch (error) {
				audit.logAction("whatsapp:sanitize_error", {
					error: String(error),
					from: msg.from
				}, { success: false });
				continue;
			}
			ingestText(pipeline, audit, sanitized, "whatsapp:text");
			if (onInbound) onInbound({
				sourceNodeId: phoneNumberId,
				platform: "whatsapp",
				senderId: msg.from,
				senderIsOwner: false,
				groupId: null,
				content: sanitized,
				contentType: "text",
				timestamp: (/* @__PURE__ */ new Date(Number(msg.timestamp) * 1e3)).toISOString()
			});
			audit.logAction("whatsapp:message_received", {
				from: scrubPII(msg.from),
				messageId: msg.id
			});
		}
	}
}
async function ingestText(pipeline, audit, text, source) {
	try {
		await pipeline.ingestEvent(source, {
			content: text,
			timestamp: (/* @__PURE__ */ new Date()).toISOString()
		});
	} catch (error) {
		audit.logAction("whatsapp:ingest_error", {
			source,
			error: String(error)
		}, { success: false });
	}
}
function readBody(req) {
	return new Promise((resolve, reject) => {
		const chunks = [];
		let totalBytes = 0;
		req.on("data", (chunk) => {
			totalBytes += chunk.length;
			if (totalBytes > MAX_REQUEST_BODY_BYTES) {
				req.destroy();
				reject(/* @__PURE__ */ new Error("Request body too large"));
				return;
			}
			chunks.push(chunk);
		});
		req.on("end", () => {
			resolve(Buffer.concat(chunks).toString("utf-8"));
		});
		req.on("error", reject);
	});
}

//#endregion
//#region src/channels/whatsapp.ts
const GRAPH_API_BASE = "https://graph.facebook.com/v18.0/";
const FETCH_TIMEOUT_MS = 1e4;
var WhatsAppChannel = class {
	name = "whatsapp";
	guards = new ChannelGuards("whatsapp");
	server = null;
	constructor(deps) {
		this.deps = deps;
	}
	async start() {
		const { audit, webhookPort } = this.deps;
		audit.logAction("whatsapp:start", { port: webhookPort });
		this.server = createServer((req, res) => {
			this.handleRequest(req, res);
		});
		await new Promise((resolve, reject) => {
			const srv = this.server;
			if (!srv) {
				reject(/* @__PURE__ */ new Error("Server not initialized"));
				return;
			}
			srv.on("error", reject);
			srv.listen(webhookPort, "127.0.0.1", () => {
				srv.removeListener("error", reject);
				resolve();
			});
		});
	}
	async stop() {
		this.deps.audit.logAction("whatsapp:stop", {});
		await new Promise((resolve, reject) => {
			if (!this.server) {
				resolve();
				return;
			}
			this.server.close((err) => {
				if (err) {
					reject(err);
					return;
				}
				resolve();
			});
			this.server = null;
		});
	}
	async sendAlert(alert) {
		if (this.guards.isSilenced()) return;
		const text = formatAlert(alert);
		await this.sendTextMessage(this.deps.phoneNumberId, text);
	}
	async sendMessage(content, groupId) {
		const recipient = groupId ?? this.deps.phoneNumberId;
		await this.sendTextMessage(recipient, content);
	}
	async sendToGroup(groupId, content) {
		await this.sendTextMessage(groupId, content);
	}
	async sendTextMessage(recipientId, text) {
		const { accessToken, phoneNumberId, audit } = this.deps;
		const url = `${GRAPH_API_BASE}${phoneNumberId}/messages`;
		const body = JSON.stringify({
			messaging_product: "whatsapp",
			to: recipientId,
			type: "text",
			text: { body: text }
		});
		try {
			const response = await fetch(url, {
				method: "POST",
				headers: {
					Authorization: `Bearer ${accessToken}`,
					"Content-Type": "application/json"
				},
				body,
				signal: AbortSignal.timeout(FETCH_TIMEOUT_MS)
			});
			if (!response.ok) {
				const errorBody = await response.text();
				audit.logAction("whatsapp:send_error", {
					status: response.status,
					errorBody,
					recipientId
				}, { success: false });
				return;
			}
			audit.logAction("whatsapp:message_sent", { recipientId });
		} catch (error) {
			audit.logAction("whatsapp:send_error", {
				error: String(error),
				recipientId
			}, { success: false });
		}
	}
	async handleRequest(req, res) {
		const { audit } = this.deps;
		if (req.method === "GET") {
			handleVerification(req, res, this.deps.verifyToken, audit);
			return;
		}
		if (req.method !== "POST") {
			res.writeHead(405).end();
			return;
		}
		try {
			const rawBody = await readBody(req);
			if (!verifySignature(req, rawBody, this.deps.appSecret)) {
				audit.logAction("whatsapp:invalid_signature", {}, { success: false });
				res.writeHead(401).end();
				return;
			}
			const payload = JSON.parse(rawBody);
			if (!isWhatsAppPayload(payload)) {
				res.writeHead(400).end();
				return;
			}
			processWebhookPayload(payload, this.deps, this.guards);
			res.writeHead(200).end();
		} catch (error) {
			audit.logAction("whatsapp:webhook_error", { error: String(error) }, { success: false });
			res.writeHead(400).end();
		}
	}
};

//#endregion
export { WhatsAppChannel };
//# sourceMappingURL=whatsapp-5-v6JPEY.mjs.map