import { ScopeViolationError } from "./index.js";
import { sql } from "drizzle-orm";
//#region src/isolation-rls.ts
function quotedIdent(ident) {
	if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(ident)) throw new Error(`invalid SQL identifier: ${ident}`);
	return `"${ident.replace(/"/g, "\"\"")}"`;
}
async function runInTenant(db, tenantId, fn, opts) {
	const gucName = opts?.gucName ?? "app.current_tenant";
	return db.transaction(async (tx) => {
		await tx.execute(sql`select set_config(${gucName}, ${tenantId}, true)`);
		if (opts?.role) await tx.execute(sql.raw(`SET LOCAL ROLE ${quotedIdent(opts.role)}`));
		const res = await tx.execute(sql`SELECT ((current_setting('is_superuser') = 'on') OR EXISTS (SELECT 1 FROM pg_roles WHERE rolname = current_user AND rolbypassrls)) AS can_bypass, current_user AS effective_role`);
		const row = (Array.isArray(res) ? res : res.rows)?.[0];
		if (row?.can_bypass) throw new ScopeViolationError(`tenancy: runInTenant requires a non-superuser, non-BYPASSRLS role — RLS is silently bypassed by privileged roles (current_user=${row?.effective_role ?? "unknown"}). See the security floor in the boundary spec.`, tenantId);
		return fn(tx);
	});
}
function tenantPolicyDDL(tableName, opts) {
	const column = opts?.column ?? "tenant_id";
	const gucName = opts?.gucName ?? "app.current_tenant";
	const force = opts?.force ?? true;
	const table = quotedIdent(tableName);
	const col = quotedIdent(column);
	const statements = [`ALTER TABLE ${table} ENABLE ROW LEVEL SECURITY`];
	if (force) statements.push(`ALTER TABLE ${table} FORCE ROW LEVEL SECURITY`);
	statements.push(`CREATE POLICY tenant_isolation ON ${table} USING (${col}::text = current_setting('${gucName.replace(/'/g, "''")}', true))`);
	return statements;
}
//#endregion
export { runInTenant, tenantPolicyDDL };
