import { logger } from "../logger/index.mjs";
import { formatPaginatedResponse, formatResponse } from "../utils/responseData.mjs";
import { ErrorHandler } from "../utils/errors/ErrorHandler.mjs";
import { countProjects, createProject, deleteProjectById, findProjects, getProjectById, updateProjectById } from "../services/project.service.mjs";
import { hasPermission } from "../utils/permissions.mjs";
import { getUsersByIds } from "../services/user.service.mjs";
import { SessionModel } from "../models/session.model.mjs";
import { getPlanDetails } from "../utils/plan.mjs";
import { getProjectFiltersAndPagination } from "../utils/filtersAndPagination/getProjectFiltersAndPagination.mjs";
import { mapProjectToAPI, mapProjectsToAPI } from "../utils/mapper/project.mjs";
import { t } from "express-intlayer";

//#region src/controllers/project.controller.ts
/**
* Retrieves a list of projects based on filters and pagination.
*/
const getProjects = async (req, res, _next) => {
	const { user, organization, roles } = res.locals;
	const { filters, sortOptions, pageSize, skip, page, getNumberOfPages } = getProjectFiltersAndPagination(req, res);
	if (!user) {
		ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
		return;
	}
	if (!organization && !roles.includes("admin")) {
		ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
		return;
	}
	try {
		const projects = await findProjects(filters, skip, pageSize, sortOptions);
		if (!hasPermission(roles, "project:read")({
			...res.locals,
			targetProjects: projects
		})) {
			ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
			return;
		}
		const totalItems = await countProjects(filters);
		const responseData = formatPaginatedResponse({
			data: mapProjectsToAPI(projects),
			page,
			pageSize,
			totalPages: getNumberOfPages(totalItems),
			totalItems
		});
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};
/**
* Adds a new project to the database.
*/
const addProject = async (req, res, _next) => {
	const { organization, user, roles } = res.locals;
	const projectData = req.body;
	if (!user) {
		ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
		return;
	}
	if (!organization) {
		ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
		return;
	}
	if (!projectData) ErrorHandler.handleGenericErrorResponse(res, "PROJECT_DATA_NOT_FOUND");
	if (!hasPermission(roles, "organization:admin")({
		...res.locals,
		targetOrganizations: [organization]
	})) {
		ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
		return;
	}
	const { plan } = organization;
	const planType = getPlanDetails(plan);
	if (planType.numberOfProjects) {
		if (await countProjects({ organizationId: organization.id }) >= planType.numberOfProjects) {
			ErrorHandler.handleGenericErrorResponse(res, "PLAN_PROJECT_LIMIT_REACHED", { organizationId: organization.id });
			return;
		}
	}
	const project = {
		membersIds: [user.id],
		adminsIds: [user.id],
		creatorId: user.id,
		organizationId: organization.id,
		...projectData
	};
	try {
		const formattedProject = mapProjectToAPI(await createProject(project));
		const responseData = formatResponse({
			message: t({
				en: "Project created successfully",
				fr: "Projet créé avec succès",
				es: "Proyecto creado con éxito"
			}),
			description: t({
				en: "Your project has been created successfully",
				fr: "Votre projet a été créé avec succès",
				es: "Su proyecto ha sido creado con éxito"
			}),
			data: formattedProject
		});
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};
/**
* Updates an existing project in the database.
*/
const updateProject = async (req, res, _next) => {
	const { organization, project, user, roles } = res.locals;
	const projectData = req.body;
	if (!user) {
		ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
		return;
	}
	if (!project) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_DATA_NOT_FOUND");
		return;
	}
	if (!organization) {
		ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
		return;
	}
	if (String(project.organizationId) !== String(organization.id)) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_IN_ORGANIZATION");
		return;
	}
	if (!hasPermission(roles, "project:write")({
		...res.locals,
		targetProjectIds: [String(project.id)]
	})) {
		ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
		return;
	}
	try {
		const formattedProject = mapProjectToAPI(await updateProjectById(project.id, projectData));
		const responseData = formatResponse({
			message: t({
				en: "Project updated successfully",
				fr: "Projet mis à jour avec succès",
				es: "Proyecto actualizado con éxito"
			}),
			description: t({
				en: "Your project has been updated successfully",
				fr: "Votre projet a été mis à jour avec succès",
				es: "Su proyecto ha sido actualizado con éxito"
			}),
			data: formattedProject
		});
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};
/**
* Update members to the dictionary in the database.
*/
const updateProjectMembers = async (req, res, _next) => {
	const { user, project, organization, roles } = res.locals;
	const { membersIds } = req.body;
	if (!user) {
		ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
		return;
	}
	if (!project) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
		return;
	}
	if (!organization) {
		ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
		return;
	}
	if (membersIds?.length === 0) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_MUST_HAVE_MEMBER");
		return;
	}
	if (membersIds?.map((el) => el.isAdmin)?.length === 0) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_MUST_HAVE_ADMIN");
		return;
	}
	if (!hasPermission(roles, "project:write")({
		...res.locals,
		targetProjectIds: [String(project.id)]
	})) {
		ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
		return;
	}
	try {
		const existingUsers = [];
		if (membersIds) {
			const userIdList = membersIds?.filter((member) => !organization?.membersIds.includes(member.userId)).map((member) => member.userId);
			const users = await getUsersByIds(userIdList);
			if (users) {
				const userMap = users.map((user$1) => ({
					user: user$1,
					isAdmin: membersIds.find((member) => String(member.userId) === String(user$1.id))?.isAdmin ?? false
				}));
				existingUsers.push(...userMap);
			}
		}
		const formattedMembers = existingUsers.map((user$1) => user$1.user.id);
		const formattedAdmin = existingUsers.filter((el) => el.isAdmin).map((user$1) => user$1.user.id);
		const formattedProject = mapProjectToAPI(await updateProjectById(project.id, {
			...project,
			membersIds: formattedMembers,
			adminsIds: formattedAdmin
		}));
		const responseData = formatResponse({
			message: t({
				en: "Project members updated successfully",
				fr: "Membres du projet mis à jour avec succès",
				es: "Miembros del proyecto actualizados con éxito"
			}),
			description: t({
				en: "Your project members have been updated successfully",
				fr: "Les membres de votre projet ont été mis à jour avec succès",
				es: "Los miembros de su proyecto han sido actualizados con éxito"
			}),
			data: formattedProject
		});
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};
/**
* Pushes a project configuration to the database.
* @param req - Express request object.
* @param  res - Express response object.
* @returns Response confirming the deletion.
*/
const pushProjectConfiguration = async (req, res, _next) => {
	const { user, project, roles } = res.locals;
	const projectConfiguration = req.body;
	if (!user) {
		ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
		return;
	}
	if (!project) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
		return;
	}
	if (!hasPermission(roles, "project:write")({
		...res.locals,
		targetProjectIds: [String(project.id)]
	})) {
		ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
		return;
	}
	try {
		const projectObject = await getProjectById(project.id);
		projectObject.configuration = projectConfiguration;
		projectObject.save();
		if (!projectObject.configuration) {
			ErrorHandler.handleGenericErrorResponse(res, "PROJECT_UPDATE_FAILED", { projectId: project.id });
			return;
		}
		const responseData = formatResponse({
			message: t({
				en: "Project configuration updated successfully",
				fr: "Configuration du projet mise à jour avec succès",
				es: "Configuración del proyecto actualizada con éxito"
			}),
			description: t({
				en: "Your project configuration has been updated successfully",
				fr: "La configuration du projet a été mise à jour avec succès",
				es: "Su configuración del proyecto ha sido actualizada con éxito"
			}),
			data: projectObject.configuration
		});
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};
/**
* Deletes a project from the database by its ID.
* @param req - Express request object.
* @param  res - Express response object.
* @returns Response confirming the deletion.
*/
const deleteProject = async (_req, res, _next) => {
	const { user, organization, project, session, roles } = res.locals;
	if (!user) {
		ErrorHandler.handleGenericErrorResponse(res, "USER_NOT_DEFINED");
		return;
	}
	if (!organization) {
		ErrorHandler.handleGenericErrorResponse(res, "ORGANIZATION_NOT_DEFINED");
		return;
	}
	if (!project) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED");
		return;
	}
	if (typeof session === "undefined") {
		ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
		return;
	}
	if (!hasPermission(roles, "project:admin")({
		...res.locals,
		targetProjectIds: [String(project.id)]
	})) {
		ErrorHandler.handleGenericErrorResponse(res, "PERMISSION_DENIED");
		return;
	}
	try {
		const projectToDelete = await getProjectById(project.id);
		if (String(projectToDelete.organizationId) !== String(organization.id)) {
			ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_IN_ORGANIZATION");
			return;
		}
		const deletedProject = await deleteProjectById(project.id);
		if (!deletedProject) {
			ErrorHandler.handleGenericErrorResponse(res, "PROJECT_NOT_DEFINED", { projectId: project.id });
			return;
		}
		logger.info(`Project deleted: ${String(deletedProject.id)}`);
		const responseData = formatResponse({
			message: t({
				en: "Project deleted successfully",
				fr: "Projet supprimé avec succès",
				es: "Proyecto eliminado con éxito"
			}),
			description: t({
				en: "Your project has been deleted successfully",
				fr: "Votre projet a été supprimé avec succès",
				es: "Su proyecto ha sido eliminado con éxito"
			}),
			data: mapProjectToAPI(deletedProject)
		});
		await SessionModel.updateOne({ _id: session.id }, { $set: { activeProjectId: null } });
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};
/**
* Select a project.
*/
const selectProject = async (req, res, _next) => {
	const { projectId } = req.params;
	const { session } = res.locals;
	if (!projectId) {
		ErrorHandler.handleGenericErrorResponse(res, "PROJECT_ID_NOT_FOUND");
		return;
	}
	if (typeof session === "undefined") {
		ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
		return;
	}
	try {
		const project = await getProjectById(projectId);
		await SessionModel.updateOne({ _id: session.id }, { $set: { activeProjectId: String(projectId) } });
		const responseData = formatResponse({
			message: t({
				en: "Project selected successfully",
				fr: "Projet sélectionné avec succès",
				es: "Proyecto seleccionado con éxito"
			}),
			description: t({
				en: "Your project has been selected successfully",
				fr: "Votre projet a été sélectionné avec succès",
				es: "Su proyecto ha sido seleccionado con éxito"
			}),
			data: mapProjectToAPI(project)
		});
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};
/**
* Unselect a project.
*/
const unselectProject = async (_req, res, _next) => {
	const { session } = res.locals;
	if (typeof session === "undefined") {
		ErrorHandler.handleGenericErrorResponse(res, "SESSION_NOT_DEFINED");
		return;
	}
	try {
		await SessionModel.updateOne({ _id: session.id }, { $set: { activeProjectId: null } });
		const responseData = formatResponse({
			message: t({
				en: "Project unselected successfully",
				fr: "Projet désélectionné avec succès",
				es: "Proyecto deseleccionado con éxito"
			}),
			description: t({
				en: "Your project has been unselected successfully",
				fr: "Votre projet a été désélectionné avec succès",
				es: "Su proyecto ha sido deseleccionado con éxito"
			}),
			data: null
		});
		res.json(responseData);
		return;
	} catch (error) {
		ErrorHandler.handleAppErrorResponse(res, error);
		return;
	}
};

//#endregion
export { addProject, deleteProject, getProjects, pushProjectConfiguration, selectProject, unselectProject, updateProject, updateProjectMembers };
//# sourceMappingURL=project.controller.mjs.map