import { getLogger as getLogger$1 } from "../logger.js";
import manageDbClient_default from "../data/db/manageDbClient.js";
import { checkoutBranch, doltAddAndCommit, doltReset, doltStatus, generateId } from "@inkeep/agents-core";
import * as schema from "@inkeep/agents-core/db/manage-schema";
import { drizzle } from "drizzle-orm/node-postgres";

//#region src/middleware/branchScopedDb.ts
const logger = getLogger$1("branch-scoped-db");
function isProjectDeleteOperation(path, method) {
	return method.toUpperCase() === "DELETE" && /^\/tenants\/[^/]+\/(?:projects|project-full)\/[^/]+\/?$/.test(path);
}
/**
* Get the underlying connection pool from a Drizzle database client
*/
function getPoolFromClient(client) {
	if ("$client" in client && client.$client) return client.$client;
	return null;
}
/**
* Middleware that provides branch-scoped database connections
*
* Flow:
* 1. Get a dedicated connection from the pool
* 2. If ref is specified, checkout that branch/tag/commit on this connection
* 3. Create a Drizzle client wrapping this specific connection
* 4. Inject into context as 'db' (request-scoped database client)
* 5. Execute the route handler
* 6. For write operations on branches: auto-commit changes
* 7. Always cleanup: checkout main and release connection
*
* This ensures:
* - All operations in a request use the same connection (correct)
* - Only one checkout per request (performant)
* - Automatic commits for successful writes on branches
* - Proper connection cleanup
*/
const branchScopedDbMiddleware = async (c, next) => {
	const resolvedRef = c.get("resolvedRef");
	const method = c.req.method;
	const userId = c.get("userId");
	const userEmail = c.get("userEmail");
	const pool = getPoolFromClient(manageDbClient_default);
	if (!pool) {
		logger.error({}, "Could not get connection pool from dbClient");
		c.set("db", manageDbClient_default);
		await next();
		return;
	}
	if (process.env.ENVIRONMENT === "test") {
		c.set("db", manageDbClient_default);
		await next();
		return;
	}
	const connection = await pool.connect();
	let tempBranch = null;
	try {
		const requestDb = drizzle(connection, { schema });
		if (resolvedRef.type === "branch") {
			logger.debug({ branch: resolvedRef.name }, "Checking out branch");
			await checkoutBranch(requestDb)({
				branchName: resolvedRef.name,
				autoCommitPending: true
			});
		} else {
			tempBranch = `temp_${resolvedRef.type}_${resolvedRef.hash}_${generateId()}`;
			logger.debug({
				tempBranch,
				hash: resolvedRef.hash
			}, "Creating temporary branch");
			await connection.query(`SELECT DOLT_CHECKOUT('-b', $1, $2)`, [tempBranch, resolvedRef.hash]);
		}
		c.set("db", requestDb);
		await next();
		const isReadMethod = method === "GET" || method === "HEAD";
		const status = c.res.status;
		const projectDeleteOperation = isProjectDeleteOperation(c.req.path, method);
		const operationSuccess = status >= 200 && status < 300;
		if (resolvedRef.type === "branch" && operationSuccess && !projectDeleteOperation && !isReadMethod) try {
			const statusResult = await doltStatus(requestDb)();
			if (statusResult.length > 0 && operationSuccess) {
				const path = c.req.path;
				const commitMessage = generateCommitMessage(method, path);
				logger.info({
					branch: resolvedRef.name,
					message: commitMessage
				}, "Auto-committing changes");
				await doltAddAndCommit(requestDb)({
					message: commitMessage,
					author: {
						name: userId ?? "agents-api",
						email: userEmail ?? "api@inkeep.com"
					}
				});
				logger.info({ branch: resolvedRef.name }, "Successfully committed changes");
			} else if (statusResult.length > 0 && !operationSuccess) {
				await doltReset(requestDb)();
				logger.info({ branch: resolvedRef.name }, "Successfully reset changes due to failed operation");
			}
		} catch (error) {
			logger.error({
				error,
				branch: resolvedRef.name
			}, "Failed to auto-commit changes");
		}
	} finally {
		try {
			await connection.query(`SELECT DOLT_CHECKOUT('main')`);
			if (tempBranch) await connection.query(`SELECT DOLT_BRANCH('-D', $1)`, [tempBranch]);
		} catch (cleanupError) {
			logger.error({ error: cleanupError }, "Error during connection cleanup");
		} finally {
			connection.release();
		}
	}
};
/**
* Generate a commit message based on HTTP method and path
*/
function generateCommitMessage(method, path) {
	let operation;
	switch (method) {
		case "POST":
			operation = "Create";
			break;
		case "PUT":
		case "PATCH":
			operation = "Update";
			break;
		case "DELETE":
			operation = "Delete";
			break;
		default: operation = method;
	}
	return `${operation} ${path} via API`;
}

//#endregion
export { branchScopedDbMiddleware, getPoolFromClient, isProjectDeleteOperation };