import { artifactComponents, subAgentArtifactComponents, subAgentRelations, subAgents } from "../../db/manage/manage-schema.js";
import { validatePropsAsJsonSchema } from "../../validation/props-validation.js";
import { validateRender } from "../../validation/render-validation.js";
import { generateId } from "../../utils/conversations.js";
import { agentScopedWhere, projectScopedWhere, subAgentScopedWhere } from "./scope-helpers.js";
import { and, count, desc, eq } from "drizzle-orm";

//#region src/data-access/manage/artifactComponents.ts
const getArtifactComponentById = (db) => async (params) => {
	return await db.query.artifactComponents.findFirst({ where: and(projectScopedWhere(artifactComponents, params.scopes), eq(artifactComponents.id, params.id)) });
};
const listArtifactComponents = (db) => async (params) => {
	return await db.select().from(artifactComponents).where(projectScopedWhere(artifactComponents, params.scopes)).orderBy(desc(artifactComponents.createdAt));
};
const listArtifactComponentsPaginated = (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 = projectScopedWhere(artifactComponents, params.scopes);
	const [data, totalResult] = await Promise.all([db.select().from(artifactComponents).where(whereClause).limit(limit).offset(offset).orderBy(desc(artifactComponents.createdAt)), db.select({ count: count() }).from(artifactComponents).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	const totalNumber = typeof total === "string" ? Number.parseInt(total, 10) : total;
	return {
		data,
		pagination: {
			page,
			limit,
			total: totalNumber,
			pages: Math.ceil(totalNumber / limit)
		}
	};
};
const createArtifactComponent = (db) => async (params) => {
	if (params.props !== null && params.props !== void 0) {
		const propsValidation = validatePropsAsJsonSchema(params.props);
		if (!propsValidation.isValid) {
			const errorMessages = propsValidation.errors.map((e) => `${e.field}: ${e.message}`).join(", ");
			throw new Error(`Invalid props schema: ${errorMessages}`);
		}
	}
	if (params.render !== void 0 && params.render !== null) {
		if (typeof params.render === "object" && params.render !== null && "component" in params.render && "mockData" in params.render) {
			const renderValidation = validateRender(params.render);
			if (!renderValidation.isValid) {
				const errorMessages = renderValidation.errors.map((e) => `${e.field}: ${e.message}`).join(", ");
				throw new Error(`Invalid render: ${errorMessages}`);
			}
		}
	}
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [artifactComponent] = await db.insert(artifactComponents).values({
		...params,
		createdAt: now,
		updatedAt: now
	}).returning();
	return artifactComponent;
};
const updateArtifactComponent = (db) => async (params) => {
	if (params.data.props !== void 0 && params.data.props !== null) {
		const propsValidation = validatePropsAsJsonSchema(params.data.props);
		if (!propsValidation.isValid) {
			const errorMessages = propsValidation.errors.map((e) => `${e.field}: ${e.message}`).join(", ");
			throw new Error(`Invalid props schema: ${errorMessages}`);
		}
	}
	if (params.data.render !== void 0 && params.data.render !== null) {
		if (typeof params.data.render === "object" && params.data.render !== null && "component" in params.data.render && "mockData" in params.data.render) {
			const renderValidation = validateRender(params.data.render);
			if (!renderValidation.isValid) {
				const errorMessages = renderValidation.errors.map((e) => `${e.field}: ${e.message}`).join(", ");
				throw new Error(`Invalid render: ${errorMessages}`);
			}
		}
	}
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [updated] = await db.update(artifactComponents).set({
		...params.data,
		updatedAt: now
	}).where(and(projectScopedWhere(artifactComponents, params.scopes), eq(artifactComponents.id, params.id))).returning();
	return updated;
};
const deleteArtifactComponent = (db) => async (params) => {
	try {
		return (await db.delete(artifactComponents).where(and(projectScopedWhere(artifactComponents, params.scopes), eq(artifactComponents.id, params.id))).returning()).length > 0;
	} catch (error) {
		console.error("Error deleting artifact component:", error);
		return false;
	}
};
const getArtifactComponentsForAgent = (db) => async (params) => {
	return await db.select({
		id: artifactComponents.id,
		tenantId: artifactComponents.tenantId,
		projectId: artifactComponents.projectId,
		name: artifactComponents.name,
		description: artifactComponents.description,
		props: artifactComponents.props,
		render: artifactComponents.render,
		createdAt: artifactComponents.createdAt,
		updatedAt: artifactComponents.updatedAt
	}).from(artifactComponents).innerJoin(subAgentArtifactComponents, and(eq(artifactComponents.id, subAgentArtifactComponents.artifactComponentId), eq(artifactComponents.tenantId, subAgentArtifactComponents.tenantId), eq(artifactComponents.projectId, subAgentArtifactComponents.projectId))).where(and(projectScopedWhere(artifactComponents, params.scopes), eq(subAgentArtifactComponents.agentId, params.scopes.agentId), eq(subAgentArtifactComponents.subAgentId, params.scopes.subAgentId))).orderBy(desc(artifactComponents.createdAt));
};
const associateArtifactComponentWithAgent = (db) => async (params) => {
	const [association] = await db.insert(subAgentArtifactComponents).values({
		id: generateId(),
		tenantId: params.scopes.tenantId,
		projectId: params.scopes.projectId,
		agentId: params.scopes.agentId,
		subAgentId: params.scopes.subAgentId,
		artifactComponentId: params.artifactComponentId,
		createdAt: (/* @__PURE__ */ new Date()).toISOString()
	}).returning();
	return association;
};
const removeArtifactComponentFromAgent = (db) => async (params) => {
	try {
		return (await db.delete(subAgentArtifactComponents).where(and(subAgentScopedWhere(subAgentArtifactComponents, params.scopes), eq(subAgentArtifactComponents.artifactComponentId, params.artifactComponentId))).returning()).length > 0;
	} catch (error) {
		console.error("Error removing artifact component from agent:", error);
		return false;
	}
};
const deleteAgentArtifactComponentRelationByAgent = (db) => async (params) => {
	return (await db.delete(subAgentArtifactComponents).where(subAgentScopedWhere(subAgentArtifactComponents, params.scopes)).returning()).length > 0;
};
const getAgentsUsingArtifactComponent = (db) => async (params) => {
	return await db.select({
		agentId: subAgentArtifactComponents.agentId,
		subAgentId: subAgentArtifactComponents.subAgentId,
		createdAt: subAgentArtifactComponents.createdAt
	}).from(subAgentArtifactComponents).where(and(projectScopedWhere(subAgentArtifactComponents, params.scopes), eq(subAgentArtifactComponents.artifactComponentId, params.artifactComponentId))).orderBy(desc(subAgentArtifactComponents.createdAt));
};
const isArtifactComponentAssociatedWithAgent = (db) => async (params) => {
	return (await db.select({ id: subAgentArtifactComponents.id }).from(subAgentArtifactComponents).where(and(subAgentScopedWhere(subAgentArtifactComponents, params.scopes), eq(subAgentArtifactComponents.artifactComponentId, params.artifactComponentId))).limit(1)).length > 0;
};
const agentHasArtifactComponents = (db) => async (params) => {
	const total = (await db.select({ count: count() }).from(subAgentArtifactComponents).innerJoin(subAgents, and(eq(subAgentArtifactComponents.subAgentId, subAgents.id), eq(subAgentArtifactComponents.tenantId, subAgents.tenantId), eq(subAgentArtifactComponents.projectId, subAgents.projectId), eq(subAgentArtifactComponents.agentId, subAgents.agentId))).innerJoin(subAgentRelations, and(eq(subAgents.id, subAgentRelations.sourceSubAgentId), eq(subAgents.tenantId, subAgentRelations.tenantId), eq(subAgents.projectId, subAgentRelations.projectId), eq(subAgents.agentId, subAgentRelations.agentId))).where(agentScopedWhere(subAgentArtifactComponents, params.scopes)).limit(1))[0]?.count || 0;
	return (typeof total === "string" ? Number.parseInt(total, 10) : total) > 0;
};
const countArtifactComponents = (db) => async (params) => {
	const total = (await db.select({ count: count() }).from(artifactComponents).where(projectScopedWhere(artifactComponents, params.scopes)))[0]?.count || 0;
	return typeof total === "string" ? Number.parseInt(total, 10) : total;
};
const countArtifactComponentsForAgent = (db) => async (params) => {
	const total = (await db.select({ count: count() }).from(subAgentArtifactComponents).where(subAgentScopedWhere(subAgentArtifactComponents, params.scopes)))[0]?.count || 0;
	return typeof total === "string" ? Number.parseInt(total, 10) : total;
};
/**
* Upsert agent-artifact component relation (create if it doesn't exist, no-op if it does)
*/
const upsertAgentArtifactComponentRelation = (db) => async (params) => {
	if (!await isArtifactComponentAssociatedWithAgent(db)(params)) return await associateArtifactComponentWithAgent(db)(params);
	return null;
};
/**
* Upsert an artifact component (create if it doesn't exist, update if it does)
*/
const upsertArtifactComponent = (db) => async (params) => {
	const scopes = {
		tenantId: params.data.tenantId,
		projectId: params.data.projectId
	};
	if (await getArtifactComponentById(db)({
		scopes,
		id: params.data.id
	})) return await updateArtifactComponent(db)({
		scopes,
		id: params.data.id,
		data: {
			name: params.data.name,
			description: params.data.description,
			props: params.data.props,
			render: params.data.render
		}
	});
	return await createArtifactComponent(db)(params.data);
};

//#endregion
export { agentHasArtifactComponents, associateArtifactComponentWithAgent, countArtifactComponents, countArtifactComponentsForAgent, createArtifactComponent, deleteAgentArtifactComponentRelationByAgent, deleteArtifactComponent, getAgentsUsingArtifactComponent, getArtifactComponentById, getArtifactComponentsForAgent, isArtifactComponentAssociatedWithAgent, listArtifactComponents, listArtifactComponentsPaginated, removeArtifactComponentFromAgent, updateArtifactComponent, upsertAgentArtifactComponentRelation, upsertArtifactComponent };