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

//#region src/data-access/manage/triggers.ts
/**
* Get a trigger by ID (agent-scoped)
*/
const getTriggerById = (db) => async (params) => {
	const { scopes, triggerId } = params;
	return await db.query.triggers.findFirst({ where: and(agentScopedWhere(triggers, scopes), eq(triggers.id, triggerId)) });
};
/**
* List all triggers for an agent
*/
const listTriggers = (db) => async (params) => {
	return await db.query.triggers.findMany({ where: agentScopedWhere(triggers, params.scopes) });
};
/**
* List triggers for an agent with pagination
*/
const listTriggersPaginated = (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 = agentScopedWhere(triggers, params.scopes);
	const [data, totalResult] = await Promise.all([db.select().from(triggers).where(whereClause).limit(limit).offset(offset).orderBy(desc(triggers.createdAt)), db.select({ count: count() }).from(triggers).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
/**
* Create a new trigger (agent-scoped)
*/
const createTrigger = (db) => async (params) => {
	return (await db.insert(triggers).values(params).returning())[0];
};
const createTriggerWithUsers = (db) => async (params) => {
	return db.transaction(async (tx) => {
		const trigger = await createTrigger(tx)(params.trigger);
		if (params.userIds.length > 0) await tx.insert(triggerUsers).values(params.userIds.map((userId) => ({
			tenantId: trigger.tenantId,
			projectId: trigger.projectId,
			agentId: trigger.agentId,
			triggerId: trigger.id,
			userId
		})));
		return trigger;
	});
};
/**
* Update a trigger (agent-scoped)
*/
const updateTrigger = (db) => async (params) => {
	const updateData = {
		...params.data,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	};
	return (await db.update(triggers).set(updateData).where(and(agentScopedWhere(triggers, params.scopes), eq(triggers.id, params.triggerId))).returning())[0];
};
/**
* Delete a trigger (agent-scoped)
*/
const deleteTrigger = (db) => async (params) => {
	await db.delete(triggers).where(and(agentScopedWhere(triggers, params.scopes), eq(triggers.id, params.triggerId)));
};
/**
* Delete all webhook triggers for a given runAsUserId within a tenant+project scope.
* Operates across all agents in the project (not agent-scoped).
*/
const deleteTriggersByRunAsUserId = (db) => async (params) => {
	await db.delete(triggers).where(and(projectScopedWhere(triggers, {
		tenantId: params.tenantId,
		projectId: params.projectId
	}), eq(triggers.runAsUserId, params.runAsUserId)));
};
const getTriggerUsers = (db) => async (params) => {
	return db.select().from(triggerUsers).where(and(agentScopedWhere(triggerUsers, params.scopes), eq(triggerUsers.triggerId, params.triggerId))).orderBy(asc(triggerUsers.createdAt));
};
const getTriggerUsersBatch = (db) => async (params) => {
	if (params.triggerIds.length === 0) return /* @__PURE__ */ new Map();
	const rows = await db.select().from(triggerUsers).where(and(agentScopedWhere(triggerUsers, params.scopes), inArray(triggerUsers.triggerId, params.triggerIds))).orderBy(asc(triggerUsers.createdAt));
	const result = /* @__PURE__ */ new Map();
	for (const triggerId of params.triggerIds) result.set(triggerId, []);
	for (const row of rows) {
		const userIds = result.get(row.triggerId);
		if (userIds) userIds.push(row.userId);
	}
	return result;
};
const createTriggerUser = (db) => async (params) => {
	return (await db.insert(triggerUsers).values({
		tenantId: params.scopes.tenantId,
		projectId: params.scopes.projectId,
		agentId: params.scopes.agentId,
		triggerId: params.triggerId,
		userId: params.userId
	}).onConflictDoNothing().returning())[0];
};
const deleteTriggerUser = (db) => async (params) => {
	await db.delete(triggerUsers).where(and(agentScopedWhere(triggerUsers, params.scopes), eq(triggerUsers.triggerId, params.triggerId), eq(triggerUsers.userId, params.userId)));
};
const setTriggerUsers = (db) => async (params) => {
	await db.delete(triggerUsers).where(and(agentScopedWhere(triggerUsers, params.scopes), eq(triggerUsers.triggerId, params.triggerId)));
	if (params.userIds.length > 0) await db.insert(triggerUsers).values(params.userIds.map((userId) => ({
		tenantId: params.scopes.tenantId,
		projectId: params.scopes.projectId,
		agentId: params.scopes.agentId,
		triggerId: params.triggerId,
		userId
	})));
};
const getTriggerUserCount = (db) => async (params) => {
	return (await db.select({ count: count() }).from(triggerUsers).where(and(agentScopedWhere(triggerUsers, params.scopes), eq(triggerUsers.triggerId, params.triggerId))))[0]?.count ?? 0;
};
const getWebhookTriggerIdsWithUser = (db) => async (params) => {
	return db.select({
		agentId: triggers.agentId,
		id: triggers.id
	}).from(triggers).innerJoin(triggerUsers, and(eq(triggerUsers.tenantId, triggers.tenantId), eq(triggerUsers.projectId, triggers.projectId), eq(triggerUsers.agentId, triggers.agentId), eq(triggerUsers.triggerId, triggers.id))).where(and(projectScopedWhere(triggers, {
		tenantId: params.tenantId,
		projectId: params.projectId
	}), eq(triggerUsers.userId, params.userId)));
};
const removeUserFromProjectTriggerUsers = (db) => async (params) => {
	await db.transaction(async (tx) => {
		const triggerRows = await getWebhookTriggerIdsWithUser(tx)(params);
		if (triggerRows.length === 0) return;
		const triggerIds = triggerRows.map((row) => row.id);
		await tx.delete(triggerUsers).where(and(projectScopedWhere(triggerUsers, {
			tenantId: params.tenantId,
			projectId: params.projectId
		}), inArray(triggerUsers.triggerId, triggerIds), eq(triggerUsers.userId, params.userId)));
		const triggersWithRemainingUsers = await tx.select({ triggerId: triggerUsers.triggerId }).from(triggerUsers).where(and(projectScopedWhere(triggerUsers, {
			tenantId: params.tenantId,
			projectId: params.projectId
		}), inArray(triggerUsers.triggerId, triggerIds))).groupBy(triggerUsers.triggerId);
		const triggerIdsWithRemainingUsers = new Set(triggersWithRemainingUsers.map((row) => row.triggerId));
		const emptyTriggerIds = triggerIds.filter((id) => !triggerIdsWithRemainingUsers.has(id));
		if (emptyTriggerIds.length > 0) await tx.update(triggers).set({
			enabled: false,
			updatedAt: (/* @__PURE__ */ new Date()).toISOString()
		}).where(and(projectScopedWhere(triggers, {
			tenantId: params.tenantId,
			projectId: params.projectId
		}), inArray(triggers.id, emptyTriggerIds), eq(triggers.enabled, true)));
	});
};
/**
* Upsert a trigger (create or update based on existence)
*/
const upsertTrigger = (db) => async (params) => {
	const { scopes, data } = params;
	if (await db.query.triggers.findFirst({ where: and(agentScopedWhere(triggers, scopes), eq(triggers.id, data.id)) })) {
		const updateData = {
			...data,
			updatedAt: (/* @__PURE__ */ new Date()).toISOString()
		};
		return (await db.update(triggers).set(updateData).where(and(agentScopedWhere(triggers, scopes), eq(triggers.id, data.id))).returning())[0];
	}
	return (await db.insert(triggers).values({
		...data,
		tenantId: scopes.tenantId,
		projectId: scopes.projectId,
		agentId: scopes.agentId
	}).returning())[0];
};

//#endregion
export { createTrigger, createTriggerUser, createTriggerWithUsers, deleteTrigger, deleteTriggerUser, deleteTriggersByRunAsUserId, getTriggerById, getTriggerUserCount, getTriggerUsers, getTriggerUsersBatch, getWebhookTriggerIdsWithUser, listTriggers, listTriggersPaginated, removeUserFromProjectTriggerUsers, setTriggerUsers, updateTrigger, upsertTrigger };