import { getLogger as getLogger$1 } from "../../../logger.js";
import manageDbClient_default from "../../../data/db/manageDbClient.js";
import runDbClient_default from "../../../data/db/runDbClient.js";
import { requireProjectPermission } from "../../../middleware/projectAccess.js";
import { requirePermission } from "../../../middleware/requirePermission.js";
import { OpenAPIHono, createRoute, z } from "@hono/zod-openapi";
import { ErrorResponseSchema, FullProjectDefinitionSchema, FullProjectSelectResponse, FullProjectSelectWithRelationIdsResponse, TenantParamsSchema, TenantProjectParamsSchema, cascadeDeleteByProject, checkoutBranch, commonGetErrorResponses, createApiError, createFullProjectServerSide, createProjectMetadataAndBranch, deleteFullProject, deleteProjectWithBranch, doltCheckout, getFullProject, getFullProjectWithRelationIds, getProjectMainBranchName, getProjectMetadata, updateFullProjectServerSide } from "@inkeep/agents-core";

//#region src/domains/manage/routes/projectFull.ts
const logger = getLogger$1("projectFull");
const app = new OpenAPIHono();
app.use("/project-full", async (c, next) => {
	if (c.req.method === "POST") return requirePermission({ project: ["create"] })(c, next);
	return next();
});
app.use("/project-full/:projectId", async (c, next) => {
	if (c.req.method === "GET") return requireProjectPermission("view")(c, next);
	return next();
});
app.use("/project-full/:projectId/with-relation-ids", async (c, next) => {
	if (c.req.method === "GET") return requireProjectPermission("view")(c, next);
	return next();
});
const requireProjectUpsertPermission = async (c, next) => {
	const tenantId = c.get("tenantId");
	const projectId = c.req.param("projectId");
	if (!tenantId || !projectId) throw createApiError({
		code: "bad_request",
		message: "Missing tenantId or projectId"
	});
	const exists = await getProjectMetadata(runDbClient_default)({
		tenantId,
		projectId
	});
	c.set("isProjectCreate", !exists);
	return exists ? requireProjectPermission("edit")(c, next) : requirePermission({ project: ["create"] })(c, next);
};
app.openapi(createRoute({
	method: "post",
	path: "/project-full",
	summary: "Create Full Project",
	operationId: "create-full-project",
	tags: ["Projects"],
	description: "Create a complete project with all Agents, Sub Agents, tools, and relationships from JSON definition",
	request: {
		params: TenantParamsSchema,
		body: { content: { "application/json": { schema: FullProjectDefinitionSchema } } }
	},
	responses: {
		201: {
			description: "Full project created successfully",
			content: { "application/json": { schema: FullProjectSelectResponse } }
		},
		409: {
			description: "Project already exists",
			content: { "application/json": { schema: ErrorResponseSchema } }
		},
		...commonGetErrorResponses
	}
}), async (c) => {
	const configDb = c.get("db");
	const userId = c.get("userId");
	const { tenantId } = c.req.valid("param");
	const projectData = c.req.valid("json");
	const validatedProjectData = FullProjectDefinitionSchema.parse(projectData);
	try {
		await createProjectMetadataAndBranch(runDbClient_default, configDb)({
			tenantId,
			projectId: validatedProjectData.id,
			createdBy: userId
		});
		logger.info({
			tenantId,
			projectId: validatedProjectData.id
		}, "Created project with branch, now populating config");
		const projectMainBranch = getProjectMainBranchName(tenantId, validatedProjectData.id);
		await checkoutBranch(configDb)({
			branchName: projectMainBranch,
			autoCommitPending: true
		});
		const newResolvedRef = {
			type: "branch",
			name: projectMainBranch,
			hash: ""
		};
		c.set("resolvedRef", newResolvedRef);
		logger.debug({ projectMainBranch }, "Checked out project branch for config writes");
		const createdProject = await createFullProjectServerSide(configDb)({
			scopes: {
				tenantId,
				projectId: validatedProjectData.id
			},
			projectData: validatedProjectData
		});
		return c.json({ data: createdProject }, 201);
	} catch (error) {
		logger.error({ error }, "Error creating project");
		if (error?.cause?.code === "23505" || error?.message?.includes("already exists")) throw createApiError({
			code: "conflict",
			message: `Project with ID '${projectData.id}' already exists`
		});
		throw error;
	}
});
app.openapi(createRoute({
	method: "get",
	path: "/project-full/{projectId}",
	summary: "Get Full Project",
	operationId: "get-full-project",
	tags: ["Projects"],
	description: "Retrieve a complete project definition with all Agents, Sub Agents, tools, and relationships",
	request: { params: TenantProjectParamsSchema },
	responses: {
		200: {
			description: "Full project found",
			content: { "application/json": { schema: FullProjectSelectResponse } }
		},
		...commonGetErrorResponses
	}
}), async (c) => {
	const { tenantId, projectId } = c.req.valid("param");
	const db = c.get("db");
	try {
		const project = await getFullProject(db)({ scopes: {
			tenantId,
			projectId
		} });
		if (!project) throw createApiError({
			code: "not_found",
			message: "Project not found"
		});
		return c.json({ data: project });
	} catch (error) {
		if (error instanceof Error && error.message.includes("not found")) throw createApiError({
			code: "not_found",
			message: "Project not found"
		});
		throw createApiError({
			code: "internal_server_error",
			message: error instanceof Error ? error.message : "Failed to retrieve project"
		});
	}
});
app.openapi(createRoute({
	method: "get",
	path: "/project-full/{projectId}/with-relation-ids",
	summary: "Get Full Project with Relation IDs",
	operationId: "get-full-project-with-relation-ids",
	tags: ["Projects"],
	description: "Retrieve a complete project definition with all Agents, Sub Agents, tools, and relationships",
	request: { params: TenantProjectParamsSchema },
	responses: {
		200: {
			description: "Full project found",
			content: { "application/json": { schema: FullProjectSelectWithRelationIdsResponse } }
		},
		...commonGetErrorResponses
	}
}), async (c) => {
	const { tenantId, projectId } = c.req.valid("param");
	const db = c.get("db");
	try {
		const project = await getFullProjectWithRelationIds(db)({ scopes: {
			tenantId,
			projectId
		} });
		if (!project) throw createApiError({
			code: "not_found",
			message: "Project not found"
		});
		return c.json({ data: project });
	} catch (error) {
		if (error instanceof Error && error.message.includes("not found")) throw createApiError({
			code: "not_found",
			message: "Project not found"
		});
		throw createApiError({
			code: "internal_server_error",
			message: error instanceof Error ? error.message : "Failed to retrieve project"
		});
	}
});
app.use("/project-full/:projectId", async (c, next) => {
	if (c.req.method === "PUT") return requireProjectUpsertPermission(c, next);
	return next();
});
app.openapi(createRoute({
	method: "put",
	path: "/project-full/{projectId}",
	summary: "Update Full Project",
	operationId: "update-full-project",
	tags: ["Projects"],
	description: "Update or create a complete project with all Agents, Sub Agents, tools, and relationships from JSON definition",
	request: {
		params: TenantProjectParamsSchema,
		body: { content: { "application/json": { schema: FullProjectDefinitionSchema } } }
	},
	responses: {
		200: {
			description: "Full project updated successfully",
			content: { "application/json": { schema: FullProjectSelectResponse } }
		},
		201: {
			description: "Full project created successfully",
			content: { "application/json": { schema: FullProjectSelectResponse } }
		},
		...commonGetErrorResponses
	}
}), async (c) => {
	const { tenantId, projectId } = c.req.valid("param");
	const projectData = c.req.valid("json");
	const configDb = c.get("db");
	const userId = c.get("userId");
	try {
		const validatedProjectData = FullProjectDefinitionSchema.parse(projectData);
		if (projectId !== validatedProjectData.id) throw createApiError({
			code: "bad_request",
			message: `Project ID mismatch: expected ${projectId}, got ${validatedProjectData.id}`
		});
		const isCreate = c.get("isProjectCreate") ?? false;
		if (isCreate) {
			await createProjectMetadataAndBranch(runDbClient_default, configDb)({
				tenantId,
				projectId,
				createdBy: userId
			});
			logger.info({
				tenantId,
				projectId
			}, "Created project with branch for PUT (upsert)");
			const projectMainBranch = getProjectMainBranchName(tenantId, projectId);
			await checkoutBranch(configDb)({
				branchName: projectMainBranch,
				autoCommitPending: true
			});
		}
		const updatedProject = isCreate ? await createFullProjectServerSide(configDb)({
			scopes: {
				tenantId,
				projectId
			},
			projectData: validatedProjectData
		}) : await updateFullProjectServerSide(configDb)({
			scopes: {
				tenantId,
				projectId
			},
			projectData: validatedProjectData
		});
		return c.json({ data: updatedProject }, isCreate ? 201 : 200);
	} catch (error) {
		if (error instanceof z.ZodError) throw createApiError({
			code: "bad_request",
			message: "Invalid project definition"
		});
		if (error instanceof Error && error.message.includes("ID mismatch")) throw createApiError({
			code: "bad_request",
			message: error.message
		});
		throw createApiError({
			code: "internal_server_error",
			message: error instanceof Error ? error.message : "Failed to update project"
		});
	}
});
app.use("/project-full/:projectId", async (c, next) => {
	if (c.req.method === "DELETE") return requirePermission({ project: ["delete"] })(c, next);
	return next();
});
app.openapi(createRoute({
	method: "delete",
	path: "/project-full/{projectId}",
	summary: "Delete Full Project",
	operationId: "delete-full-project",
	tags: ["Projects"],
	description: "Delete a complete project and cascade to all related entities (Agents, Sub Agents, tools, relationships)",
	request: { params: TenantProjectParamsSchema },
	responses: {
		204: { description: "Project deleted successfully" },
		...commonGetErrorResponses
	}
}), async (c) => {
	const { tenantId, projectId } = c.req.valid("param");
	const configDb = c.get("db");
	const resolvedRef = c.get("resolvedRef");
	const expectedMainBranch = `${tenantId}_${projectId}_main`;
	if (resolvedRef?.name !== expectedMainBranch) throw createApiError({
		code: "bad_request",
		message: "Project deletion must be performed from the main branch"
	});
	try {
		await cascadeDeleteByProject(runDbClient_default)({
			scopes: {
				tenantId,
				projectId
			},
			fullBranchName: resolvedRef.name
		});
		await deleteFullProject(configDb)({ scopes: {
			tenantId,
			projectId
		} });
		await doltCheckout(configDb)({ branch: "main" });
		if (!await deleteProjectWithBranch(runDbClient_default, manageDbClient_default)({
			tenantId,
			projectId
		})) throw createApiError({
			code: "not_found",
			message: "Project not found"
		});
		return c.body(null, 204);
	} catch (error) {
		if (error instanceof Error && error.message.includes("not found")) throw createApiError({
			code: "not_found",
			message: "Project not found"
		});
		throw createApiError({
			code: "internal_server_error",
			message: error instanceof Error ? error.message : "Failed to delete project"
		});
	}
});
var projectFull_default = app;

//#endregion
export { projectFull_default as default };