import { subAgentRelations, subAgentToolRelations, subAgents, tools } from "../../db/manage/manage-schema.js";
import { deriveRelationId } from "../../utils/conversations.js";
import { agentScopedWhere, subAgentScopedWhere } from "./scope-helpers.js";
import { and, count, desc, eq, isNotNull } from "drizzle-orm";

//#region src/data-access/manage/subAgentRelations.ts
const getAgentRelationById = (db) => async (params) => {
	return db.query.subAgentRelations.findFirst({ where: and(agentScopedWhere(subAgentRelations, params.scopes), eq(subAgentRelations.id, params.relationId)) });
};
const listAgentRelations = (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(subAgentRelations, params.scopes);
	const [data, totalResult] = await Promise.all([db.select().from(subAgentRelations).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentRelations.createdAt)), db.select({ count: count() }).from(subAgentRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const getAgentRelations = (db) => async (params) => {
	return await db.query.subAgentRelations.findMany({ where: and(agentScopedWhere(subAgentRelations, params.scopes), eq(subAgentRelations.sourceSubAgentId, params.scopes.subAgentId)) });
};
const getAgentRelationsByAgent = (db) => async (params) => {
	return await db.query.subAgentRelations.findMany({ where: agentScopedWhere(subAgentRelations, params.scopes) });
};
const getAgentRelationsBySource = (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(agentScopedWhere(subAgentRelations, params.scopes), eq(subAgentRelations.sourceSubAgentId, params.sourceSubAgentId));
	const [data, totalResult] = await Promise.all([db.select().from(subAgentRelations).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentRelations.createdAt)), db.select({ count: count() }).from(subAgentRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const getSubAgentRelationsByTarget = (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(agentScopedWhere(subAgentRelations, params.scopes), eq(subAgentRelations.targetSubAgentId, params.targetSubAgentId));
	const [data, totalResult] = await Promise.all([db.select().from(subAgentRelations).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentRelations.createdAt)), db.select({ count: count() }).from(subAgentRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const getRelatedAgentsForAgent = (db) => async (params) => {
	return { data: await db.select({
		id: subAgents.id,
		name: subAgents.name,
		description: subAgents.description,
		relationType: subAgentRelations.relationType,
		relationId: subAgentRelations.id
	}).from(subAgentRelations).innerJoin(subAgents, and(eq(subAgentRelations.targetSubAgentId, subAgents.id), eq(subAgentRelations.tenantId, subAgents.tenantId), eq(subAgentRelations.projectId, subAgents.projectId), eq(subAgentRelations.agentId, subAgents.agentId))).where(and(agentScopedWhere(subAgentRelations, params.scopes), eq(subAgentRelations.sourceSubAgentId, params.subAgentId), isNotNull(subAgentRelations.targetSubAgentId))) };
};
const createSubAgentRelation = (db) => async (params) => {
	const count$1 = [
		params.targetSubAgentId != null,
		params.externalSubAgentId != null,
		params.teamSubAgentId != null
	].filter(Boolean).length;
	if (count$1 > 1) throw new Error("Cannot specify more than one of targetSubAgentId, externalSubAgentId, or teamSubAgentId");
	if (count$1 === 0) throw new Error("Must specify exactly one of targetSubAgentId, externalSubAgentId, or teamSubAgentId");
	return (await db.insert(subAgentRelations).values({ ...params }).returning())[0];
};
/**
* Check if sub-agent relation exists by agent, source, target, and relation type
*/
const getAgentRelationByParams = (db) => async (params) => {
	const whereConditions = [
		agentScopedWhere(subAgentRelations, params.scopes),
		eq(subAgentRelations.sourceSubAgentId, params.sourceSubAgentId),
		eq(subAgentRelations.relationType, params.relationType)
	];
	if (params.targetSubAgentId) whereConditions.push(eq(subAgentRelations.targetSubAgentId, params.targetSubAgentId));
	return db.query.subAgentRelations.findFirst({ where: and(...whereConditions) });
};
/**
* Upsert agent relation (create if it doesn't exist, no-op if it does)
*/
const upsertSubAgentRelation = (db) => async (params) => {
	const existing = await getAgentRelationByParams(db)({
		scopes: {
			tenantId: params.tenantId,
			projectId: params.projectId,
			agentId: params.agentId
		},
		sourceSubAgentId: params.sourceSubAgentId,
		targetSubAgentId: params.targetSubAgentId,
		relationType: params.relationType ?? ""
	});
	if (!existing) return await createSubAgentRelation(db)(params);
	return existing;
};
const updateAgentRelation = (db) => async (params) => {
	const updateData = {
		...params.data,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	};
	return (await db.update(subAgentRelations).set(updateData).where(and(agentScopedWhere(subAgentRelations, params.scopes), eq(subAgentRelations.id, params.relationId))).returning())[0];
};
const deleteSubAgentRelation = (db) => async (params) => {
	return (await db.delete(subAgentRelations).where(and(agentScopedWhere(subAgentRelations, params.scopes), eq(subAgentRelations.id, params.relationId))).returning()).length > 0;
};
const deleteAgentRelationsByAgent = (db) => async (params) => {
	return (await db.delete(subAgentRelations).where(agentScopedWhere(subAgentRelations, params.scopes)).returning()).length > 0;
};
const createAgentToolRelation = (db) => async (params) => {
	const finalRelationId = params.relationId ?? deriveRelationId(params.scopes.tenantId, params.scopes.projectId, params.scopes.agentId, params.data.subAgentId, params.data.toolId);
	return (await db.insert(subAgentToolRelations).values({
		id: finalRelationId,
		...params.scopes,
		subAgentId: params.data.subAgentId,
		toolId: params.data.toolId,
		selectedTools: params.data.selectedTools,
		headers: params.data.headers,
		toolPolicies: params.data.toolPolicies
	}).returning())[0];
};
const updateAgentToolRelation = (db) => async (params) => {
	const updateData = {
		...params.data,
		updatedAt: (/* @__PURE__ */ new Date()).toISOString()
	};
	return (await db.update(subAgentToolRelations).set(updateData).where(and(agentScopedWhere(subAgentToolRelations, params.scopes), eq(subAgentToolRelations.id, params.relationId))).returning())[0];
};
const deleteAgentToolRelation = (db) => async (params) => {
	return (await db.delete(subAgentToolRelations).where(and(agentScopedWhere(subAgentToolRelations, params.scopes), eq(subAgentToolRelations.id, params.relationId))).returning()).length > 0;
};
const deleteAgentToolRelationByAgent = (db) => async (params) => {
	return (await db.delete(subAgentToolRelations).where(subAgentScopedWhere(subAgentToolRelations, params.scopes)).returning()).length > 0;
};
const getAgentToolRelationById = (db) => async (params) => {
	return await db.query.subAgentToolRelations.findFirst({ where: and(agentScopedWhere(subAgentToolRelations, params.scopes), eq(subAgentToolRelations.id, params.relationId)) });
};
const getAgentToolRelationByAgent = (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 = subAgentScopedWhere(subAgentToolRelations, params.scopes);
	const [data, totalResult] = await Promise.all([db.select().from(subAgentToolRelations).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentToolRelations.createdAt)), db.select({ count: count() }).from(subAgentToolRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const getAgentToolRelationByTool = (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(agentScopedWhere(subAgentToolRelations, params.scopes), eq(subAgentToolRelations.toolId, params.toolId));
	const [data, totalResult] = await Promise.all([db.select().from(subAgentToolRelations).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentToolRelations.createdAt)), db.select({ count: count() }).from(subAgentToolRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const listAgentToolRelations = (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(subAgentToolRelations, params.scopes);
	const [data, totalResult] = await Promise.all([db.select().from(subAgentToolRelations).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentToolRelations.createdAt)), db.select({ count: count() }).from(subAgentToolRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const getToolsForAgent = (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 = subAgentScopedWhere(subAgentToolRelations, params.scopes);
	const [data, totalResult] = await Promise.all([db.select({
		id: subAgentToolRelations.id,
		tenantId: subAgentToolRelations.tenantId,
		subAgentId: subAgentToolRelations.subAgentId,
		toolId: subAgentToolRelations.toolId,
		selectedTools: subAgentToolRelations.selectedTools,
		headers: subAgentToolRelations.headers,
		toolPolicies: subAgentToolRelations.toolPolicies,
		createdAt: subAgentToolRelations.createdAt,
		updatedAt: subAgentToolRelations.updatedAt,
		tool: {
			id: tools.id,
			name: tools.name,
			description: tools.description,
			config: tools.config,
			createdAt: tools.createdAt,
			updatedAt: tools.updatedAt,
			capabilities: tools.capabilities,
			lastError: tools.lastError,
			credentialReferenceId: tools.credentialReferenceId,
			credentialScope: tools.credentialScope,
			tenantId: tools.tenantId,
			projectId: tools.projectId,
			headers: tools.headers,
			imageUrl: tools.imageUrl
		}
	}).from(subAgentToolRelations).innerJoin(tools, and(eq(subAgentToolRelations.tenantId, tools.tenantId), eq(subAgentToolRelations.projectId, tools.projectId), eq(subAgentToolRelations.toolId, tools.id))).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentToolRelations.createdAt)), db.select({ count: count() }).from(subAgentToolRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const getAgentsForTool = (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(agentScopedWhere(subAgentToolRelations, params.scopes), eq(subAgentToolRelations.toolId, params.toolId));
	const [data, totalResult] = await Promise.all([db.select({
		id: subAgentToolRelations.id,
		tenantId: subAgentToolRelations.tenantId,
		subAgentId: subAgentToolRelations.subAgentId,
		toolId: subAgentToolRelations.toolId,
		selectedTools: subAgentToolRelations.selectedTools,
		headers: subAgentToolRelations.headers,
		toolPolicies: subAgentToolRelations.toolPolicies,
		createdAt: subAgentToolRelations.createdAt,
		updatedAt: subAgentToolRelations.updatedAt,
		subAgent: {
			id: subAgents.id,
			name: subAgents.name,
			description: subAgents.description,
			prompt: subAgents.prompt,
			conversationHistoryConfig: subAgents.conversationHistoryConfig,
			models: subAgents.models,
			stopWhen: subAgents.stopWhen,
			createdAt: subAgents.createdAt,
			updatedAt: subAgents.updatedAt
		}
	}).from(subAgentToolRelations).innerJoin(subAgents, and(eq(subAgentToolRelations.subAgentId, subAgents.id), eq(subAgentToolRelations.tenantId, subAgents.tenantId), eq(subAgentToolRelations.projectId, subAgents.projectId), eq(subAgentToolRelations.agentId, subAgents.agentId))).where(whereClause).limit(limit).offset(offset).orderBy(desc(subAgentToolRelations.createdAt)), db.select({ count: count() }).from(subAgentToolRelations).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	return {
		data,
		pagination: {
			page,
			limit,
			total,
			pages: Math.ceil(total / limit)
		}
	};
};
const validateSubAgent = (db) => async (params) => {
	return (await db.select({ id: subAgents.id }).from(subAgents).where(and(agentScopedWhere(subAgents, params.scopes), eq(subAgents.id, params.scopes.subAgentId))).limit(1)).length > 0;
};

//#endregion
export { createAgentToolRelation, createSubAgentRelation, deleteAgentRelationsByAgent, deleteAgentToolRelation, deleteAgentToolRelationByAgent, deleteSubAgentRelation, getAgentRelationById, getAgentRelationByParams, getAgentRelations, getAgentRelationsByAgent, getAgentRelationsBySource, getAgentToolRelationByAgent, getAgentToolRelationById, getAgentToolRelationByTool, getAgentsForTool, getRelatedAgentsForAgent, getSubAgentRelationsByTarget, getToolsForAgent, listAgentRelations, listAgentToolRelations, updateAgentRelation, updateAgentToolRelation, upsertSubAgentRelation, validateSubAgent };