globalThis.process ??= {};
globalThis.process.env ??= {};
import { A as inArray, C as asc, E as eq, P as ne, T as and, Tt as sql } from "./d1_DTqC4o_t.mjs";
import { d as translationValue, u as languages } from "./db_DZJ1iBSP.mjs";
//#region ../../packages/i18n-content/dist/index.js
var I18nContentError = class extends Error {
	code;
	name = "I18nContentError";
	_tag = "I18nContentError";
	constructor(code, message) {
		super(message);
		this.code = code;
	}
};
var UnknownLocaleError = class extends I18nContentError {
	locale;
	name = "UnknownLocaleError";
	constructor(locale) {
		super("UNKNOWN_LOCALE", `locale '${locale}' is not active or does not exist`);
		this.locale = locale;
	}
};
var InvalidFieldKeyError = class extends I18nContentError {
	key;
	name = "InvalidFieldKeyError";
	constructor(key) {
		super("INVALID_FIELD_KEY", `field key '${key}' is invalid`);
		this.key = key;
	}
};
var InvalidEntityIdError = class extends I18nContentError {
	entityId;
	name = "InvalidEntityIdError";
	constructor(entityId) {
		super("INVALID_ENTITY_ID", `entity id '${entityId}' is invalid (must be non-empty, ≤ 1024 chars, no null bytes)`);
		this.entityId = entityId;
	}
};
var FIELD_KEY_RE = /^[a-z][a-z0-9_]*$/;
var ENTITY_ID_MAX_LEN = 1024;
function assertFieldKey(key) {
	if (!key || !FIELD_KEY_RE.test(key)) throw new InvalidFieldKeyError(key);
}
function assertEntityType(t) {
	if (!t || !FIELD_KEY_RE.test(t)) throw new InvalidFieldKeyError(t);
}
function assertEntityId(id) {
	if (!id || id.length > ENTITY_ID_MAX_LEN || id.includes("\0")) throw new InvalidEntityIdError(id);
}
function rowToLanguage(row) {
	return {
		code: row.code,
		nameNative: row.nameNative,
		nameEnglish: row.nameEnglish,
		direction: row.direction,
		searchConfig: row.searchConfig,
		isActive: row.isActive,
		isDefault: row.isDefault,
		sortOrder: row.sortOrder,
		createdAt: row.createdAt,
		updatedAt: row.updatedAt
	};
}
async function listLanguages(q, opts) {
	return (opts?.activeOnly ? await q.select().from(languages).where(eq(languages.isActive, true)).orderBy(asc(languages.sortOrder)) : await q.select().from(languages).orderBy(asc(languages.sortOrder))).map(rowToLanguage);
}
async function getDefaultLocale(q) {
	const [row] = await q.select({ code: languages.code }).from(languages).where(eq(languages.isDefault, true)).limit(1);
	if (!row) throw new I18nContentError("NO_DEFAULT_LOCALE", "no default locale configured");
	return row.code;
}
async function isLocaleActive(q, code) {
	const [row] = await q.select({ isActive: languages.isActive }).from(languages).where(eq(languages.code, code)).limit(1);
	return row?.isActive === true;
}
async function setTranslation(q, args) {
	assertEntityType(args.entityType);
	assertFieldKey(args.fieldKey);
	assertEntityId(args.entityId);
	if (!await isLocaleActive(q, args.locale)) throw new UnknownLocaleError(args.locale);
	const manualOverride = args.manualOverride ?? false;
	const sourceHash = args.sourceHash ?? "";
	const modelId = args.modelId ?? null;
	const isProtectedMachineWrite = !manualOverride;
	const conflictTarget = [
		translationValue.entityType,
		translationValue.entityId,
		translationValue.fieldKey,
		translationValue.locale
	];
	if (isProtectedMachineWrite) {
		await q.insert(translationValue).values({
			entityType: args.entityType,
			entityId: args.entityId,
			fieldKey: args.fieldKey,
			locale: args.locale,
			value: args.value,
			sourceHash,
			modelId,
			manualOverride: false,
			status: "OK",
			translatedAt: sql`now()`,
			updatedAt: sql`now()`
		}).onConflictDoUpdate({
			target: conflictTarget,
			set: {
				value: sql`excluded.value`,
				sourceHash: sql`excluded.source_hash`,
				modelId: sql`excluded.model_id`,
				status: sql`'OK'`,
				translatedAt: sql`now()`,
				updatedAt: sql`now()`
			},
			setWhere: sql`NOT ${translationValue.manualOverride}`
		});
		return;
	}
	await q.insert(translationValue).values({
		entityType: args.entityType,
		entityId: args.entityId,
		fieldKey: args.fieldKey,
		locale: args.locale,
		value: args.value,
		sourceHash,
		modelId,
		manualOverride,
		status: "OK",
		translatedAt: sql`now()`,
		updatedAt: sql`now()`
	}).onConflictDoUpdate({
		target: conflictTarget,
		set: {
			value: args.value,
			sourceHash,
			modelId,
			manualOverride,
			status: "OK",
			translatedAt: sql`now()`,
			updatedAt: sql`now()`
		}
	});
}
async function markFailed(q, args) {
	assertEntityType(args.entityType);
	assertFieldKey(args.fieldKey);
	assertEntityId(args.entityId);
	if (!await isLocaleActive(q, args.locale)) throw new UnknownLocaleError(args.locale);
	const sourceHash = args.sourceHash ?? "";
	const modelId = args.modelId ?? null;
	const conflictTarget = [
		translationValue.entityType,
		translationValue.entityId,
		translationValue.fieldKey,
		translationValue.locale
	];
	await q.insert(translationValue).values({
		entityType: args.entityType,
		entityId: args.entityId,
		fieldKey: args.fieldKey,
		locale: args.locale,
		value: "",
		sourceHash,
		modelId,
		manualOverride: false,
		status: "FAILED",
		translatedAt: null,
		updatedAt: sql`now()`
	}).onConflictDoUpdate({
		target: conflictTarget,
		set: {
			value: sql`''`,
			sourceHash: sql`excluded.source_hash`,
			modelId: sql`excluded.model_id`,
			status: sql`'FAILED'`,
			translatedAt: sql`null`,
			updatedAt: sql`now()`
		},
		setWhere: sql`NOT ${translationValue.manualOverride} AND ${translationValue.status} <> 'OK'`
	});
}
async function markStale(q, args) {
	assertEntityType(args.entityType);
	assertEntityId(args.entityId);
	const entries = Object.entries(args.fieldHashes);
	if (entries.length === 0) return;
	for (const [field, newHash] of entries) {
		assertFieldKey(field);
		await q.update(translationValue).set({
			status: "STALE",
			updatedAt: sql`now()`
		}).where(and(eq(translationValue.entityType, args.entityType), eq(translationValue.entityId, args.entityId), eq(translationValue.fieldKey, field), eq(translationValue.manualOverride, false), ne(translationValue.status, sql`'FAILED'`), ne(translationValue.sourceHash, newHash)));
	}
}
function validateReadArgs(entityType, fields) {
	assertEntityType(entityType);
	if (fields) for (const field of fields) assertFieldKey(field);
}
function buildReadConditions(entityType, locales, fields) {
	const conditions = [
		eq(translationValue.entityType, entityType),
		inArray(translationValue.locale, [...locales]),
		ne(translationValue.status, "FAILED"),
		ne(translationValue.value, "")
	];
	if (fields && fields.length > 0) conditions.push(inArray(translationValue.fieldKey, [...fields]));
	return conditions;
}
function mergeLocaleRows(rows, requestedLocale, fallbackToDefault) {
	const primary = /* @__PURE__ */ new Map();
	const fallback = /* @__PURE__ */ new Map();
	for (const row of rows) if (row.locale === requestedLocale) primary.set(row.fieldKey, row.value);
	else if (fallbackToDefault) fallback.set(row.fieldKey, row.value);
	const result = {};
	const keys = /* @__PURE__ */ new Set([...primary.keys(), ...fallbackToDefault ? fallback.keys() : []]);
	for (const key of keys) {
		const value = primary.get(key) ?? fallback.get(key);
		if (value !== void 0) result[key] = value;
	}
	return result;
}
async function resolveLocales(q, locale, fallbackToDefault) {
	if (!fallbackToDefault) return [locale];
	const defaultLocale = await getDefaultLocale(q);
	if (defaultLocale === locale) return [locale];
	return [locale, defaultLocale];
}
async function getTranslationsFor(q, args) {
	validateReadArgs(args.entityType, args.fields);
	if (args.entityIds.length === 0) return /* @__PURE__ */ new Map();
	const fallbackToDefault = args.fallbackToDefault ?? false;
	const locales = await resolveLocales(q, args.locale, fallbackToDefault);
	const rows = await q.select({
		entityId: translationValue.entityId,
		fieldKey: translationValue.fieldKey,
		locale: translationValue.locale,
		value: translationValue.value
	}).from(translationValue).where(and(inArray(translationValue.entityId, [...args.entityIds]), ...buildReadConditions(args.entityType, locales, args.fields)));
	const byEntity = /* @__PURE__ */ new Map();
	for (const row of rows) {
		const list = byEntity.get(row.entityId) ?? [];
		list.push(row);
		byEntity.set(row.entityId, list);
	}
	const result = /* @__PURE__ */ new Map();
	for (const entityId of args.entityIds) {
		const entityRows = byEntity.get(entityId) ?? [];
		result.set(entityId, mergeLocaleRows(entityRows, args.locale, fallbackToDefault));
	}
	return result;
}
//#endregion
export { markFailed as a, listLanguages as i, getTranslationsFor as n, markStale as o, isLocaleActive as r, setTranslation as s, getDefaultLocale as t };
