import { a as encodeCursor, i as decodeCursor, n as InvalidCursorError } from "./types-CuW0zWDA.mjs";
import { a as getDb } from "./loader-CB6YHeul.mjs";
import { ulid } from "ulidx";

//#region src/sections/index.ts
/**
* Get a section by slug
*
* @example
* ```ts
* import { getSection } from "emdash";
*
* const section = await getSection("hero-centered");
* if (section) {
*   console.log(section.content); // Portable Text array
* }
* ```
*/
async function getSection(slug) {
	return getSectionWithDb(slug, await getDb());
}
/**
* Get a section by slug (with explicit db)
*
* @internal Use `getSection()` in templates. This variant is for admin routes
* that already have a database handle.
*/
async function getSectionWithDb(slug, db) {
	const row = await db.selectFrom("_emdash_sections").selectAll().$castTo().where("slug", "=", slug).executeTakeFirst();
	if (!row) return null;
	return rowToSection(row, db);
}
/**
* Get a section by ID
*
* @internal Primarily for admin use
*/
async function getSectionById(id, db) {
	const row = await db.selectFrom("_emdash_sections").selectAll().$castTo().where("id", "=", id).executeTakeFirst();
	if (!row) return null;
	return rowToSection(row, db);
}
/**
* Get all sections with optional filtering
*
* @example
* ```ts
* import { getSections } from "emdash";
*
* // Get all theme-provided sections
* const themeSections = await getSections({ source: "theme" });
*
* // Search sections
* const results = await getSections({ search: "pricing" });
* ```
*/
async function getSections(options = {}) {
	return getSectionsWithDb(await getDb(), options);
}
/**
* Get all sections with optional filtering (with explicit db)
*
* @internal Use `getSections()` in templates. This variant is for admin routes
* that already have a database handle.
*/
async function getSectionsWithDb(db, options = {}) {
	const limit = Math.min(Math.max(1, options.limit || 50), 100);
	let query = db.selectFrom("_emdash_sections").selectAll();
	if (options.source) query = query.where("source", "=", options.source);
	if (options.search) {
		const searchTerm = `%${options.search.toLowerCase()}%`;
		query = query.where((eb) => eb.or([
			eb("title", "like", searchTerm),
			eb("description", "like", searchTerm),
			eb("keywords", "like", searchTerm)
		]));
	}
	query = query.orderBy("title", "asc").orderBy("id", "asc");
	if (options.cursor) {
		const decoded = decodeCursor(options.cursor);
		query = query.where((eb) => eb.or([eb("title", ">", decoded.orderValue), eb.and([eb("title", "=", decoded.orderValue), eb("id", ">", decoded.id)])]));
	}
	query = query.limit(limit + 1);
	const rows = await query.$castTo().execute();
	const hasMore = rows.length > limit;
	const sliced = rows.slice(0, limit);
	const items = await Promise.all(sliced.map((row) => rowToSection(row, db)));
	const result = { items };
	if (hasMore && items.length > 0) {
		const last = items.at(-1);
		result.nextCursor = encodeCursor(last.title, last.id);
	}
	return result;
}
/**
* Convert a section row to the API type
*/
async function rowToSection(row, db) {
	let keywords = [];
	if (row.keywords) try {
		keywords = JSON.parse(row.keywords);
	} catch {}
	let content = [];
	if (row.content) try {
		const parsed = JSON.parse(row.content);
		if (Array.isArray(parsed)) content = parsed;
	} catch {}
	let previewUrl;
	if (row.preview_media_id) {
		const media = await db.selectFrom("media").select("storage_key").where("id", "=", row.preview_media_id).executeTakeFirst();
		if (media) previewUrl = `/_emdash/media/${media.storage_key}`;
	}
	return {
		id: row.id,
		slug: row.slug,
		title: row.title,
		description: row.description ?? void 0,
		keywords,
		content,
		previewUrl,
		source: row.source,
		themeId: row.theme_id ?? void 0,
		createdAt: row.created_at,
		updatedAt: row.updated_at
	};
}

