import { streamChunks } from "../../db/runtime/runtime-schema.js";
import { and, eq, gt, sql } from "drizzle-orm";

//#region src/data-access/runtime/streamChunks.ts
const DEFAULT_CHUNK_BATCH_LIMIT = 500;
const DEFAULT_CLEANUP_AGE_MINUTES = 60;
const DEFAULT_CLEANUP_BATCH_SIZE = 1e3;
const scopeConditions = (scope) => [
	eq(streamChunks.tenantId, scope.tenantId),
	eq(streamChunks.projectId, scope.projectId),
	eq(streamChunks.conversationId, scope.conversationId)
];
const insertStreamChunks = (db) => async (params) => {
	if (params.chunks.length === 0) return;
	await db.insert(streamChunks).values(params.chunks.map((chunk) => ({
		tenantId: params.tenantId,
		projectId: params.projectId,
		conversationId: params.conversationId,
		idx: chunk.idx,
		data: chunk.data,
		isFinal: false
	})));
};
const markStreamComplete = (db) => async (params) => {
	await db.insert(streamChunks).values({
		tenantId: params.tenantId,
		projectId: params.projectId,
		conversationId: params.conversationId,
		idx: params.finalIdx,
		data: "",
		isFinal: true
	});
};
const getStreamChunks = (db) => async (params) => {
	const conditions = scopeConditions(params);
	if (params.afterIdx !== void 0) conditions.push(gt(streamChunks.idx, params.afterIdx));
	return db.select({
		idx: streamChunks.idx,
		data: streamChunks.data,
		isFinal: streamChunks.isFinal
	}).from(streamChunks).where(and(...conditions)).orderBy(streamChunks.idx).limit(params.limit ?? DEFAULT_CHUNK_BATCH_LIMIT);
};
const deleteStreamChunks = (db) => async (params) => {
	await db.delete(streamChunks).where(and(...scopeConditions(params)));
};
const cleanupExpiredStreamChunks = (db) => async (olderThanMinutes = DEFAULT_CLEANUP_AGE_MINUTES, batchSize = DEFAULT_CLEANUP_BATCH_SIZE) => {
	const cutoff = sql`now() - make_interval(mins => ${olderThanMinutes})`;
	let deleted;
	do {
		const batch = await db.select({
			tenantId: streamChunks.tenantId,
			projectId: streamChunks.projectId,
			conversationId: streamChunks.conversationId,
			idx: streamChunks.idx
		}).from(streamChunks).where(sql`${streamChunks.createdAt} < ${cutoff}`).limit(batchSize);
		deleted = batch.length;
		if (deleted > 0) {
			const pks = batch.map((row) => sql`(${row.tenantId}, ${row.projectId}, ${row.conversationId}, ${row.idx})`);
			await db.delete(streamChunks).where(sql`(${streamChunks.tenantId}, ${streamChunks.projectId}, ${streamChunks.conversationId}, ${streamChunks.idx}) IN (${sql.join(pks, sql`, `)})`);
		}
	} while (deleted >= batchSize);
};

//#endregion
export { cleanupExpiredStreamChunks, deleteStreamChunks, getStreamChunks, insertStreamChunks, markStreamComplete };