import { t as validateIdentifier } from "./validate-VPnKoIzW.mjs";
import { t as CommentRepository } from "./comment-CzeatwBV.mjs";
import { t as escapeHtml } from "./escape-DqD0aCKu.mjs";

//#region src/comments/notifications.ts
const NOTIFICATION_SOURCE = "emdash-comments";
const MAX_EXCERPT_LENGTH = 500;
const CRLF_RE = /[\r\n]/g;
/**
* Build an email notification for a new comment.
*/
function buildCommentNotificationEmail(to, data) {
	const title = data.contentTitle || `${data.collection} item`;
	const subject = `New comment on "${title}"`.replace(CRLF_RE, " ");
	const excerpt = data.commentBody.length > MAX_EXCERPT_LENGTH ? data.commentBody.slice(0, MAX_EXCERPT_LENGTH) + "..." : data.commentBody;
	const adminUrl = `${data.adminBaseUrl}/admin/comments`;
	return {
		to,
		subject,
		text: [
			`${data.commentAuthorName} commented on "${title}":`,
			"",
			excerpt,
			"",
			`View in admin: ${adminUrl}`
		].join("\n"),
		html: [
			`<p><strong>${escapeHtml(data.commentAuthorName)}</strong> commented on &ldquo;${escapeHtml(title)}&rdquo;:</p>`,
			`<blockquote style="border-left:3px solid #ccc;padding-left:12px;margin:12px 0;color:#555">${escapeHtml(excerpt)}</blockquote>`,
			`<p><a href="${escapeHtml(adminUrl)}">View in admin</a></p>`
		].join("\n")
	};
}
/**
* Send a comment notification to the content author if all conditions are met:
* 1. Comment status is "approved"
* 2. Content author exists and has an email
* 3. Email provider is configured
* 4. Commenter is not the content author (no self-notifications)
*
* Returns true if the email was sent, false if skipped.
*/
async function sendCommentNotification(params) {
	const { email, comment, contentAuthor, adminBaseUrl } = params;
	if (comment.status !== "approved") return false;
	if (!contentAuthor?.email) return false;
	if (!email.isAvailable()) return false;
	if (comment.authorEmail.toLowerCase() === contentAuthor.email.toLowerCase()) return false;
	const message = buildCommentNotificationEmail(contentAuthor.email, {
		commentAuthorName: comment.authorName,
		commentBody: comment.body,
		contentTitle: params.contentTitle || "",
		collection: comment.collection,
		adminBaseUrl
	});
	await email.send(message, NOTIFICATION_SOURCE);
	return true;
}
/**
* Look up a content item's author from the database.
*
* Used by the admin moderation route where content info isn't
* readily available (only the comment record is at hand).
*/
async function lookupContentAuthor(db, collection, contentId) {
	validateIdentifier(collection, "collection");
	const contentRow = await db.selectFrom(`ec_${collection}`).select(["slug", "author_id"]).where("id", "=", contentId).executeTakeFirst();
	if (!contentRow) return null;
	const typed = contentRow;
	let author;
	if (typed.author_id) {
		const userRow = await db.selectFrom("users").select([
			"id",
			"name",
			"email",
			"email_verified"
		]).where("id", "=", typed.author_id).executeTakeFirst();
		if (userRow && userRow.email_verified) author = {
			id: userRow.id,
			email: userRow.email,
			name: userRow.name
		};
	}
	return {
		slug: typed.slug,
		author
	};
}

//#endregion
//#region src/comments/service.ts
/**
* Create a comment through the full hook pipeline.
*
* Returns null if the comment was rejected by a beforeCreate handler.
*/
async function createComment(db, input, collectionSettings, hooks, contentInfo) {
	const repo = new CommentRepository(db);
	const beforeCreateEvent = {
		comment: {
			collection: input.collection,
			contentId: input.contentId,
			parentId: input.parentId ?? null,
			authorName: input.authorName,
			authorEmail: input.authorEmail,
			authorUserId: input.authorUserId ?? null,
			body: input.body,
			ipHash: input.ipHash ?? null,
			userAgent: input.userAgent ?? null
		},
		metadata: {}
	};
	const result = await hooks.runBeforeCreate(beforeCreateEvent);
	if (result === false) return null;
	const event = result;
	const priorApprovedCount = await repo.countApprovedByEmail(event.comment.authorEmail);
	const moderateEvent = {
		comment: event.comment,
		metadata: event.metadata,
		collectionSettings,
		priorApprovedCount
	};
	const decision = await hooks.runModerate(moderateEvent);
	const comment = await repo.create({
		collection: event.comment.collection,
		contentId: event.comment.contentId,
		parentId: event.comment.parentId,
		authorName: event.comment.authorName,
		authorEmail: event.comment.authorEmail,
		authorUserId: event.comment.authorUserId,
		body: event.comment.body,
		status: decision.status,
		ipHash: event.comment.ipHash,
		userAgent: event.comment.userAgent,
		moderationMetadata: Object.keys(event.metadata).length > 0 ? event.metadata : null
	});
	if (contentInfo) {
		const afterEvent = {
			comment: commentToStored(comment),
			metadata: event.metadata,
			content: {
				id: contentInfo.id,
				collection: contentInfo.collection,
				slug: contentInfo.slug,
				title: contentInfo.title
			},
			contentAuthor: contentInfo.author
		};
		hooks.fireAfterCreate(afterEvent);
	}
	return {
		comment,
		decision
	};
}
/**
* Admin moderation — change a comment's status.
* Fires comment:afterModerate hook.
*/
async function moderateComment(db, id, newStatus, moderator, hooks) {
	const repo = new CommentRepository(db);
	const existing = await repo.findById(id);
	if (!existing) return null;
	const previousStatus = existing.status;
	const updated = await repo.updateStatus(id, newStatus);
	if (!updated) return null;
	const afterEvent = {
		comment: commentToStored(updated),
		previousStatus,
		newStatus,
		moderator
	};
	hooks.fireAfterModerate(afterEvent);
	return updated;
}
function commentToStored(comment) {
	return {
		id: comment.id,
		collection: comment.collection,
		contentId: comment.contentId,
		parentId: comment.parentId,
		authorName: comment.authorName,
		authorEmail: comment.authorEmail,
		authorUserId: comment.authorUserId,
		body: comment.body,
		status: comment.status,
		moderationMetadata: comment.moderationMetadata,
		createdAt: comment.createdAt,
		updatedAt: comment.updatedAt
	};
}

//#endregion
export { sendCommentNotification as i, moderateComment as n, lookupContentAuthor as r, createComment as t };
//# sourceMappingURL=service-DQmiBMzt.mjs.map