const dbSAPPS = require("../../helpers/db");
require("dotenv").config();
const { Op } = require("sequelize");

module.exports = {
	create,
	getAll,
	option,
	count,
	update,
	enabled,
	delete: _delete,
};

const formatWithModifier = async (jobRoles) => {
	return Promise.all(
		jobRoles.map(async (jobRole) => {
			const modifier = await dbSAPPS.User.findOne({
				where: { id: jobRole.modified_by },
				attributes: ["full_name"],
			});

			return {
				...jobRole,
				modifier: modifier?.full_name,
			};
		}),
	);
};

async function getAll(params) {
	try {
		const filterConditions = {};
		const andConditions = [];

		// precedence: company_id wins over companiesId
		if (params.company_id != null && String(params.company_id).trim() !== "") {
			filterConditions.company_id = { [Op.eq]: Number(params.company_id) };
		} else if (Array.isArray(params.companiesId) && params.companiesId.length > 0) {
			filterConditions.company_id = { [Op.in]: params.companiesId };
		}

		const q = params.q ? String(params.q).trim() : "";
		if (q) {
			andConditions.push({
				[Op.or]: [{ name: { [Op.like]: `%${q}%` } }, { display_name: { [Op.like]: `%${q}%` } }, { "$company.display_name$": { [Op.like]: `%${q}%` } }],
			});
		}

		if (params.f_name) {
			andConditions.push({ name: { [Op.like]: `%${String(params.f_name).trim()}%` } });
		}
		if (params.f_display_name) {
			andConditions.push({ display_name: { [Op.like]: `%${String(params.f_display_name).trim()}%` } });
		}
		if (params.f_company) {
			andConditions.push({ "$company.display_name$": { [Op.like]: `%${String(params.f_company).trim()}%` } });
		}

		const where = { ...filterConditions };
		if (andConditions.length) where[Op.and] = andConditions;

		let jobRoles = await dbSAPPS.JobRole.findAll({
			where,
			order: [["modified", "DESC"]],
			include: [{ model: dbSAPPS.Company, as: "company", attributes: ["id", "display_name"], required: false }],
		});

		jobRoles = jobRoles.map((jr) => ({
			...jr.dataValues,
			company_name: jr?.company?.display_name,
		}));

		jobRoles = await formatWithModifier(jobRoles);

		return { jobRoles, success: true, message: "Loaded successfully!" };
	} catch (error) {
		return { success: false, message: error?.message || "Failed to load, please try again!" };
	}
}

async function option(params) {
	try {
		const filterConditions = {};
		// precedence: company_id wins over companiesId
		if (params.company_id != null && String(params.company_id).trim() !== "") {
			filterConditions.company_id = { [Op.eq]: Number(params.company_id) };
		} else if (Array.isArray(params.companiesId) && params.companiesId.length > 0) {
			filterConditions.company_id = { [Op.in]: params.companiesId };
		}
		filterConditions.enabled = { [Op.eq]: true };

		let options = await dbSAPPS.JobRole.findAll({
			where: filterConditions,
			attributes: ["id", "name", "display_name", "company_id"],
			include: [{ model: dbSAPPS.Company, as: "company", attributes: ["id", "name", "display_name"], required: false }],
			order: [["name", "ASC"]],
		});

		options = options.map((o) => ({
			...o.dataValues,
			company_name: o?.company?.display_name,
		}));

		return { options, success: true, message: "Loaded successfully!" };
	} catch (error) {
		return { success: false, message: error?.message || "Failed to load, please try again!" };
	}
}

async function count() {
	try {
		const count = await dbSAPPS.JobRole.count({ where: { enabled: { [Op.eq]: true } } });
		return { count, success: true, message: "Loaded successfully!" };
	} catch (error) {
		return { success: false, message: error?.message || "Failed to load, please try again!" };
	}
}

async function create(params) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		const existingName = await dbSAPPS.JobRole.findOne({ where: { name: params.name, company_id: params.company_id }, transaction });
		if (existingName) return { success: false, message: `"${params.name}" is already taken.` };

		const existingDisplayName = await dbSAPPS.JobRole.findOne({
			where: { display_name: params.display_name, company_id: params.company_id },
			transaction,
		});
		if (existingDisplayName) return { success: false, message: `"${params.display_name}" is already taken.` };

		await dbSAPPS.JobRole.create(params, { transaction });
		await transaction.commit();
		return { success: true, message: "Saved successfully!" };
	} catch (error) {
		await transaction.rollback();
		return { success: false, message: error?.message || "Failed to save, please try again!" };
	}
}

async function update(id, params) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		const jobRole = await dbSAPPS.JobRole.findByPk(id, { transaction });
		if (!jobRole) return { success: false, message: "Job Role not found." };

		if (params.name && params.name !== jobRole.name) {
			const existingName = await dbSAPPS.JobRole.findOne({
				where: { id: { [Op.ne]: id }, name: params.name, company_id: jobRole.company_id },
				transaction,
			});
			if (existingName) return { success: false, message: `"${params.name}" is already taken.` };
		}

		if (params.display_name && params.display_name !== jobRole.display_name) {
			const existingDisplayName = await dbSAPPS.JobRole.findOne({
				where: { id: { [Op.ne]: id }, display_name: params.display_name, company_id: jobRole.company_id },
				transaction,
			});
			if (existingDisplayName) return { success: false, message: `"${params.display_name}" is already taken.` };
		}

		await jobRole.update(params, { transaction });
		await transaction.commit();
		return { success: true, message: "Updated successfully!" };
	} catch (error) {
		await transaction.rollback();
		return { success: false, message: error?.message || "Failed to update, please try again!" };
	}
}

async function enabled(id, params) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		const jobRole = await dbSAPPS.JobRole.findByPk(id, { transaction });
		if (!jobRole) return { success: false, message: "Job Role not found." };

		await jobRole.update({ enabled: !!params.enabled }, { transaction });
		await transaction.commit();
		return { success: true, message: "Updated successfully!" };
	} catch (error) {
		await transaction.rollback();
		return { success: false, message: error?.message || "Failed to update, please try again!" };
	}
}

async function _delete(id) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		const jobRole = await dbSAPPS.JobRole.findByPk(id, { transaction });
		if (!jobRole) return { success: false, message: "Job Role not found." };

		await jobRole.destroy({ transaction });
		await transaction.commit();
		return { success: true, message: "Deleted successfully!" };
	} catch (error) {
		await transaction.rollback();
		return { success: false, message: error?.message || "Failed to delete, please try again!" };
	}
}
