import { C as CommentNotFoundError, D as isCommentError, S as CommentModerationError, a as insertComment, h as normalizeCommentInput, i as getById, t as assertSanitize, u as setStatus, w as CommentSanitizationError, y as assertCanModerate } from "./store-GfOfxPns.js";
//#region src/moderation.ts
/** Default classify timeout — fail-safe lands pending on hang (spec §2). */
const CLASSIFY_TIMEOUT_MS = 1e4;
const MODERATABLE_STATUSES = /* @__PURE__ */ new Set([
	"published",
	"pending",
	"spam"
]);
/**
* Trust-boundary guard for an injected moderator's verdict. The CommentModerator is an external
* authority (an ai service, a custom classifier) — its return value is untrusted. A resolved-but-
* out-of-contract status (undefined/null/'trashed'/'approved'/any string) is NOT caught by the
* throw/timeout fail-safe and would otherwise be written verbatim to the status column (no DB CHECK).
*/
function isModeratableStatus(s) {
	return typeof s === "string" && MODERATABLE_STATUSES.has(s);
}
function classifyWithTimeout(moderator, input) {
	return new Promise((resolve, reject) => {
		const timer = setTimeout(() => reject(/* @__PURE__ */ new Error("classify_timeout")), CLASSIFY_TIMEOUT_MS);
		moderator.classify(input).then((result) => {
			clearTimeout(timer);
			resolve(result);
		}).catch((err) => {
			clearTimeout(timer);
			reject(err);
		});
	});
}
async function resolveModeratedStatus(moderator, input, target) {
	try {
		const verdict = await classifyWithTimeout(moderator, input);
		if (!isModeratableStatus(verdict?.status)) throw new CommentModerationError(`invalid verdict status: ${JSON.stringify(verdict?.status)}`);
		return verdict.status;
	} catch (reason) {
		console.warn({
			event: "comment_moderation_failed",
			reason: reason instanceof Error ? reason.message : String(reason),
			targetType: target.type,
			targetId: target.id
		});
		return "pending";
	}
}
/**
* postModerated — classify then insert with moderator verdict (system authority).
* Fail-safe: throw/timeout → pending, NEVER published.
*/
async function postModerated(db, input, actor, sanitize, moderator, opts) {
	assertSanitize(sanitize, "postModerated");
	const normalized = normalizeCommentInput(input);
	const status = await resolveModeratedStatus(moderator, {
		body: normalized.body,
		author: normalized.author,
		target: normalized.target
	}, normalized.target);
	const ref = await insertComment(db, normalized, status, sanitize, opts);
	const comment = await getById(db, ref.id, {
		id: actor?.id ?? "system",
		canModerate: true
	}, opts);
	if (!comment) throw new CommentNotFoundError(`id=${ref.id}`);
	return comment;
}
/**
* moderate — re-classify an existing comment (moderator queue).
* Classifier errors propagate; existing status unchanged on failure.
*/
async function moderate(db, id, moderator, actor, opts) {
	assertCanModerate(actor, "moderate", id);
	const existing = await getById(db, id, actor, opts);
	if (!existing) throw new CommentNotFoundError(`id=${id}`);
	const verdict = await moderator.classify({
		body: existing.body,
		author: existing.author,
		target: existing.target
	});
	if (!isModeratableStatus(verdict?.status)) throw new CommentModerationError(`invalid verdict status: ${JSON.stringify(verdict?.status)}`);
	await setStatus(db, id, verdict.status, actor, opts);
	const updated = await getById(db, id, actor, opts);
	if (!updated) throw new CommentNotFoundError(`id=${id}`);
	return updated;
}
/** Reference ai-backed moderator — client errors propagate to caller fail-safe. */
function aiModerator(client, opts) {
	const threshold = opts?.threshold ?? .5;
	return { async classify(input) {
		const { spamScore } = await client.classify(input);
		if (typeof spamScore !== "number" || !Number.isFinite(spamScore)) throw new CommentModerationError(`invalid spamScore: ${typeof spamScore === "number" ? spamScore : typeof spamScore}`);
		return { status: spamScore >= threshold ? "spam" : "published" };
	} };
}
//#endregion
export { CLASSIFY_TIMEOUT_MS, CommentModerationError, CommentNotFoundError, CommentSanitizationError, aiModerator, isCommentError, moderate, postModerated };
