import { scheduledTriggers } from "../../db/runtime/runtime-schema.js";
import { computeNextRunAt } from "../../utils/compute-next-run-at.js";
import { and, count, desc, eq, isNotNull, lte } from "drizzle-orm";

//#region src/data-access/runtime/scheduledTriggers.ts
const getScheduledTriggerById = (db) => async (params) => {
	const conditions = [
		eq(scheduledTriggers.tenantId, params.scopes.tenantId),
		eq(scheduledTriggers.projectId, params.scopes.projectId),
		eq(scheduledTriggers.id, params.scheduledTriggerId)
	];
	if (params.scopes.agentId) conditions.push(eq(scheduledTriggers.agentId, params.scopes.agentId));
	return await db.query.scheduledTriggers.findFirst({ where: and(...conditions) });
};
const listScheduledTriggersPaginated = (db) => async (params) => {
	const page = params.pagination?.page || 1;
	const limit = Math.min(params.pagination?.limit || 10, 100);
	const offset = (page - 1) * limit;
	const whereClause = and(eq(scheduledTriggers.tenantId, params.scopes.tenantId), eq(scheduledTriggers.projectId, params.scopes.projectId), eq(scheduledTriggers.agentId, params.scopes.agentId));
	const [data, totalResult] = await Promise.all([db.select().from(scheduledTriggers).where(whereClause).limit(limit).offset(offset).orderBy(desc(scheduledTriggers.createdAt)), db.select({ count: count() }).from(scheduledTriggers).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const createScheduledTrigger = (db) => async (params) => {
	const created = (await db.insert(scheduledTriggers).values(params).returning())[0];
	if (!created) throw new Error("Failed to create scheduled trigger");
	return created;
};
const updateScheduledTrigger = (db) => async (params) => {
	const conditions = [
		eq(scheduledTriggers.tenantId, params.scopes.tenantId),
		eq(scheduledTriggers.projectId, params.scopes.projectId),
		eq(scheduledTriggers.id, params.scheduledTriggerId)
	];
	if (params.scopes.agentId) conditions.push(eq(scheduledTriggers.agentId, params.scopes.agentId));
	const updated = (await db.update(scheduledTriggers).set({
		...params.data,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	}).where(and(...conditions)).returning())[0];
	if (!updated) throw new Error(`Scheduled trigger ${params.scheduledTriggerId} not found for update`);
	return updated;
};
const deleteScheduledTrigger = (db) => async (params) => {
	const conditions = [
		eq(scheduledTriggers.tenantId, params.scopes.tenantId),
		eq(scheduledTriggers.projectId, params.scopes.projectId),
		eq(scheduledTriggers.id, params.scheduledTriggerId)
	];
	if (params.scopes.agentId) conditions.push(eq(scheduledTriggers.agentId, params.scopes.agentId));
	await db.delete(scheduledTriggers).where(and(...conditions));
};
const upsertScheduledTrigger = (db) => async (params) => {
	const nextRunAt = params.data.enabled ?? true ? computeNextRunAt({
		cronExpression: params.data.cronExpression,
		cronTimezone: params.data.cronTimezone,
		runAt: params.data.runAt
	}) : null;
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const values = {
		...params.data,
		nextRunAt
	};
	const upserted = (await db.insert(scheduledTriggers).values(values).onConflictDoUpdate({
		target: [scheduledTriggers.tenantId, scheduledTriggers.id],
		set: {
			...values,
			updatedAt: now
		}
	}).returning())[0];
	if (!upserted) throw new Error(`Failed to upsert scheduled trigger ${params.data.id}`);
	return upserted;
};
const deleteScheduledTriggersByRunAsUserId = (db) => async (params) => {
	await db.delete(scheduledTriggers).where(and(eq(scheduledTriggers.tenantId, params.tenantId), eq(scheduledTriggers.projectId, params.projectId), eq(scheduledTriggers.runAsUserId, params.runAsUserId)));
};
const listScheduledTriggers = (db) => async (params) => {
	return await db.select().from(scheduledTriggers).where(and(eq(scheduledTriggers.tenantId, params.scopes.tenantId), eq(scheduledTriggers.projectId, params.scopes.projectId), eq(scheduledTriggers.agentId, params.scopes.agentId)));
};
/**
* Query due scheduled triggers across all projects directly from the runtime DB.
* No AS OF queries needed - simple WHERE clause on enabled + nextRunAt.
*/
const findDueScheduledTriggersAcrossProjects = (db) => async (params) => {
	return await db.select().from(scheduledTriggers).where(and(eq(scheduledTriggers.enabled, true), isNotNull(scheduledTriggers.nextRunAt), lte(scheduledTriggers.nextRunAt, params.asOf)));
};
/**
* Advance the next_run_at timestamp for a scheduled trigger in the runtime DB.
* No withRef scope needed - direct update.
*/
const advanceScheduledTriggerNextRunAt = (db) => async (params) => {
	const set = {
		nextRunAt: params.nextRunAt,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	};
	if (params.enabled !== void 0) set.enabled = params.enabled;
	const conditions = [
		eq(scheduledTriggers.tenantId, params.scopes.tenantId),
		eq(scheduledTriggers.projectId, params.scopes.projectId),
		eq(scheduledTriggers.id, params.scheduledTriggerId)
	];
	if (params.scopes.agentId) conditions.push(eq(scheduledTriggers.agentId, params.scopes.agentId));
	await db.update(scheduledTriggers).set(set).where(and(...conditions));
};
const findScheduledTriggerByDatasetRunConfigId = (db) => async (params) => {
	const [result] = await db.select().from(scheduledTriggers).where(and(eq(scheduledTriggers.tenantId, params.tenantId), eq(scheduledTriggers.projectId, params.projectId), eq(scheduledTriggers.datasetRunConfigId, params.datasetRunConfigId)));
	return result;
};

//#endregion
export { advanceScheduledTriggerNextRunAt, createScheduledTrigger, deleteScheduledTrigger, deleteScheduledTriggersByRunAsUserId, findDueScheduledTriggersAcrossProjects, findScheduledTriggerByDatasetRunConfigId, getScheduledTriggerById, listScheduledTriggers, listScheduledTriggersPaginated, updateScheduledTrigger, upsertScheduledTrigger };