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

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

async function getAll() {
	try {
		const holidays = await dbSAPPS.Holiday.findAll({
			order: [["modified", "DESC"]],
			include: [
				{
					model: dbSAPPS.HolidayGroup,
					as: "holidaygroup",
					attributes: ["id", "display_name"],
				},
			],
		});

		return {
			holidays,
			success: true,
			message: "holidays loaded successfully!",
		};
	} catch (error) {
		const errorMessage = error.message || "Failed to load holidays!";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function getHolidayByHolidayGroupId(params) {
	const year = params.year;
	const companyId = params.company_id != null ? parseInt(params.company_id, 10) : null;
	const holidayGroupIdResult = await _getHolidayGroupIdByYear(year, companyId);
	if (!holidayGroupIdResult.success) {
		return holidayGroupIdResult;
	}

	const holidayGroupId = holidayGroupIdResult.holidayGroupId;

	try {
		const holidays = await dbSAPPS.Holiday.findAll({
			where: {
				holidaygroup_id: holidayGroupId,
			},
		});

		const is_weekend = holidays.filter((holiday) => holiday.is_weekend_holiday === true);
		const is_national = holidays.filter((holiday) => holiday.is_national_holiday === true);

		return {
			holidays,
			is_weekend,
			is_national,
			success: true,
			message: `holidays of year ${year} loaded successfully!`,
		};
	} catch (error) {
		const errorMessage = error.message || `Failed to load holidays of year ${year}!`;
		return {
			success: false,
			message: errorMessage,
		};
	}
}

const _getHolidayGroupIdByYear = async (year, companyId = null) => {
	try {
		const where = { display_name: "Holidays " + year };
		if (companyId != null && !Number.isNaN(companyId)) {
			where.company_id = companyId;
		}
		const holidayGroup = await dbSAPPS.HolidayGroup.findOne({
			where,
			attributes: ["id"],
		});

		if (!holidayGroup) {
			return {
				success: false,
				message: companyId != null ? `Holiday group of year ${year} for company is not found!` : `Holiday group of year ${year} is not found!`,
			};
		}

		return {
			holidayGroupId: holidayGroup.id,
			success: true,
			message: `Holiday group of year ${year} is found!`,
		};
	} catch (error) {
		const errorMessage = error.message || `Failed to get holiday group of year ${year}!`;
		return {
			success: false,
			message: errorMessage,
		};
	}
};

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

	if (params.display_name) {
		filterConditions.display_name = {
			[Op.like]: `%${params.display_name}%`,
		};
	}

	// Backward compatible query param: holiday_group_id (old) or holidaygroup_id (correct)
	const rawHolidayGroupId = params.holidaygroup_id ?? params.holiday_group_id;
	if (rawHolidayGroupId !== undefined && rawHolidayGroupId !== null && String(rawHolidayGroupId).length > 0) {
		const holidayGroupId = parseInt(rawHolidayGroupId, 10);
		filterConditions.holidaygroup_id = {
			[Op.eq]: Number.isNaN(holidayGroupId) ? rawHolidayGroupId : holidayGroupId,
		};
	}

	if (params.enabled) {
		filterConditions.enabled = {
			[Op.eq]: params.enabled === "1" ? true : false,
		};
	}

	try {
		const holidays = await dbSAPPS.Holiday.findAll({
			where: filterConditions,
			order: [["modified", "DESC"]],
			include: [
				{
					model: dbSAPPS.HolidayGroup,
					as: "holidaygroup",
					attributes: ["id", "display_name"],
				},
			],
		});

		return {
			success: true,
			holidays,
			message: "holiday loaded successfully!",
		};
	} catch (error) {
		console.error("Error retrieving holiday : ", error);
		const errorMessage = error.message || "Failed to retrieve holiday. Please try again later.";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function option() {
	try {
		const holidays = await dbSAPPS.Holiday.findAll({
			attributes: ["id", "display_name"],
			where: { enabled: true },
			order: [["display_name", "ASC"]],
			include: [
				{
					model: dbSAPPS.HolidayGroup,
					as: "holidaygroup",
					attributes: ["id", "display_name"],
				},
			],
		});

		return {
			success: true,
			options: holidays,
			holidays,
			message: "holiday loaded successfully!",
		};
	} catch (error) {
		console.error("Error retrieving holiday: ", error);
		const errorMessage = error.message || "Failed to retrieve holiday. Please try again later.";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function count() {
	try {
		const count = await dbSAPPS.Holiday.count({
			where: { enabled: true },
		});

		return {
			success: true,
			count,
			message: "holiday loaded successfully!",
		};
	} catch (error) {
		console.error("Error counting holiday: ", error);
		return {
			success: false,
			message: "Failed to retrieve holiday count. Please try again later.",
		};
	}
}

async function create(params) {
	try {
		if (!params.display_name)
			return {
				success: false,
				message: "Holiday is required!",
			};

		const existingHoliday = await dbSAPPS.Holiday.findOne({
			where: {
				display_name: params.display_name,
				holiday_date: params.holiday_date,
			},
		});
		if (existingHoliday)
			return {
				success: false,
				message: `Holiday of "${params.display_name}" is already taken.`,
			};

		if (!params.enabled) params.enabled = true;
		const newHoliday = await dbSAPPS.Holiday.create(params);

		return {
			success: true,
			message: "Data Holiday has been successfully adeded!",
			year: newHoliday,
		};
	} catch (error) {
		const errorMessage = error.message || "An error occurred during holiday creation.";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function update(id, params) {
	try {
		const holiday = await dbSAPPS.Holiday.findByPk(id);
		if (!holiday)
			return {
				success: false,
				message: "holiday not found!",
			};

		if ((params.display_name && params.display_name !== holiday.display_name, params.holiday_date && params.holiday_date !== holiday.holiday_date)) {
			const existingName = await dbSAPPS.Holiday.findOne({
				where: {
					display_name: params.display_name,
					holiday_date: params.holiday_date,
				},
			});
			if (existingName) {
				return {
					success: false,
					message: `holiday of "${params.display_name}" is already taken. Try again!`,
				};
			}
		}

		await holiday.update(params);

		return {
			success: true,
			message: "Your data holiday has been saved!",
		};
	} catch (error) {
		const errorMessage = error.message || "Failed to update data.";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function getByDate(params) {
	try {
		const include = [];
		if (params?.company_id !== undefined && params?.company_id !== null && String(params.company_id).length > 0) {
			const companyId = parseInt(params.company_id, 10);
			include.push({
				model: dbSAPPS.HolidayGroup,
				as: "holidaygroup",
				required: true,
				attributes: [],
				where: {
					company_id: Number.isNaN(companyId) ? params.company_id : companyId,
				},
			});
		}

		const holidays = await dbSAPPS.Holiday.findAll({
			where: {
				holiday_date: params?.date,
			},
			...(include.length ? { include } : {}),
		});

		return {
			holidays,
			success: true,
			message: `Holidays of date ${params?.date} has been loaded!`,
		};
	} catch (error) {
		const errorMessage = error?.message || "Failed to load holidays!";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function enabled(id, params) {
	try {
		const holiday = await dbSAPPS.Holiday.findByPk(id);
		if (!holiday)
			return {
				success: false,
				message: "Holiday not found!",
			};

		const updateData = {};
		updateData.enabled = params.enabled;
		if (params.modified_by) updateData.modified_by = params.modified_by;
		if (params.modified) updateData.modified = params.modified;

		await holiday.update(updateData);

		return {
			success: true,
			message: "Holiday group has been updated!",
		};
	} catch (error) {
		const errorMessage = error.message || "Failed to Update Holiday.";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function _delete(id) {
	try {
		const holiday = await dbSAPPS.Holiday.findByPk(id);
		if (!holiday) return { success: false, message: "Holiday not found!" };

		await holiday.destroy();

		return {
			success: true,
			message: "Holiday successfully deleted!",
		};
	} catch (error) {
		const errorMessage = error.message || "Failed to delete holiday.";
		return {
			success: false,
			message: errorMessage,
		};
	}
}
