import { getLogger } from "../../utils/logger.js";
import { deleteExternalAgent, listExternalAgents, upsertExternalAgent } from "./externalAgents.js";
import { deleteFunction, listFunctions, upsertFunction } from "./functions.js";
import { listSkillsWithFiles, upsertSkill } from "./skills.js";
import { deleteCredentialReference, listCredentialReferences, upsertCredentialReference } from "./credentialReferences.js";
import { deleteTool, listTools, upsertTool } from "./tools.js";
import { listAgents } from "./agents.js";
import { deleteArtifactComponent, listArtifactComponents, upsertArtifactComponent } from "./artifactComponents.js";
import { deleteDataComponent, listDataComponents, upsertDataComponent } from "./dataComponents.js";
import { createFullAgentServerSide, deleteFullAgent, getFullAgent, getFullAgentWithRelationIds, updateFullAgentServerSide } from "./agentFull.js";
import { createProject, deleteProject, getProject, updateProject } from "./projects.js";

//#region src/data-access/manage/projectFull.ts
const logger = getLogger("projectFull");
/**
* Validate and type the project data
*/
function validateAndTypeProjectData(projectData) {
	return projectData;
}
/**
* Server-side implementation of createFullProject that performs actual database operations.
* This function creates a complete project with all agent and their nested resources.
*/
const createFullProjectServerSide = (db) => async (params) => {
	const { scopes, projectData } = params;
	const { tenantId } = scopes;
	const typed = validateAndTypeProjectData(projectData);
	logger.info({
		tenantId,
		projectId: typed.id,
		agentCount: Object.keys(typed.agents || {}).length
	}, "Creating full project in database");
	try {
		const projectPayload = {
			id: typed.id,
			name: typed.name,
			description: typed.description || "",
			models: typed.models,
			stopWhen: typed.stopWhen,
			tenantId
		};
		logger.info({ projectId: typed.id }, "Creating project metadata");
		await createProject(db)(projectPayload);
		logger.info({ projectId: typed.id }, "Project metadata created successfully");
		if (typed.skills && Object.keys(typed.skills).length) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.skills).length
			}, "Creating project skills");
			for (const [skillId, skill] of Object.entries(typed.skills)) try {
				await upsertSkill(db)({
					...skill,
					tenantId,
					projectId: typed.id
				});
				logger.info({
					projectId: typed.id,
					skillId
				}, "Skill processed");
			} catch (error) {
				logger.error({
					projectId: typed.id,
					skillId,
					error
				}, "Failed to create skill");
				throw error;
			}
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.skills).length
			}, "All project skills created successfully");
		}
		if (typed.credentialReferences && Object.keys(typed.credentialReferences).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.credentialReferences).length
			}, "Creating project credentialReferences");
			const credentialPromises = Object.entries(typed.credentialReferences).map(async ([_credId, credData]) => {
				try {
					logger.info({
						projectId: typed.id,
						credId: credData.id
					}, "Creating credentialReference in project");
					await upsertCredentialReference(db)({ data: {
						...credData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						credId: credData.id
					}, "CredentialReference created successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						credId: credData.id,
						error
					}, "Failed to create credentialReference in project");
					throw error;
				}
			});
			await Promise.all(credentialPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.credentialReferences).length
			}, "All project credentialReferences created successfully");
		}
		if (typed.functions && Object.keys(typed.functions).length > 0) {
			const functionPromises = Object.entries(typed.functions).map(async ([functionId, functionData]) => {
				try {
					logger.info({
						projectId: typed.id,
						functionId
					}, "Creating project function");
					await upsertFunction(db)({
						data: { ...functionData },
						scopes: {
							tenantId,
							projectId: typed.id
						}
					});
					logger.info({
						projectId: typed.id,
						functionId
					}, "Project function created successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						functionId,
						error
					}, "Failed to create global function");
					throw error;
				}
			});
			await Promise.all(functionPromises);
			logger.info({
				projectId: typed.id,
				functionCount: Object.keys(typed.functions).length
			}, "All project functions created successfully");
		}
		if (typed.tools && Object.keys(typed.tools).length > 0) {
			logger.info({
				projectId: typed.id,
				toolCount: Object.keys(typed.tools).length
			}, "Creating project tools");
			const toolPromises = Object.entries(typed.tools).map(async ([toolId, toolData]) => {
				try {
					logger.info({
						projectId: typed.id,
						toolId
					}, "Creating tool in project");
					await upsertTool(db)({ data: {
						tenantId,
						projectId: typed.id,
						...toolData
					} });
					logger.info({
						projectId: typed.id,
						toolId
					}, "Tool created successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						toolId,
						error
					}, "Failed to create tool in project");
					throw error;
				}
			});
			await Promise.all(toolPromises);
			logger.info({
				projectId: typed.id,
				toolCount: Object.keys(typed.tools).length
			}, "All project tools created successfully");
		}
		if (typed.externalAgents && Object.keys(typed.externalAgents).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.externalAgents).length
			}, "Creating project externalAgents");
			const externalAgentPromises = Object.entries(typed.externalAgents).map(async ([externalAgentId, externalAgentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						externalAgentId
					}, "Creating externalAgent in project");
					await upsertExternalAgent(db)({ data: {
						...externalAgentData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						externalAgentId
					}, "ExternalAgent created successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						externalAgentId,
						error
					}, "Failed to create externalAgent in project");
					throw error;
				}
			});
			await Promise.all(externalAgentPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.externalAgents).length
			}, "All project externalAgents created successfully");
		}
		if (typed.dataComponents && Object.keys(typed.dataComponents).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.dataComponents).length
			}, "Creating project dataComponents");
			const dataComponentPromises = Object.entries(typed.dataComponents).map(async ([componentId, componentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						componentId
					}, "Creating dataComponent in project");
					await upsertDataComponent(db)({ data: {
						...componentData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						componentId
					}, "DataComponent created successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						componentId,
						error
					}, "Failed to create dataComponent in project");
					throw error;
				}
			});
			await Promise.all(dataComponentPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.dataComponents).length
			}, "All project dataComponents created successfully");
		}
		if (typed.artifactComponents && Object.keys(typed.artifactComponents).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.artifactComponents).length
			}, "Creating project artifactComponents");
			const artifactComponentPromises = Object.entries(typed.artifactComponents).map(async ([componentId, componentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						componentId
					}, "Creating artifactComponent in project");
					await upsertArtifactComponent(db)({ data: {
						...componentData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						componentId
					}, "ArtifactComponent created successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						componentId,
						error
					}, "Failed to create artifactComponent in project");
					throw error;
				}
			});
			await Promise.all(artifactComponentPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.artifactComponents).length
			}, "All project artifactComponents created successfully");
		}
		if (typed.agents && Object.keys(typed.agents).length > 0) {
			logger.info({
				projectId: typed.id,
				agentCount: Object.keys(typed.agents).length
			}, "Creating project agent");
			logger.info({
				projectId: typed.id,
				agentCount: Object.keys(typed.agents).length
			}, "Phase 1: Creating agents without sub-agents");
			const agentPromises = Object.entries(typed.agents).map(async ([agentId, agentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						agentId
					}, "Creating agent in project (phase 1)");
					const agentDataWithoutSubAgents = {
						...agentData,
						subAgents: {},
						defaultSubAgentId: void 0,
						tools: typed.tools || {},
						functions: typed.functions || {},
						dataComponents: typed.dataComponents || {},
						artifactComponents: typed.artifactComponents || {},
						externalAgents: typed.externalAgents || {},
						credentialReferences: typed.credentialReferences || {},
						statusUpdates: agentData.statusUpdates === null ? void 0 : agentData.statusUpdates
					};
					await createFullAgentServerSide(db)({
						tenantId,
						projectId: typed.id
					}, agentDataWithoutSubAgents);
					logger.info({
						projectId: typed.id,
						agentId
					}, "Agent created successfully in project (phase 1)");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						agentId,
						error
					}, "Failed to create agent in project (phase 1)");
					throw error;
				}
			});
			const phase1Errors = (await Promise.allSettled(agentPromises)).filter((r) => r.status === "rejected").map((r) => r.reason);
			if (phase1Errors.length > 0) {
				logger.error({
					projectId: typed.id,
					errorCount: phase1Errors.length
				}, `Some agents failed to create in phase 1: ${phase1Errors.join(", ")}`);
				throw phase1Errors[0];
			}
			logger.info({
				projectId: typed.id,
				agentCount: Object.keys(typed.agents).length
			}, "Phase 1 complete: All agents created without sub-agents");
			logger.info({
				projectId: typed.id,
				agentCount: Object.keys(typed.agents).length
			}, "Phase 2: Adding sub-agents with relationships");
			const updatePromises = Object.entries(typed.agents).filter(([_, agentData]) => Object.keys(agentData.subAgents).length > 0).map(async ([agentId, agentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						agentId
					}, "Adding sub-agents (phase 2)");
					const updateData = {
						...agentData,
						subAgents: agentData.subAgents
					};
					await updateFullAgentServerSide(db)({
						tenantId,
						projectId: typed.id
					}, updateData);
					logger.info({
						projectId: typed.id,
						agentId
					}, "Sub-agents added successfully (phase 2)");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						agentId,
						error
					}, "Failed to add sub-agents (phase 2)");
					throw error;
				}
			});
			const phase2Errors = (await Promise.allSettled(updatePromises)).filter((r) => r.status === "rejected").map((r) => r.reason);
			if (phase2Errors.length > 0) {
				logger.error({
					projectId: typed.id,
					errorCount: phase2Errors.length
				}, `Some agents failed to add sub-agents in phase 2: ${phase2Errors.join(", ")}`);
				throw phase2Errors[0];
			}
			logger.info({
				projectId: typed.id,
				agentCount: Object.keys(typed.agents).length
			}, "Phase 2 complete: All sub-agents added successfully");
		}
		logger.info({ projectId: typed.id }, "Full project created successfully");
		const fullProject = await getFullProject(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		if (!fullProject) throw new Error(`Failed to retrieve created project ${typed.id}`);
		return fullProject;
	} catch (error) {
		logger.error({
			tenantId,
			projectId: typed.id,
			error
		}, "Failed to create full project");
		throw error;
	}
};
/**
* Server-side implementation of updateFullProject that performs actual database operations.
* This function updates a complete project with all agent and their nested resources.
*/
const updateFullProjectServerSide = (db) => async (params) => {
	const { scopes, projectData } = params;
	const { tenantId } = scopes;
	const typed = validateAndTypeProjectData(projectData);
	if (!typed.id) throw new Error("Project ID is required");
	logger.info({
		tenantId,
		projectId: typed.id,
		agentCount: Object.keys(typed.agents || {}).length
	}, "Updating full project in database");
	try {
		if (!await getProject(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} })) {
			logger.info({ projectId: typed.id }, "Project not found, creating new project");
			return await createFullProjectServerSide(db)({
				scopes: {
					tenantId,
					projectId: typed.id
				},
				projectData
			});
		}
		const projectUpdatePayload = {
			name: typed.name,
			description: typed.description || "",
			models: typed.models,
			stopWhen: typed.stopWhen
		};
		logger.info({ projectId: typed.id }, "Updating project metadata");
		await updateProject(db)({
			scopes: {
				tenantId,
				projectId: typed.id
			},
			data: projectUpdatePayload
		});
		logger.info({ projectId: typed.id }, "Project metadata updated successfully");
		if (typed.skills && Object.keys(typed.skills).length) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.skills).length
			}, "Updating project skills");
			for (const [skillId, skill] of Object.entries(typed.skills)) try {
				await upsertSkill(db)({
					...skill,
					tenantId,
					projectId: typed.id
				});
				logger.info({
					projectId: typed.id,
					skillId
				}, "Skill processed");
			} catch (error) {
				logger.error({
					projectId: typed.id,
					skillId,
					error
				}, "Failed to update skill");
				throw error;
			}
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.skills).length
			}, "All project skills updated successfully");
		}
		if (typed.credentialReferences && Object.keys(typed.credentialReferences).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.credentialReferences).length
			}, "Updating project credentialReferences");
			const credentialPromises = Object.entries(typed.credentialReferences).map(async ([_credId, credData]) => {
				try {
					logger.info({
						projectId: typed.id,
						credId: credData.id
					}, "Updating credentialReference in project");
					await upsertCredentialReference(db)({ data: {
						...credData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						credId: credData.id
					}, "CredentialReference updated successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						credId: credData.id,
						error
					}, "Failed to update credentialReference in project");
					throw error;
				}
			});
			await Promise.all(credentialPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.credentialReferences).length
			}, "All project credentialReferences updated successfully");
		}
		if (typed.functions && Object.keys(typed.functions).length > 0) {
			logger.info({
				projectId: typed.id,
				functionCount: Object.keys(typed.functions).length
			}, "Updating project functions");
			const functionPromises = Object.entries(typed.functions).map(async ([functionId, functionData]) => {
				try {
					logger.info({
						projectId: typed.id,
						functionId
					}, "Updating project function");
					await upsertFunction(db)({
						data: { ...functionData },
						scopes: {
							tenantId,
							projectId: typed.id
						}
					});
					logger.info({
						projectId: typed.id,
						functionId
					}, "Project function updated successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						functionId,
						error
					}, "Failed to update global function");
					throw error;
				}
			});
			await Promise.all(functionPromises);
			logger.info({
				projectId: typed.id,
				functionCount: Object.keys(typed.functions).length
			}, "All project functions updated successfully");
		}
		if (typed.tools && Object.keys(typed.tools).length > 0) {
			logger.info({
				projectId: typed.id,
				toolCount: Object.keys(typed.tools).length
			}, "Updating project tools");
			const toolPromises = Object.entries(typed.tools).map(async ([toolId, toolData]) => {
				try {
					logger.info({
						projectId: typed.id,
						toolId
					}, "Updating tool in project");
					await upsertTool(db)({ data: {
						tenantId,
						projectId: typed.id,
						...toolData
					} });
					logger.info({
						projectId: typed.id,
						toolId
					}, "Tool updated successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						toolId,
						error
					}, "Failed to update tool in project");
					throw error;
				}
			});
			await Promise.all(toolPromises);
			logger.info({
				projectId: typed.id,
				toolCount: Object.keys(typed.tools).length
			}, "All project tools updated successfully");
		}
		if (typed.externalAgents && Object.keys(typed.externalAgents).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.externalAgents).length
			}, "Updating project externalAgents");
			const externalAgentPromises = Object.entries(typed.externalAgents).map(async ([externalAgentId, externalAgentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						externalAgentId
					}, "Updating externalAgent in project");
					await upsertExternalAgent(db)({ data: {
						...externalAgentData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						externalAgentId
					}, "ExternalAgent updated successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						externalAgentId,
						error
					}, "Failed to update externalAgent in project");
					throw error;
				}
			});
			await Promise.all(externalAgentPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.externalAgents).length
			}, "All project externalAgents updated successfully");
		}
		if (typed.dataComponents && Object.keys(typed.dataComponents).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.dataComponents).length
			}, "Updating project dataComponents");
			const dataComponentPromises = Object.entries(typed.dataComponents).map(async ([componentId, componentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						componentId
					}, "Updating dataComponent in project");
					await upsertDataComponent(db)({ data: {
						...componentData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						componentId
					}, "DataComponent updated successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						componentId,
						error
					}, "Failed to update dataComponent in project");
					throw error;
				}
			});
			await Promise.all(dataComponentPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.dataComponents).length
			}, "All project dataComponents updated successfully");
		}
		if (typed.artifactComponents && Object.keys(typed.artifactComponents).length > 0) {
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.artifactComponents).length
			}, "Updating project artifactComponents");
			const artifactComponentPromises = Object.entries(typed.artifactComponents).map(async ([componentId, componentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						componentId
					}, "Updating artifactComponent in project");
					await upsertArtifactComponent(db)({ data: {
						...componentData,
						tenantId,
						projectId: typed.id
					} });
					logger.info({
						projectId: typed.id,
						componentId
					}, "ArtifactComponent updated successfully");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						componentId,
						error
					}, "Failed to update artifactComponent in project");
					throw error;
				}
			});
			await Promise.all(artifactComponentPromises);
			logger.info({
				projectId: typed.id,
				count: Object.keys(typed.artifactComponents).length
			}, "All project artifactComponents updated successfully");
		}
		const incomingToolIds = new Set(Object.keys(typed.tools || {}));
		const existingTools = (await listTools(db)({
			scopes: {
				tenantId,
				projectId: typed.id
			},
			pagination: {
				page: 1,
				limit: 1e3
			}
		})).data;
		let deletedToolCount = 0;
		for (const tool of existingTools) if (!incomingToolIds.has(tool.id)) try {
			await deleteTool(db)({
				toolId: tool.id,
				scopes: {
					tenantId,
					projectId: typed.id
				}
			});
			deletedToolCount++;
			logger.info({ toolId: tool.id }, "Deleted orphaned tool from project");
		} catch (error) {
			logger.error({
				toolId: tool.id,
				error
			}, "Failed to delete orphaned tool from project");
		}
		if (deletedToolCount > 0) logger.info({
			deletedToolCount,
			projectId: typed.id
		}, "Deleted orphaned tools from project");
		const incomingFunctionIds = new Set(Object.keys(typed.functions || {}));
		const existingFunctions = await listFunctions(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		let deletedFunctionCount = 0;
		for (const func of existingFunctions) if (!incomingFunctionIds.has(func.id)) try {
			await deleteFunction(db)({
				functionId: func.id,
				scopes: {
					tenantId,
					projectId: typed.id
				}
			});
			deletedFunctionCount++;
			logger.info({ functionId: func.id }, "Deleted orphaned function from project");
		} catch (error) {
			logger.error({
				functionId: func.id,
				error
			}, "Failed to delete orphaned function from project");
		}
		if (deletedFunctionCount > 0) logger.info({
			deletedFunctionCount,
			projectId: typed.id
		}, "Deleted orphaned functions from project");
		const incomingCredentialReferenceIds = new Set(Object.keys(typed.credentialReferences || {}));
		const existingCredentialReferences = await listCredentialReferences(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		let deletedCredentialReferenceCount = 0;
		for (const credRef of existingCredentialReferences) if (!incomingCredentialReferenceIds.has(credRef.id)) try {
			await deleteCredentialReference(db)({
				id: credRef.id,
				scopes: {
					tenantId,
					projectId: typed.id
				}
			});
			deletedCredentialReferenceCount++;
			logger.info({ credentialReferenceId: credRef.id }, "Deleted orphaned credentialReference from project");
		} catch (error) {
			logger.error({
				credentialReferenceId: credRef.id,
				error
			}, "Failed to delete orphaned credentialReference from project");
		}
		if (deletedCredentialReferenceCount > 0) logger.info({
			deletedCredentialReferenceCount,
			projectId: typed.id
		}, "Deleted orphaned credentialReferences from project");
		const incomingExternalAgentIds = new Set(Object.keys(typed.externalAgents || {}));
		const existingExternalAgents = await listExternalAgents(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		let deletedExternalAgentCount = 0;
		for (const extAgent of existingExternalAgents) if (!incomingExternalAgentIds.has(extAgent.id)) try {
			await deleteExternalAgent(db)({
				externalAgentId: extAgent.id,
				scopes: {
					tenantId,
					projectId: typed.id
				}
			});
			deletedExternalAgentCount++;
			logger.info({ externalAgentId: extAgent.id }, "Deleted orphaned externalAgent from project");
		} catch (error) {
			logger.error({
				externalAgentId: extAgent.id,
				error
			}, "Failed to delete orphaned externalAgent from project");
		}
		if (deletedExternalAgentCount > 0) logger.info({
			deletedExternalAgentCount,
			projectId: typed.id
		}, "Deleted orphaned externalAgents from project");
		const incomingDataComponentIds = new Set(Object.keys(typed.dataComponents || {}));
		const existingDataComponents = await listDataComponents(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		let deletedDataComponentCount = 0;
		for (const dataComp of existingDataComponents) if (!incomingDataComponentIds.has(dataComp.id)) try {
			await deleteDataComponent(db)({
				dataComponentId: dataComp.id,
				scopes: {
					tenantId,
					projectId: typed.id
				}
			});
			deletedDataComponentCount++;
			logger.info({ dataComponentId: dataComp.id }, "Deleted orphaned dataComponent from project");
		} catch (error) {
			logger.error({
				dataComponentId: dataComp.id,
				error
			}, "Failed to delete orphaned dataComponent from project");
		}
		if (deletedDataComponentCount > 0) logger.info({
			deletedDataComponentCount,
			projectId: typed.id
		}, "Deleted orphaned dataComponents from project");
		const incomingArtifactComponentIds = new Set(Object.keys(typed.artifactComponents || {}));
		const existingArtifactComponents = await listArtifactComponents(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		let deletedArtifactComponentCount = 0;
		for (const artifactComp of existingArtifactComponents) if (!incomingArtifactComponentIds.has(artifactComp.id)) try {
			await deleteArtifactComponent(db)({
				id: artifactComp.id,
				scopes: {
					tenantId,
					projectId: typed.id
				}
			});
			deletedArtifactComponentCount++;
			logger.info({ artifactComponentId: artifactComp.id }, "Deleted orphaned artifactComponent from project");
		} catch (error) {
			logger.error({
				artifactComponentId: artifactComp.id,
				error
			}, "Failed to delete orphaned artifactComponent from project");
		}
		if (deletedArtifactComponentCount > 0) logger.info({
			deletedArtifactComponentCount,
			projectId: typed.id
		}, "Deleted orphaned artifactComponents from project");
		const incomingAgentIds = new Set(Object.keys(typed.agents || {}));
		const existingAgents = await listAgents(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		let deletedAgentCount = 0;
		for (const agent of existingAgents) if (!incomingAgentIds.has(agent.id)) try {
			await deleteFullAgent(db)({ scopes: {
				tenantId,
				projectId: typed.id,
				agentId: agent.id
			} });
			deletedAgentCount++;
			logger.info({ agentId: agent.id }, "Deleted orphaned agent from project");
		} catch (error) {
			logger.error({
				agentId: agent.id,
				error
			}, "Failed to delete orphaned agent from project");
		}
		if (deletedAgentCount > 0) logger.info({
			deletedAgentCount,
			projectId: typed.id
		}, "Deleted orphaned agent from project");
		if (typed.agents && Object.keys(typed.agents).length > 0) {
			logger.info({
				projectId: typed.id,
				agentCount: Object.keys(typed.agents).length
			}, "Updating project agent");
			const agentPromises = Object.entries(typed.agents).map(async ([agentId, agentData]) => {
				try {
					logger.info({
						projectId: typed.id,
						agentId
					}, "Updating agent in project");
					const agentDataWithProjectResources = {
						...agentData,
						tools: typed.tools || {},
						functions: typed.functions || {},
						dataComponents: typed.dataComponents || {},
						artifactComponents: typed.artifactComponents || {},
						externalAgents: typed.externalAgents || {},
						credentialReferences: typed.credentialReferences || {},
						statusUpdates: agentData.statusUpdates === null ? void 0 : agentData.statusUpdates
					};
					await updateFullAgentServerSide(db)({
						tenantId,
						projectId: typed.id
					}, agentDataWithProjectResources);
					logger.info({
						projectId: typed.id,
						agentId
					}, "Agent updated successfully in project");
				} catch (error) {
					logger.error({
						projectId: typed.id,
						agentId,
						error
					}, "Failed to update agent in project");
					throw error;
				}
			});
			const agentErrors = (await Promise.allSettled(agentPromises)).filter((r) => r.status === "rejected").map((r) => r.reason);
			if (agentErrors.length > 0) {
				logger.error({
					projectId: typed.id,
					errorCount: agentErrors.length
				}, `Some agents failed to update in project: ${agentErrors.join(", ")}`);
				throw agentErrors[0];
			}
			logger.info({
				projectId: typed.id,
				agentCount: Object.keys(typed.agents).length
			}, "All project agent updated successfully");
		}
		logger.info({ projectId: typed.id }, "Full project updated successfully");
		const fullProject = await getFullProject(db)({ scopes: {
			tenantId,
			projectId: typed.id
		} });
		if (!fullProject) throw new Error("Failed to retrieve full project");
		return fullProject;
	} catch (error) {
		logger.error({
			tenantId,
			projectId: typed.id,
			error
		}, "Failed to update full project");
		throw error;
	}
};
/**
* Get a complete project definition with all nested resources
*/
const getFullProjectInternal = (db) => async (params) => {
	const { scopes, includeRelationIds = false } = params;
	const { tenantId, projectId } = scopes;
	logger.info({
		tenantId,
		projectId,
		includeRelationIds
	}, "Retrieving full project definition");
	try {
		const project = await getProject(db)({ scopes: {
			tenantId,
			projectId
		} });
		if (!project) {
			logger.info({
				tenantId,
				projectId
			}, "Project not found");
			return null;
		}
		logger.info({
			tenantId,
			projectId
		}, "Project metadata retrieved");
		const agentList = await listAgents(db)({ scopes: {
			tenantId,
			projectId
		} });
		logger.info({
			tenantId,
			projectId,
			agentCount: agentList.length
		}, "Found agent for project");
		const projectTools = {};
		try {
			const toolsList = await listTools(db)({
				scopes: {
					tenantId,
					projectId
				},
				pagination: {
					page: 1,
					limit: 1e3
				}
			});
			for (const tool of toolsList.data) projectTools[tool.id] = tool;
			logger.info({
				tenantId,
				projectId,
				toolCount: Object.keys(projectTools).length
			}, "Tools retrieved for project");
		} catch (error) {
			logger.warn({
				tenantId,
				projectId,
				error
			}, "Failed to retrieve tools for project");
		}
		const projectExternalAgents = {};
		try {
			const externalAgentsList = await listExternalAgents(db)({ scopes: {
				tenantId,
				projectId
			} });
			for (const externalAgent of externalAgentsList) projectExternalAgents[externalAgent.id] = externalAgent;
			logger.info({
				tenantId,
				projectId,
				count: Object.keys(projectExternalAgents).length
			}, "ExternalAgents retrieved for project");
		} catch (error) {
			logger.warn({
				tenantId,
				projectId,
				error
			}, "Failed to retrieve externalAgents for project");
		}
		const projectDataComponents = {};
		try {
			const dataComponentsList = await listDataComponents(db)({ scopes: {
				tenantId,
				projectId
			} });
			for (const component of dataComponentsList) projectDataComponents[component.id] = component;
			logger.info({
				tenantId,
				projectId,
				count: Object.keys(projectDataComponents).length
			}, "DataComponents retrieved for project");
		} catch (error) {
			logger.warn({
				tenantId,
				projectId,
				error
			}, "Failed to retrieve dataComponents for project");
		}
		const projectArtifactComponents = {};
		try {
			const artifactComponentsList = await listArtifactComponents(db)({ scopes: {
				tenantId,
				projectId
			} });
			for (const component of artifactComponentsList) projectArtifactComponents[component.id] = component;
			logger.info({
				tenantId,
				projectId,
				count: Object.keys(projectArtifactComponents).length
			}, "ArtifactComponents retrieved for project");
		} catch (error) {
			logger.warn({
				tenantId,
				projectId,
				error
			}, "Failed to retrieve artifactComponents for project");
		}
		const projectCredentialReferences = {};
		try {
			const credentialReferencesList = await listCredentialReferences(db)({ scopes: {
				tenantId,
				projectId
			} });
			for (const credential of credentialReferencesList) projectCredentialReferences[credential.id] = credential;
			logger.info({
				tenantId,
				projectId,
				count: Object.keys(projectCredentialReferences).length
			}, "CredentialReferences retrieved for project");
		} catch (error) {
			logger.warn({
				tenantId,
				projectId,
				error
			}, "Failed to retrieve credentialReferences for project");
		}
		const projectFunctions = {};
		try {
			const functionsList = await listFunctions(db)({ scopes: {
				tenantId,
				projectId
			} });
			for (const func of functionsList) projectFunctions[func.id] = func;
			logger.info({
				tenantId,
				projectId,
				functionCount: Object.keys(projectFunctions).length
			}, "Functions retrieved for project");
		} catch (error) {
			logger.warn({
				tenantId,
				projectId,
				error
			}, "Failed to retrieve functions for project");
		}
		const projectSkills = {};
		try {
			const skillsList = await listSkillsWithFiles(db)({
				scopes: {
					tenantId,
					projectId
				},
				pagination: {
					page: 1,
					limit: 1e3
				}
			});
			for (const skill of skillsList.data) projectSkills[skill.id] = {
				id: skill.id,
				name: skill.name,
				description: skill.description,
				content: skill.content,
				metadata: skill.metadata,
				files: skill.files.map((file) => ({
					filePath: file.filePath,
					content: file.content
				})),
				createdAt: skill.createdAt,
				updatedAt: skill.updatedAt
			};
			logger.info({
				tenantId,
				projectId,
				skillCount: Object.keys(projectSkills).length
			}, "Skills retrieved for project");
		} catch (error) {
			logger.warn({
				tenantId,
				projectId,
				error
			}, "Failed to retrieve skills for project");
		}
		const agents = {};
		if (agentList.length > 0) {
			const getAgentFn = includeRelationIds ? getFullAgentWithRelationIds : getFullAgent;
			const agentPromises = agentList.map(async (agent) => {
				try {
					logger.info({
						tenantId,
						projectId,
						agentId: agent.id
					}, "Retrieving full agent definition");
					const fullAgent = await getAgentFn(db)({ scopes: {
						tenantId,
						projectId,
						agentId: agent.id
					} });
					if (fullAgent) {
						agents[agent.id] = fullAgent;
						logger.info({
							tenantId,
							projectId,
							agentId: agent.id
						}, "Full agent definition retrieved");
					} else logger.warn({
						tenantId,
						projectId,
						agentId: agent.id
					}, "Agent definition not found");
				} catch (error) {
					logger.error({
						tenantId,
						projectId,
						agentId: agent.id,
						error
					}, "Failed to retrieve full agent definition");
				}
			});
			await Promise.all(agentPromises);
		}
		const projectModels = project.models ?? {
			base: { model: "claude-sonnet-4-5" },
			structuredOutput: { model: "claude-sonnet-4-5" },
			summarizer: { model: "claude-sonnet-4-5" }
		};
		if (!projectModels.base) logger.warn({
			tenantId,
			projectId
		}, `Project ${project.id} is missing base model configuration. Using default: claude-sonnet-4-5`);
		const fullProjectDefinition = {
			id: project.id,
			name: project.name,
			description: project.description,
			models: projectModels,
			stopWhen: project.stopWhen ?? null,
			agents,
			tools: projectTools,
			functions: Object.keys(projectFunctions).length > 0 ? projectFunctions : null,
			externalAgents: Object.keys(projectExternalAgents).length > 0 ? projectExternalAgents : null,
			dataComponents: Object.keys(projectDataComponents).length > 0 ? projectDataComponents : null,
			artifactComponents: Object.keys(projectArtifactComponents).length > 0 ? projectArtifactComponents : null,
			credentialReferences: Object.keys(projectCredentialReferences).length > 0 ? projectCredentialReferences : null,
			statusUpdates: null,
			functionTools: null,
			skills: Object.keys(projectSkills).length > 0 ? projectSkills : void 0,
			createdAt: project.createdAt,
			updatedAt: project.updatedAt
		};
		logger.info({
			tenantId,
			projectId,
			agentCount: Object.keys(fullProjectDefinition.agents).length
		}, "Full project definition retrieved");
		return fullProjectDefinition;
	} catch (error) {
		logger.error({
			tenantId,
			projectId,
			error
		}, "Failed to retrieve full project");
		throw error;
	}
};
const getFullProject = (db) => async (params) => {
	const { scopes } = params;
	return getFullProjectInternal(db)({
		scopes,
		includeRelationIds: false
	});
};
const getFullProjectWithRelationIds = (db) => async (params) => {
	const { scopes } = params;
	return getFullProjectInternal(db)({
		scopes,
		includeRelationIds: true
	});
};
/**
* Delete a complete project and cascade to all related entities
*/
const deleteFullProject = (db) => async (params) => {
	const { scopes } = params;
	const { tenantId, projectId } = scopes;
	logger.info({
		tenantId,
		projectId
	}, "Deleting full project and related entities");
	try {
		const project = await getFullProject(db)({ scopes: {
			tenantId,
			projectId
		} });
		if (!project) {
			logger.info({
				tenantId,
				projectId
			}, "Project not found for deletion");
			return false;
		}
		if (project.agents && Object.keys(project.agents).length > 0) {
			logger.info({
				tenantId,
				projectId,
				agentCount: Object.keys(project.agents).length
			}, "Deleting project agent");
			const agentPromises = Object.keys(project.agents).map(async (agentId) => {
				try {
					logger.info({
						tenantId,
						projectId,
						agentId
					}, "Deleting agent from project");
					await deleteFullAgent(db)({ scopes: {
						tenantId,
						projectId,
						agentId
					} });
					logger.info({
						tenantId,
						projectId,
						agentId
					}, "Agent deleted successfully from project");
				} catch (error) {
					logger.error({
						tenantId,
						projectId,
						agentId,
						error
					}, "Failed to delete agent from project");
					throw error;
				}
			});
			await Promise.all(agentPromises);
			logger.info({
				tenantId,
				projectId,
				agentCount: Object.keys(project.agents).length
			}, "All project agent deleted successfully");
		}
		if (!await deleteProject(db)({ scopes: {
			tenantId,
			projectId
		} })) {
			logger.warn({
				tenantId,
				projectId
			}, "Project deletion returned false");
			return false;
		}
		logger.info({
			tenantId,
			projectId
		}, "Full project deleted successfully");
		return true;
	} catch (error) {
		logger.error({
			tenantId,
			projectId,
			error
		}, "Failed to delete full project");
		throw error;
	}
};

//#endregion
export { createFullProjectServerSide, deleteFullProject, getFullProject, getFullProjectWithRelationIds, updateFullProjectServerSide };