import { GenericError } from "../utils/errors/ErrorsClass.mjs";
import { ProjectModel } from "../models/project.model.mjs";
import { getProjectById } from "./project.service.mjs";
import { randomBytes } from "node:crypto";

//#region src/services/projectAccessKey.service.ts
/**
* Generates cryptographically secure OAuth2 client credentials
*
* @returns Object containing clientId and clientSecret
*
* Security improvements:
* - clientId: 32 characters (128 bits of entropy)
* - clientSecret: 64 characters (256 bits of entropy)
* - Uses crypto.randomBytes for cryptographically secure random generation
* - Follows OAuth2 best practices for credential strength
*/
const generateClientCredentials = () => ({
	clientId: randomBytes(16).toString("hex"),
	clientSecret: randomBytes(32).toString("hex")
});
/**
* Adds a new access key to a project.
*
* @param accessKeyData - The access key data.
* @param projectId - The ID of the project to add the access key to.
* @param user - The user adding the access key.
* @returns The new access key.
*
*/
const addNewAccessKey = async (accessKeyData, projectId, user) => {
	const { clientId, clientSecret } = generateClientCredentials();
	const newAccessKey = {
		...accessKeyData,
		clientId,
		clientSecret,
		userId: user.id,
		accessToken: [],
		grants: accessKeyData.grants
	};
	if ((await ProjectModel.updateOne({ _id: projectId }, { $push: { oAuth2Access: newAccessKey } })).modifiedCount === 0) throw new GenericError("ACCESS_KEY_CREATION_FAILED", {
		accessKeyData,
		projectId,
		userId: user.id
	});
	const newAccessKeyId = (await getProjectById(projectId)).oAuth2Access.find((access) => access.clientId === clientId);
	if (!newAccessKeyId) throw new GenericError("ACCESS_KEY_CREATION_FAILED", {
		accessKeyData,
		projectId,
		userId: user.id
	});
	return newAccessKeyId;
};
const deleteAccessKey = async (clientId, project, userId) => {
	const projectAccess = project.oAuth2Access.find((access) => access.clientId === clientId && String(access.userId) === String(userId));
	if (!projectAccess) throw new GenericError("ACCESS_KEY_NOT_FOUND", {
		clientId,
		projectId: project.id
	});
	if ((await ProjectModel.updateOne({
		"oAuth2Access.clientId": clientId,
		"oAuth2Access.userId": String(userId)
	}, { $pull: { oAuth2Access: { clientId } } })).modifiedCount === 0) throw new GenericError("ACCESS_KEY_DELETION_FAILED", {
		clientId,
		projectId: project.id
	});
	return projectAccess;
};
const refreshAccessKey = async (clientId, projectId, userId) => {
	const project = await ProjectModel.findOne({
		_id: projectId,
		"oAuth2Access.clientId": clientId,
		"oAuth2Access.userId": String(userId)
	});
	if (!project) throw new GenericError("PROJECT_NOT_FOUND", {
		clientId,
		projectId,
		userId
	});
	const projectAccess = project.oAuth2Access.find((access) => access.clientId === clientId);
	if (!projectAccess) throw new GenericError("ACCESS_KEY_NOT_FOUND", {
		clientId,
		projectId: project.id
	});
	const { clientSecret } = generateClientCredentials();
	if ((await ProjectModel.updateOne({
		"oAuth2Access.clientId": clientId,
		"oAuth2Access.userId": String(userId)
	}, { $set: {
		"oAuth2Access.$.clientId": projectAccess.clientId,
		"oAuth2Access.$.clientSecret": clientSecret
	} })).modifiedCount === 0) throw new GenericError("ACCESS_KEY_UPDATE_FAILED", {
		clientId,
		projectId
	});
	const updatedProject = await getProjectById(projectId);
	const newAccessKeyId = updatedProject.oAuth2Access.find((access) => access.clientId === projectAccess.clientId);
	if (!newAccessKeyId) throw new GenericError("ACCESS_KEY_CREATION_FAILED", {
		accessKeyData: updatedProject.oAuth2Access,
		projectId,
		userId
	});
	return newAccessKeyId;
};

//#endregion
export { addNewAccessKey, deleteAccessKey, refreshAccessKey };
//# sourceMappingURL=projectAccessKey.service.mjs.map