import runDbClient_default from "../data/db/runDbClient.js";
import { OrgRoles, createApiError, getUserOrganizationsFromDb } from "@inkeep/agents-core";
import { createMiddleware } from "hono/factory";
import { HTTPException } from "hono/http-exception";

//#region src/middleware/tenantAccess.ts
/**
* Middleware to enforce tenant access control.
* Verifies that the authenticated user has access to the requested tenant/organization.
*
* Access rules:
* - System user (bypass auth): Full access to all tenants
* - API key user: Access only to the tenant associated with the API key
* - Session user: Access based on organization membership
*/
const requireTenantAccess = () => createMiddleware(async (c, next) => {
	const userId = c.get("userId");
	const tenantId = c.req.param("tenantId");
	if (!userId) throw createApiError({
		code: "unauthorized",
		message: "User ID not found"
	});
	if (!tenantId) throw createApiError({
		code: "bad_request",
		message: "Organization ID is required"
	});
	if (userId === "system") {
		c.set("tenantId", tenantId);
		c.set("tenantRole", OrgRoles.OWNER);
		await next();
		return;
	}
	if (userId.startsWith("apikey:")) {
		const apiKeyTenantId = c.get("tenantId");
		if (apiKeyTenantId && apiKeyTenantId !== tenantId) throw createApiError({
			code: "forbidden",
			message: "API key does not have access to this organization"
		});
		c.set("tenantId", tenantId);
		c.set("tenantRole", OrgRoles.OWNER);
		await next();
		return;
	}
	try {
		const organizationAccess = (await getUserOrganizationsFromDb(runDbClient_default)(userId)).find((org) => org.organizationId === tenantId);
		if (!organizationAccess) throw createApiError({
			code: "forbidden",
			message: "Access denied to this organization"
		});
		c.set("tenantId", tenantId);
		c.set("tenantRole", organizationAccess.role);
		await next();
	} catch (error) {
		if (error instanceof HTTPException) throw error;
		throw createApiError({
			code: "internal_server_error",
			message: "Failed to verify organization access"
		});
	}
});

//#endregion
export { requireTenantAccess };