import { messages } from "../../db/runtime/runtime-schema.js";
import { projectScopedWhere } from "../manage/scope-helpers.js";
import { and, asc, count, desc, eq, inArray } from "drizzle-orm";

//#region src/data-access/runtime/messages.ts
const getMessageById = (db) => async (params) => {
	return db.query.messages.findFirst({ where: and(projectScopedWhere(messages, params.scopes), eq(messages.id, params.messageId)) });
};
const listMessages = (db) => async (params) => {
	const page = params.pagination?.page || 1;
	const limit = Math.min(params.pagination?.limit || 10, 100);
	const offset = (page - 1) * limit;
	return await db.select().from(messages).where(projectScopedWhere(messages, params.scopes)).limit(limit).offset(offset).orderBy(desc(messages.createdAt));
};
const getMessagesByConversation = (db) => async (params) => {
	const page = params.pagination?.page || 1;
	const limit = Math.min(params.pagination?.limit || 10, 100);
	const offset = (page - 1) * limit;
	return await db.select().from(messages).where(and(projectScopedWhere(messages, params.scopes), eq(messages.conversationId, params.conversationId))).limit(limit).offset(offset).orderBy(desc(messages.createdAt));
};
/**
* Batch-fetch the earliest `user` message for each of the given conversations in a single
* query (Postgres `DISTINCT ON`), returning one row per conversation.
*
* Set-based alternative to calling {@link getMessagesByConversation} once per conversation
* and reducing in JS, which fanned out two connection acquisitions per conversation and
* exhausted the runtime DB pool when enriching large evaluation-result sets.
*/
const getFirstUserMessageByConversations = (db) => async (params) => {
	if (params.conversationIds.length === 0) return [];
	return await db.selectDistinctOn([messages.conversationId], {
		conversationId: messages.conversationId,
		content: messages.content
	}).from(messages).where(and(projectScopedWhere(messages, params.scopes), inArray(messages.conversationId, params.conversationIds), eq(messages.role, "user"))).orderBy(messages.conversationId, asc(messages.createdAt), asc(messages.id));
};
/**
* Batch-fetch the latest assistant/agent message for each of the given conversations in a
* single query (Postgres `DISTINCT ON`), returning one row per conversation.
*
* Set-based alternative to the per-conversation lookup used when enriching dataset-run items
* with their agent output.
*/
const getLastAssistantMessageByConversations = (db) => async (params) => {
	if (params.conversationIds.length === 0) return [];
	return await db.selectDistinctOn([messages.conversationId], {
		conversationId: messages.conversationId,
		content: messages.content
	}).from(messages).where(and(projectScopedWhere(messages, params.scopes), inArray(messages.conversationId, params.conversationIds), inArray(messages.role, ["assistant", "agent"]))).orderBy(messages.conversationId, desc(messages.createdAt), desc(messages.id));
};
const getMessagesByTask = (db) => async (params) => {
	const page = params.pagination?.page || 1;
	const limit = Math.min(params.pagination?.limit || 10, 100);
	const offset = (page - 1) * limit;
	return await db.select().from(messages).where(and(projectScopedWhere(messages, params.scopes), eq(messages.taskId, params.taskId))).limit(limit).offset(offset).orderBy(asc(messages.createdAt));
};
const getVisibleMessages = (db) => async (params) => {
	const page = params.pagination?.page || 1;
	const limit = Math.min(params.pagination?.limit || 10, 100);
	const offset = (page - 1) * limit;
	const visibilityFilter = params.visibility || ["user-facing"];
	return await db.select().from(messages).where(and(projectScopedWhere(messages, params.scopes), eq(messages.conversationId, params.conversationId), inArray(messages.visibility, visibilityFilter))).limit(limit).offset(offset).orderBy(asc(messages.createdAt));
};
const createMessage = (db) => async (params) => {
	const { scopes, data } = params;
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [created] = await db.insert(messages).values({
		...data,
		tenantId: scopes.tenantId,
		projectId: scopes.projectId,
		createdAt: now,
		updatedAt: now
	}).returning();
	return created;
};
const updateMessage = (db) => async (params) => {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [updated] = await db.update(messages).set({
		...params.data,
		updatedAt: now
	}).where(and(projectScopedWhere(messages, params.scopes), eq(messages.id, params.messageId))).returning();
	return updated;
};
const deleteMessage = (db) => async (params) => {
	const [deleted] = await db.delete(messages).where(and(projectScopedWhere(messages, params.scopes), eq(messages.id, params.messageId))).returning();
	return deleted;
};
const countMessagesByConversation = (db) => async (params) => {
	const total = (await db.select({ count: count() }).from(messages).where(and(projectScopedWhere(messages, params.scopes), eq(messages.conversationId, params.conversationId))))[0]?.count || 0;
	return typeof total === "string" ? Number.parseInt(total, 10) : total;
};
const countVisibleMessages = (db) => async (params) => {
	const visibilityFilter = params.visibility || ["user-facing"];
	const total = (await db.select({ count: count() }).from(messages).where(and(projectScopedWhere(messages, params.scopes), eq(messages.conversationId, params.conversationId), inArray(messages.visibility, visibilityFilter))))[0]?.count || 0;
	return typeof total === "string" ? Number.parseInt(total, 10) : total;
};

//#endregion
export { countMessagesByConversation, countVisibleMessages, createMessage, deleteMessage, getFirstUserMessageByConversations, getLastAssistantMessageByConversations, getMessageById, getMessagesByConversation, getMessagesByTask, getVisibleMessages, listMessages, updateMessage };