const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
const dbSAPPS = require("../../helpers/db");
require("dotenv").config();
const config = require("../../../../config.json");
const { Op } = require("sequelize");

// Cache for designation versions
const designationVersionCache = new Map();
const VERSION_CACHE_TTL = 10 * 60 * 1000; // 10 minutes

module.exports = {
	getDesignationHierarchy,
};

// Fungsi untuk mendapatkan hierarki jabatan karyawan

// Contoh penggunaan:
// const user = {
//     employee: {
//         id: 1,
//         company_id: 1,
//         designation_id: 10
//     }
// };

/**
 * Fungsi utama untuk mendapatkan hierarki jabatan karyawan
 * @param {Object} user - Data user yang berisi informasi employee
 * @returns {Object} - Objek yang berisi semua data hierarki
 */
async function getDesignationHierarchy(user) {
	// Inisialisasi semua variabel
	const hierarchyData = {
		employeeDesignation: null,
		designationVersion: [],
		designationVersionChilds: [],
		designationParent: [],
		designationChild: [],
		designations: [],
		hierarchyDesignations: [],
		employeeDesignationParent: [],
		workflowDesignations: [],
		employeeDesignationChild: [],
		subCoordinateDesignations: [],
		subCoordinateEmployeeDesignations: [],
		designationsIds: [],
		workflowDesignationDirect: [],
	};

	try {
		// Step 1: Dapatkan designation employee
		await getEmployeeDesignation(user, hierarchyData);

		// Step 2: Dapatkan versi designation dan children-nya
		await getDesignationVersions(user, hierarchyData);

		// Step 3: Bangun hierarki dan data terkait
		buildHierarchyData(hierarchyData);

		// Step 4: Dapatkan data employee parent
		await getEmployeeDesignationParents(hierarchyData);

		// Step 5: Dapatkan data employee child
		await getEmployeeDesignationChildren(hierarchyData);

		// Step 6: Dapatkan data employee parent direct
		await getDirectParent(hierarchyData);

		return {
			designations: hierarchyData.designations,
			hierarchyDesignations: hierarchyData.hierarchyDesignations,
			workflowDesignations: hierarchyData.workflowDesignations,
			subCoordinateDesignations: hierarchyData.subCoordinateDesignations,
			subCoordinateEmployeeDesignations:
				hierarchyData.subCoordinateEmployeeDesignations,
			workflowDesignationDirect: hierarchyData.workflowDesignationDirect,
			success: true,
			message: "Loaded successfully!",
		};
	} catch (error) {
		const errorMessage = error?.message || "Failed to load, please try again!";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

/**
 * Mendapatkan designation dari employee yang bersangkutan
 */
async function getEmployeeDesignation(user, hierarchyData) {
	if (user?.employee?.designation_id) {
		hierarchyData.employeeDesignation = await dbSAPPS.Designation.findOne({
			attributes: ["id", "display_name"],
			where: { id: user.employee.designation_id },
		});
	}
}

/**
 * Mendapatkan semua versi designation yang valid untuk perusahaan employee
 */
async function getDesignationVersions(user, hierarchyData) {
	if (
		user?.employee?.id &&
		user?.employee?.company_id &&
		hierarchyData.employeeDesignation
	) {
        const companyId = user.employee.company_id;
        const now = Date.now();

        // Check cache
        const cached = designationVersionCache.get(companyId);
        let getDesignationVersion;

        if (cached && (now - cached.timestamp < VERSION_CACHE_TTL)) {
            getDesignationVersion = cached.data;
        } else {
            const today = new Date();
            getDesignationVersion = await dbSAPPS.DesignationVersion.findAll({
                attributes: ["id", "display_name", "valid_from", "valid_to", "enabled"],
                where: {
                    [Op.and]: [
                        { company_id: companyId },
                        { enabled: true },
                        { valid_from: { [Op.lte]: today } },
                        { [Op.or]: [{ valid_to: { [Op.gte]: today } }, { valid_to: null }] },
                    ],
                },
                include: [
                    {
                        model: dbSAPPS.DesignationVersionChild,
                        as: "designationversionchilds",
                        attributes: [
                            "id",
                            "name",
                            "parent_id",
                            "designation_id",
                            "display_name",
                        ],
                    },
                ],
            });

            if (getDesignationVersion) {
                designationVersionCache.set(companyId, {
                    timestamp: now,
                    data: getDesignationVersion
                });
            }
        }

		if (getDesignationVersion?.length > 0) {
			hierarchyData.designationVersion = getDesignationVersion;
			hierarchyData.designationVersionChilds = getDesignationVersion.flatMap(
				(version) => version.designationversionchilds
			);
		}
	}
}

/**
 * Membangun struktur data hierarki
 */
function buildHierarchyData(hierarchyData) {
	// Fungsi rekursif untuk membangun hierarki
	const buildHierarchy = (parent_id = null) => {
		const children = hierarchyData.designationVersionChilds.filter(
			(c) => c.parent_id === parent_id
		);
		return children.map((child) => ({
			id: child.designation_id,
			name: child.display_name,
			display_name: child.display_name,
			children: buildHierarchy(child.designation_id),
		}));
	};

	// Fungsi untuk mendapatkan parent hierarchy
	const getParentHierarchy = (designation_id) => {
		const hierarchy = [];
		const findParent = (id) => {
			const parent = hierarchyData.designationVersionChilds.find(
				(c) => c.designation_id === id
			);
			if (parent?.parent_id) {
				if (parent.designation_id !== designation_id) {
					hierarchy.push({
						id: parent.designation_id,
						name: parent.display_name,
					});
				}
				findParent(parent.parent_id);
			} else {
				hierarchy.push({
					id,
					name: parent?.display_name,
				});
			}
		};

		findParent(designation_id);
		return hierarchy.filter((item) => item.id !== designation_id);
	};

	// Membangun hierarki utama
	hierarchyData.hierarchyDesignations = buildHierarchy();

	// Membangun data khusus untuk employee designation jika ada
	if (hierarchyData.employeeDesignation) {
		const empDesId = hierarchyData.employeeDesignation.id;
		hierarchyData.designationChild = buildHierarchy(empDesId);
		hierarchyData.designations = [
			{
				id: empDesId,
				name: hierarchyData.employeeDesignation.display_name,
				children: hierarchyData.designationChild,
			},
		];
		hierarchyData.designationParent = getParentHierarchy(empDesId);
	}
}

/**
 * Mendapatkan data employee yang memiliki designation parent
 */
async function getEmployeeDesignationParents(hierarchyData) {
	if (hierarchyData.designationParent?.length > 0) {
		const parentIds = hierarchyData.designationParent.map((t) => t.id);
		hierarchyData.employeeDesignationParent = await dbSAPPS.Employee.findAll({
			attributes: ["id", "designation_id", "employee_name", "employee_number"],
			where: { designation_id: parentIds },
			include: [
				{
					model: dbSAPPS.Designation,
					as: "designation",
					attributes: ["id", "display_name"],
				},
				{
					model: dbSAPPS.User,
					as: "user",
					attributes: ["id", "email", "username", "full_name"],
				},
			],
		});

		if (hierarchyData.employeeDesignationParent.length > 0) {
			// Urutkan berdasarkan hierarchy
			hierarchyData.employeeDesignationParent.sort(
				(a, b) =>
					hierarchyData.designationParent.findIndex(
						(t) => t.id === a.designation_id
					) -
					hierarchyData.designationParent.findIndex(
						(t) => t.id === b.designation_id
					)
			);

			// Mapping data workflow
			hierarchyData.workflowDesignations =
				hierarchyData.employeeDesignationParent.map((edp) => ({
					employee_id: edp.id,
					employee_name: edp.employee_name,
					employee_number: edp.employee_number,
					designation_id: edp.designation_id,
					designation_name: edp.designation?.display_name,
					user_id: edp.user?.id,
					email: edp.user?.email,
					username: edp.user?.username,
					full_name: edp.user?.full_name,
				}));
		}
	}
}

/**
 * Mendapatkan data employee yang memiliki designation child
 */
async function getEmployeeDesignationChildren(hierarchyData) {
	if (hierarchyData.designationChild?.length > 0) {
		// Fungsi untuk mendapatkan semua ids dari hierarki
		const getAllDesignationIds = (arr) => {
			const ids = new Set();
			const addIds = (items) => {
				items.forEach((item) => {
					ids.add(item.id);
					if (item.children?.length) addIds(item.children);
				});
			};
			addIds(arr);
			return Array.from(ids);
		};

		hierarchyData.designationsIds = getAllDesignationIds(
			hierarchyData.designations
		);

		hierarchyData.employeeDesignationChild = await dbSAPPS.Employee.findAll({
			attributes: ["id", "designation_id"],
			where: { designation_id: { [Op.in]: hierarchyData.designationsIds } },
			include: [
				{
					model: dbSAPPS.Designation,
					as: "designation",
					attributes: ["id", "display_name"],
				},
				{
					model: dbSAPPS.User,
					as: "user",
					attributes: ["id", "email", "username", "full_name"],
				},
			],
		});

		if (hierarchyData.employeeDesignationChild.length > 0) {
			// Urutkan berdasarkan parent hierarchy jika ada
			if (hierarchyData.designationParent?.length) {
				hierarchyData.employeeDesignationChild.sort(
					(a, b) =>
						hierarchyData.designationParent.findIndex(
							(t) => t.id === a.designation_id
						) -
						hierarchyData.designationParent.findIndex(
							(t) => t.id === b.designation_id
						)
				);
			}

			hierarchyData.subCoordinateDesignations =
				hierarchyData.employeeDesignationChild.map((edp) => ({
					employee_id: edp.id,
					employee_name: edp.employee_name,
					employee_number: edp.employee_number,
					designation_id: edp.designation_id,
					designation_name: edp.designation?.display_name,
					user_id: edp.user?.id,
					email: edp.user?.email,
					username: edp.user?.username,
					full_name: edp.user?.full_name,
				}));

			if (hierarchyData.subCoordinateDesignations) {
				hierarchyData.subCoordinateEmployeeDesignations =
					hierarchyData.subCoordinateDesignations.map((e) => e.employee_id);
			}
		}
	}
}

/**
 * Mendapatkan direct parent (1 tingkat di atas)
 */
async function getDirectParent(hierarchyData) {
	if (!hierarchyData.employeeDesignation) return;

	// Cari direct parent dari designation employee
	const directParent = hierarchyData.designationVersionChilds.find(
		(child) => child.designation_id === hierarchyData.employeeDesignation.id
	);

	if (directParent?.parent_id) {
		// Dapatkan informasi designation parent
		const parentDesignation = await dbSAPPS.Designation.findOne({
			attributes: ["id", "display_name"],
			where: { id: directParent.parent_id },
		});

		if (parentDesignation) {
			// Dapatkan employee dengan designation parent tersebut
			const directParentEmployees = await dbSAPPS.Employee.findAll({
				attributes: ["id", "designation_id"],
				where: { designation_id: parentDesignation.id },
				include: [
					{
						model: dbSAPPS.Designation,
						as: "designation",
						attributes: ["id", "display_name"],
					},
					{
						model: dbSAPPS.User,
						as: "user",
						attributes: ["id", "email", "username", "full_name"],
					},
				],
			});

			// Format data workflow direct
			hierarchyData.workflowDesignationDirect = directParentEmployees.map(
				(employee) => ({
					employee_id: employee.id,
					designation_id: employee.designation_id,
					designation_name: employee.designation?.display_name,
					user_id: employee.user?.id,
					email: employee.user?.email,
					username: employee.user?.username,
					full_name: employee.user?.full_name,
				})
			);
		}
	}
}
