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

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

/**
 * Format an array of holidayLists by appending a modifier field to each company.
 */
const formatWithModifier = async (holidayLists) => {
	return Promise.all(
		holidayLists.map(async (holidayList) => {
			const modifier = await dbSAPPS.User.findOne({
				where: {
					id: holidayList.modified_by,
				},
				attributes: ["full_name"],
			});

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

/**
 * Retrieves all holidayLists with their parent holidayList title.
 */
async function getAll(params) {
	try {
		// filter
		const filterConditions = {};

		if (params?.companiesId) {
			filterConditions.company_id = {
				[Op.in]: params?.companiesId,
			};
		}

		let holidayLists = [];
		holidayLists = await dbSAPPS.HolidayList.findAll({
			where: filterConditions,
			order: [["modified", "DESC"]],
			include: [
				{
					model: dbSAPPS.Company,
					as: "company",
					attributes: ["id", "name", "display_name"],
				},
				{
					model: dbSAPPS.HolidayListItem,
					as: "holidaylistitem",
				},
			],
		});

		holidayLists = holidayLists.map((holidayList) => {
			return {
				...holidayList.dataValues,
				company_name: holidayList?.company?.display_name,
			};
		});

		holidayLists = await formatWithModifier(holidayLists);

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

/**
 * Get holidayList items with their respective settings.
 */
async function option(params) {
	try {
		// filter
		const filterConditions = {};

		if (params.holidaylist_id) {
			filterConditions.id = {
				[Op.eq]: parseInt(params.holidaylist_id, 10),
			};
		}

		const raw = params?.companiesId;
		const companiesId = Array.isArray(raw)
			? raw.map((id) => parseInt(id, 10)).filter((n) => !isNaN(n))
			: [];
		if (companiesId.length > 0) {
			filterConditions.company_id = {
				[Op.in]: companiesId,
			};
		}

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

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

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

/**
 * Get holidayListItems by hilodayDate.
 */
async function getHolidayListItemByDate(params) {
	try {
		// filter
		const filterConditions = {};

		if (params.from_date && params.to_date) {
			// Filter holiday_date antara fromDate dan toDate (inclusive)
			filterConditions.holiday_date = {
				[Op.between]: [params.from_date, params.to_date],
			};
		}

		if (params.holiday_date || params.date) {
			filterConditions.holiday_date = {
				[Op.eq]: params.holiday_date || params.date,
			};
		}

		// Filter berdasarkan tahun jika params.year ada
		if (params.year) {
			// Tambahkan kondisi ekstrak tahun dari holiday_date sama dengan params.year
			filterConditions[Op.and] = filterConditions[Op.and] || [];
			filterConditions[Op.and].push(where(fn("YEAR", col("holiday_date")), params.year));
		}

		let holidayListItems = [];
		holidayListItems = await dbSAPPS.HolidayListItem.findAll({
			attributes: [
				"id",
				"holiday_date",
				"display_name",
				"description",
				"weekly_off",
				"is_national_holiday",
				"is_joint_holiday",
				"is_weekend_holiday",
				"company_id",
				"holidaylist_id",
			],
			where: filterConditions,
			order: [["holiday_date", "ASC"]],
			include: [
				{
					model: dbSAPPS.Company,
					as: "company",
					attributes: ["id", "name", "display_name"],
				},
				{
					model: dbSAPPS.HolidayList,
					as: "holidaylist",
					attributes: ["id", "name", "display_name", "from_date", "to_date", "description", "total_holidays", "weekly_off", "company_id"],
				},
			],
		});

		holidayListItems = holidayListItems.map((holidayListItem) => {
			return {
				...holidayListItem.dataValues,
				company_name: holidayListItem?.company?.display_name,
				holidaylist_name: holidayListItem?.holidaylist?.display_name,
			};
		});

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

/**
 * Count active holidayList items
 */

async function count(params) {
	try {
		// filter
		const filterConditions = {};

		const count = await dbSAPPS.HolidayList.count({
			where: filterConditions,
		});

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

/**
 * Creates a new holidayList item.
 */
async function create(params) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		// validate existing
		const existingDisplayName = await dbSAPPS.HolidayList.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.`,
			};
		}

		// save
		const holidayList = await dbSAPPS.HolidayList.create(params, {
			transaction,
		});

		if (Array.isArray(params.holidays) && params.holidays.length > 0) {
			// create holidays
			const holidaysData = params.holidays.map((holiday) => ({
				...holiday,
				holidaylist_id: holidayList?.id,
				company_id: params.company_id,
			}));

			// save
			await dbSAPPS.HolidayListItem.bulkCreate(holidaysData, { transaction });
		}

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

/**
 * Updates an existing holidayList item.
 */
async function update(id, params) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		// validate existing
		const holidayList = await dbSAPPS.HolidayList.findByPk(id);
		if (!holidayList) return { success: false, message: "ID not found!" };

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

		// save
		await holidayList.update(params, { transaction });

		if (Array.isArray(params.holidays) && params.holidays.length > 0) {
			await dbSAPPS.HolidayListItem.destroy({
				where: { holidaylist_id: id },
				transaction,
			});

			// create holidays
			const holidaysData = params.holidays.map((holiday) => ({
				...holiday,
				holidaylist_id: JSON.parse(id),
				company_id: holiday.company_id || params.company_id,
			}));

			// save
			await dbSAPPS.HolidayListItem.bulkCreate(holidaysData, { transaction });
		} else {
			// delete holidays
			await dbSAPPS.HolidayListItem.destroy({
				where: { holidaylist_id: id },
				transaction,
			});
		}

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

/**
 * Delete a holidayList
 */
async function _delete(id) {
	const transaction = await dbSAPPS.sequelize.transaction();
	try {
		// validate existing
		const holidayList = await dbSAPPS.HolidayList.findByPk(id);
		if (!holidayList) return { success: false, message: "ID not found!" };

		// validate used in leavePeriod
		const usedInLeavePeriod = await dbSAPPS.LeavePeriod.count({
			where: {
				holidaylist_id: id,
			},
			transaction,
		});
		if (usedInLeavePeriod > 0) {
			throw new Error(`This holiday list is being used in Leave Period, cannot be deleted!`);
		}

		// delete holidaylistitem
		await dbSAPPS.HolidayListItem.destroy({
			where: { holidaylist_id: id },
			transaction,
		});

		// delete
		await holidayList.destroy({ transaction });

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