import { c as getById, m as put, n as ContentNotFoundError } from "./store-D_2h-weW.js";
import { A as contentEntries, F as contentRevisions, m as termsForEntry, s as assignTerms, w as assertCanModify } from "./taxonomy-CmOYaoVZ.js";
import * as drizzle from "drizzle-orm";
//#region src/revisions.ts
/** Idempotent DDL for adopters migrating existing content_entries tables (spec §8). */
const contentRevisionsMigrationSql = () => `
CREATE TABLE IF NOT EXISTS content_revisions (
  id         uuid PRIMARY KEY DEFAULT gen_random_uuid(),
  entry_id   uuid NOT NULL REFERENCES content_entries(id) ON DELETE CASCADE,
  seq        bigserial NOT NULL,
  title      text NOT NULL,
  body       text NOT NULL,
  slug       text NOT NULL,
  type       text NOT NULL,
  term_ids   jsonb NOT NULL DEFAULT '[]'::jsonb,
  snapshot   jsonb,
  editor     text NOT NULL,
  created_at timestamptz(3) NOT NULL DEFAULT NOW(),
  host_session_id text
);
ALTER TABLE content_revisions ADD COLUMN IF NOT EXISTS snapshot jsonb;
ALTER TABLE content_revisions ADD COLUMN IF NOT EXISTS host_session_id text;
CREATE INDEX IF NOT EXISTS content_revisions_entry_seq_idx ON content_revisions (entry_id, seq DESC);
`.trim();
async function getRow(db, id) {
	const [row] = await db.select().from(contentEntries).where(drizzle.eq(contentEntries.id, id)).limit(1);
	if (!row) throw new ContentNotFoundError(`id=${id}`);
	return row;
}
function toRevision(row) {
	return {
		id: row.id,
		entryId: row.entryId,
		seq: row.seq,
		title: row.title,
		body: row.body,
		slug: row.slug,
		type: row.type,
		termIds: row.termIds ?? [],
		editor: row.editor,
		createdAt: row.createdAt
	};
}
/** Append a snapshot of the entry's current live state before a put()-update (spec §4.1). */
async function snapshotRevision(db, entryId, actor) {
	const existing = await getRow(db, entryId);
	assertCanModify(actor, "update", existing.author, existing.id);
	const termIds = (await termsForEntry(db, existing.id)).map((t) => t.id);
	const [inserted] = await db.insert(contentRevisions).values({
		entryId: existing.id,
		title: existing.title,
		body: existing.body,
		slug: existing.slug,
		type: existing.type,
		termIds,
		editor: actor.id
	}).returning();
	return toRevision(inserted);
}
const DEFAULT_LIMIT = 20;
const MAX_LIMIT = 100;
function clampLimit(limit) {
	return Math.min(Math.max(limit ?? DEFAULT_LIMIT, 1), MAX_LIMIT);
}
/** Keyset-paginated revision history for one entry, newest first (spec §4.2). */
async function listRevisions(db, entryId, actor, query = {}) {
	const existing = await getRow(db, entryId);
	assertCanModify(actor, "read", existing.author, existing.id);
	const limit = clampLimit(query.limit);
	const filters = [drizzle.eq(contentRevisions.entryId, entryId)];
	if (query.before !== void 0) filters.push(drizzle.lt(contentRevisions.seq, query.before));
	const rows = await db.select().from(contentRevisions).where(drizzle.and(...filters)).orderBy(drizzle.desc(contentRevisions.seq)).limit(limit + 1);
	const hasMore = rows.length > limit;
	const trimmed = hasMore ? rows.slice(0, limit) : rows;
	return {
		revisions: trimmed.map(toRevision),
		nextCursor: hasMore ? trimmed[trimmed.length - 1].seq : null
	};
}
/** Load one revision by id (spec §4.3). */
async function getRevision(db, revisionId, actor) {
	const [row] = await db.select().from(contentRevisions).where(drizzle.eq(contentRevisions.id, revisionId)).limit(1);
	if (!row) throw new ContentNotFoundError(`revision id=${revisionId}`);
	const parent = await getRow(db, row.entryId);
	assertCanModify(actor, "read", parent.author, parent.id);
	return toRevision(row);
}
/** Restore a revision's content tuple via put(); snapshots current state first (spec §4.4). */
async function restoreRevision(db, revisionId, actor, sanitize) {
	const revision = await getRevision(db, revisionId, actor);
	const parent = await getRow(db, revision.entryId);
	assertCanModify(actor, "update", parent.author, parent.id);
	await snapshotRevision(db, parent.id, actor);
	await put(db, {
		id: parent.id,
		slug: revision.slug,
		type: revision.type,
		title: revision.title,
		body: revision.body
	}, actor, sanitize);
	await assignTerms(db, parent.id, revision.termIds, actor);
	return await getById(db, parent.id, actor);
}
//#endregion
export { contentRevisionsMigrationSql, getRevision, listRevisions, restoreRevision, snapshotRevision };
