import { apiKeys } from "../../db/runtime/runtime-schema.js";
import { projectScopedWhere } from "../manage/scope-helpers.js";
import { extractPublicId, generateApiKey, isApiKeyExpired, validateApiKey } from "../../utils/apiKeys.js";
import { and, count, desc, eq } from "drizzle-orm";

//#region src/data-access/runtime/apiKeys.ts
const getApiKeyById = (db) => async (params) => {
	return await db.query.apiKeys.findFirst({ where: and(projectScopedWhere(apiKeys, params.scopes), eq(apiKeys.id, params.id)) });
};
const getApiKeyByPublicId = (db) => async (publicId) => {
	return await db.query.apiKeys.findFirst({ where: eq(apiKeys.publicId, publicId) });
};
const listApiKeys = (db) => async (params) => {
	const conditions = [projectScopedWhere(apiKeys, params.scopes)];
	if (params.agentId) conditions.push(eq(apiKeys.agentId, params.agentId));
	return await db.query.apiKeys.findMany({
		where: and(...conditions),
		orderBy: [desc(apiKeys.createdAt)]
	});
};
const listApiKeysPaginated = (db) => async (params) => {
	const page = params.pagination?.page || 1;
	const limit = Math.min(params.pagination?.limit || 10, 100);
	const offset = (page - 1) * limit;
	const conditions = [projectScopedWhere(apiKeys, params.scopes)];
	if (params.agentId) conditions.push(eq(apiKeys.agentId, params.agentId));
	const whereClause = and(...conditions);
	const [data, totalResult] = await Promise.all([db.select().from(apiKeys).where(whereClause).limit(limit).offset(offset).orderBy(desc(apiKeys.createdAt)), db.select({ count: count() }).from(apiKeys).where(whereClause)]);
	const total = totalResult[0]?.count || 0;
	const totalNumber = typeof total === "string" ? Number.parseInt(total, 10) : total;
	return {
		data,
		pagination: {
			page,
			limit,
			total: totalNumber,
			pages: Math.ceil(totalNumber / limit)
		}
	};
};
const createApiKey = (db) => async (params) => {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [apiKey] = await db.insert(apiKeys).values({
		id: params.id,
		name: params.name,
		tenantId: params.tenantId,
		projectId: params.projectId,
		agentId: params.agentId,
		publicId: params.publicId,
		keyHash: params.keyHash,
		keyPrefix: params.keyPrefix,
		expiresAt: params.expiresAt,
		createdAt: now,
		updatedAt: now
	}).returning();
	return apiKey;
};
const updateApiKey = (db) => async (params) => {
	const now = (/* @__PURE__ */ new Date()).toISOString();
	const [updatedKey] = await db.update(apiKeys).set({
		name: params.data.name,
		expiresAt: params.data.expiresAt,
		updatedAt: now
	}).where(and(projectScopedWhere(apiKeys, params.scopes), eq(apiKeys.id, params.id))).returning();
	return updatedKey;
};
const deleteApiKey = (db) => async (params) => {
	try {
		if (!await getApiKeyById(db)({
			scopes: params.scopes,
			id: params.id
		})) {
			console.error("API key not found", { params });
			return false;
		}
		await db.delete(apiKeys).where(and(projectScopedWhere(apiKeys, params.scopes), eq(apiKeys.id, params.id)));
		return true;
	} catch (error) {
		console.error("Error deleting API key:", error);
		return false;
	}
};
const hasApiKey = (db) => async (params) => {
	return await getApiKeyById(db)(params) !== null;
};
const updateApiKeyLastUsed = (db) => async (params) => {
	await db.update(apiKeys).set({ lastUsedAt: (/* @__PURE__ */ new Date()).toISOString() }).where(and(projectScopedWhere(apiKeys, params.scopes), eq(apiKeys.id, params.id)));
};
const countApiKeys = (db) => async (params) => {
	const conditions = [projectScopedWhere(apiKeys, params.scopes)];
	if (params.agentId) conditions.push(eq(apiKeys.agentId, params.agentId));
	const total = (await db.select({ count: count() }).from(apiKeys).where(and(...conditions)))[0]?.count || 0;
	return typeof total === "string" ? Number.parseInt(total, 10) : total;
};
/**
* Create a new API key
* Returns both the API key record and the full key (which should be shown to the user only once)
*/
const generateAndCreateApiKey = async (params, db) => {
	const { tenantId, projectId, agentId, expiresAt, name } = params;
	const keyData = await generateApiKey();
	return {
		apiKey: await createApiKey(db)({
			tenantId,
			projectId,
			agentId,
			name,
			expiresAt,
			...keyData
		}),
		key: keyData.key
	};
};
const validateAndGetApiKey = async (key, db) => {
	const publicId = extractPublicId(key);
	if (!publicId) return null;
	const apiKey = await getApiKeyByPublicId(db)(publicId);
	if (!apiKey) return null;
	if (!await validateApiKey(key, apiKey.keyHash)) return null;
	if (isApiKeyExpired(apiKey.expiresAt)) return null;
	await updateApiKeyLastUsed(db)({
		id: apiKey.id,
		scopes: {
			tenantId: apiKey.tenantId,
			projectId: apiKey.projectId
		}
	});
	return apiKey;
};

//#endregion
export { countApiKeys, createApiKey, deleteApiKey, generateAndCreateApiKey, getApiKeyById, getApiKeyByPublicId, hasApiKey, listApiKeys, listApiKeysPaginated, updateApiKey, updateApiKeyLastUsed, validateAndGetApiKey };