import { sql } from "drizzle-orm";
import { drizzle } from "drizzle-orm/d1";
//#region src/sqlite/d1.ts
/** Structural error so callers do not depend on a provider exception instance. */
var D1BatchError = class extends Error {
	detail;
	code = "d1-batch";
	constructor(detail) {
		super(`D1 atomic batch failed: ${detail}`);
		this.detail = detail;
		this.name = "D1BatchError";
	}
};
/**
* Batch guard for optimistic writes. Place this immediately after a D1 UPDATE/DELETE
* whose affected-row count must match exactly. A mismatch deliberately raises a
* SQLite JSON error, which aborts and rolls back the whole binding batch.
*/
function d1AssertPreviousChanges(expected = 1) {
	if (!Number.isSafeInteger(expected) || expected < 0) throw new D1BatchError("expected change count must be a non-negative safe integer");
	return sql`SELECT CASE WHEN changes() = ${sql.raw(String(expected))} THEN 1 ELSE json_extract('not-json', '$') END AS ok`;
}
function isD1BatchError(error) {
	if (typeof error !== "object" || error === null) return false;
	const candidate = error;
	return candidate.code === "d1-batch" && typeof candidate.detail === "string";
}
/**
* Creates D1's truthful capability surface: ordinary queries plus one-shot atomic batches.
* D1 has no interactive callback transaction API.
*/
function createD1Client(binding, opts = {}) {
	const db = drizzle(binding, { schema: opts.schema });
	const native = binding;
	const prepared = /* @__PURE__ */ new WeakMap();
	const client = Object.assign(db, {
		execute: (query) => db.all(query),
		prepare: (query) => {
			const raw = db.all(query);
			const item = Object.freeze({});
			prepared.set(item, raw.getQuery());
			return item;
		},
		batch: async (items) => {
			if (items.length === 0) throw new D1BatchError("batch must contain at least one prepared statement");
			try {
				const statements = items.map((item) => {
					const query = prepared.get(item);
					if (!query) throw new D1BatchError("batch item was not prepared by this D1 client");
					return native.prepare(query.sql).bind(...query.params);
				});
				const result = await native.batch(statements);
				if (result.length !== items.length) throw new D1BatchError("binding returned an invalid batch result length");
				return result.map((entry) => [...entry.results ?? []]);
			} catch (error) {
				if (isD1BatchError(error)) throw error;
				throw new D1BatchError(error instanceof Error ? error.message : "binding rejected batch");
			}
		}
	});
	return new Proxy(client, {
		get(target, property, receiver) {
			if (property === "transaction") return void 0;
			return Reflect.get(target, property, receiver);
		},
		has(target, property) {
			return property === "transaction" ? false : Reflect.has(target, property);
		}
	});
}
//#endregion
export { D1BatchError, createD1Client, d1AssertPreviousChanges, isD1BatchError };
