import { getLogger } from "./logger.js";
import { extractBearerToken, hasIssuer, signJwt, verifyJwt } from "./jwt-helpers.js";

//#region src/utils/internal-service-auth.ts
const logger = getLogger("internal-service-auth");
const ISSUER = "inkeep-agents-internal";
/**
* Known internal services that can authenticate
*/
const InternalServices = {
	INKEEP_AGENTS_RUN_API: "inkeep-agents-run-api",
	INKEEP_AGENTS_MANAGE_API: "inkeep-agents-manage-api",
	INKEEP_AGENTS_EVAL_API: "inkeep-agents-eval-api"
};
/**
* Generate an internal service token for service-to-service authentication
*/
async function generateInternalServiceToken(params) {
	try {
		const claims = {};
		if (params.tenantId) claims.tenantId = params.tenantId;
		if (params.projectId) claims.projectId = params.projectId;
		if (params.userId) claims.userId = params.userId;
		const token = await signJwt({
			issuer: ISSUER,
			subject: params.serviceId,
			expiresIn: params.expiresIn || "5m",
			claims
		});
		logger.debug({
			serviceId: params.serviceId,
			tenantId: params.tenantId,
			projectId: params.projectId
		}, "Generated internal service token");
		return token;
	} catch (error) {
		logger.error({ error }, "Failed to generate internal service token");
		throw new Error("Failed to generate internal service token");
	}
}
/**
* Verify and decode an internal service token
*/
async function verifyInternalServiceToken(token) {
	const result = await verifyJwt(token, { issuer: ISSUER });
	if (!result.valid || !result.payload) {
		logger.warn({ error: result.error }, "Internal service token verification failed");
		return {
			valid: false,
			error: result.error
		};
	}
	const payload = result.payload;
	if (typeof payload.sub !== "string") {
		logger.warn({ payload }, "Invalid internal service token: missing subject");
		return {
			valid: false,
			error: "Invalid token: missing service identifier"
		};
	}
	if (!Object.values(InternalServices).includes(payload.sub)) {
		logger.warn({ serviceId: payload.sub }, "Unknown service identifier in token");
		return {
			valid: false,
			error: `Unknown service identifier: ${payload.sub}`
		};
	}
	const validPayload = {
		iss: payload.iss,
		sub: payload.sub,
		tenantId: payload.tenantId,
		projectId: payload.projectId,
		userId: payload.userId,
		iat: payload.iat,
		exp: payload.exp
	};
	logger.debug({
		serviceId: validPayload.sub,
		tenantId: validPayload.tenantId,
		projectId: validPayload.projectId,
		userId: validPayload.userId
	}, "Successfully verified internal service token");
	return {
		valid: true,
		payload: validPayload
	};
}
/**
* Extract and verify an internal service token from Authorization header
*/
async function verifyInternalServiceAuthHeader(authHeader) {
	const extracted = extractBearerToken(authHeader);
	if (!extracted.token) return {
		valid: false,
		error: extracted.error
	};
	return verifyInternalServiceToken(extracted.token);
}
/**
* Check if a token is an internal service token (vs user/agent token)
* by checking the issuer claim without full verification
*/
function isInternalServiceToken(token) {
	return hasIssuer(token, ISSUER);
}
/**
* Validate that the token has access to the specified tenant.
* If token has no tenantId claim, it has access to all tenants (superuser service).
*/
function validateInternalServiceTenantAccess(payload, tenantId) {
	if (!payload.tenantId) return true;
	if (payload.tenantId !== tenantId) {
		logger.warn({
			tokenTenantId: payload.tenantId,
			requestedTenantId: tenantId,
			serviceId: payload.sub
		}, "Internal service token tenant mismatch");
		return false;
	}
	return true;
}
/**
* Validate that the token has access to the specified project.
* If token has no projectId claim, it has access to all projects in the allowed tenant(s).
*/
function validateInternalServiceProjectAccess(payload, projectId) {
	if (!payload.projectId) return true;
	if (payload.projectId !== projectId) {
		logger.warn({
			tokenProjectId: payload.projectId,
			requestedProjectId: projectId,
			serviceId: payload.sub
		}, "Internal service token project mismatch");
		return false;
	}
	return true;
}

//#endregion
export { InternalServices, generateInternalServiceToken, isInternalServiceToken, validateInternalServiceProjectAccess, validateInternalServiceTenantAccess, verifyInternalServiceAuthHeader, verifyInternalServiceToken };