//#endregion
//#region src/api/handlers/sections.ts
const SLUG_PATTERN = /^[a-z0-9-]+$/;
/**
* List sections with optional filters
*/
async function handleSectionList(db, params) {
	try {
		return {
			success: true,
			data: await getSectionsWithDb(db, {
				source: params.source,
				search: params.search,
				limit: params.limit,
				cursor: params.cursor
			})
		};
	} catch (error) {
		if (error instanceof InvalidCursorError) return {
			success: false,
			error: {
				code: "INVALID_CURSOR",
				message: error.message
			}
		};
		return {
			success: false,
			error: {
				code: "SECTION_LIST_ERROR",
				message: "Failed to fetch sections"
			}
		};
	}
}
/**
* Create a section
*/
async function handleSectionCreate(db, input) {
	try {
		if (!SLUG_PATTERN.test(input.slug)) return {
			success: false,
			error: {
				code: "VALIDATION_ERROR",
				message: "slug must only contain lowercase letters, numbers, and hyphens"
			}
		};
		if (await db.selectFrom("_emdash_sections").select("id").where("slug", "=", input.slug).executeTakeFirst()) return {
			success: false,
			error: {
				code: "CONFLICT",
				message: `Section with slug "${input.slug}" already exists`
			}
		};
		const id = ulid();
		const now = (/* @__PURE__ */ new Date()).toISOString();
		await db.insertInto("_emdash_sections").values({
			id,
			slug: input.slug,
			title: input.title,
			description: input.description ?? null,
			keywords: input.keywords ? JSON.stringify(input.keywords) : null,
			content: JSON.stringify(input.content),
			preview_media_id: input.previewMediaId ?? null,
			source: input.source ?? "user",
			theme_id: input.themeId ?? null,
			created_at: now,
			updated_at: now
		}).execute();
		const section = await getSectionById(id, db);
		if (!section) return {
			success: false,
			error: {
				code: "SECTION_CREATE_ERROR",
				message: "Failed to fetch created section"
			}
		};
		return {
			success: true,
			data: section
		};
	} catch {
		return {
			success: false,
			error: {
				code: "SECTION_CREATE_ERROR",
				message: "Failed to create section"
			}
		};
	}
}
/**
* Get a section by slug
*/
async function handleSectionGet(db, slug) {
	try {
		const section = await getSectionWithDb(slug, db);
		if (!section) return {
			success: false,
			error: {
				code: "NOT_FOUND",
				message: `Section "${slug}" not found`
			}
		};
		return {
			success: true,
			data: section
		};
	} catch {
		return {
			success: false,
			error: {
				code: "SECTION_GET_ERROR",
				message: "Failed to fetch section"
			}
		};
	}
}
/**
* Update a section by slug
*/
async function handleSectionUpdate(db, slug, input) {
	try {
		const existing = await db.selectFrom("_emdash_sections").select(["id", "source"]).where("slug", "=", slug).executeTakeFirst();
		if (!existing) return {
			success: false,
			error: {
				code: "NOT_FOUND",
				message: `Section "${slug}" not found`
			}
		};
		if (input.slug && input.slug !== slug) {
			if (!SLUG_PATTERN.test(input.slug)) return {
				success: false,
				error: {
					code: "VALIDATION_ERROR",
					message: "slug must only contain lowercase letters, numbers, and hyphens"
				}
			};
			if (await db.selectFrom("_emdash_sections").select("id").where("slug", "=", input.slug).executeTakeFirst()) return {
				success: false,
				error: {
					code: "CONFLICT",
					message: `Section with slug "${input.slug}" already exists`
				}
			};
		}
		const updates = { updated_at: (/* @__PURE__ */ new Date()).toISOString() };
		if (input.slug !== void 0) updates.slug = input.slug;
		if (input.title !== void 0) updates.title = input.title;
		if (input.description !== void 0) updates.description = input.description;
		if (input.keywords !== void 0) updates.keywords = JSON.stringify(input.keywords);
		if (input.content !== void 0) updates.content = JSON.stringify(input.content);
		if (input.previewMediaId !== void 0) updates.preview_media_id = input.previewMediaId;
		await db.updateTable("_emdash_sections").set(updates).where("id", "=", existing.id).execute();
		const section = await getSectionById(existing.id, db);
		if (!section) return {
			success: false,
			error: {
				code: "SECTION_UPDATE_ERROR",
				message: "Failed to fetch updated section"
			}
		};
		return {
			success: true,
			data: section
		};
	} catch {
		return {
			success: false,
			error: {
				code: "SECTION_UPDATE_ERROR",
				message: "Failed to update section"
			}
		};
	}
}
/**
* Delete a section by slug
*/
async function handleSectionDelete(db, slug) {
	try {
		const existing = await db.selectFrom("_emdash_sections").select([
			"id",
			"source",
			"theme_id"
		]).where("slug", "=", slug).executeTakeFirst();
		if (!existing) return {
			success: false,
			error: {
				code: "NOT_FOUND",
				message: `Section "${slug}" not found`
			}
		};
		if (existing.source === "theme") return {
			success: false,
			error: {
				code: "FORBIDDEN",
				message: "Cannot delete theme-provided sections. Edit the section to create a user copy, then delete that."
			}
		};
		await db.deleteFrom("_emdash_sections").where("id", "=", existing.id).execute();
		return {
			success: true,
			data: { deleted: true }
		};
	} catch {
		return {
			success: false,
			error: {
				code: "SECTION_DELETE_ERROR",
				message: "Failed to delete section"
			}
		};
	}
}

//#endregion
export { handleSectionUpdate as a, handleSectionList as i, handleSectionDelete as n, getSection as o, handleSectionGet as r, getSections as s, handleSectionCreate as t };
//# sourceMappingURL=sections-CpF5SaGr.mjs.map