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

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

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

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

async function getAll(params) {
	try {
		console.log("params rn", params);
		const filterConditions = {};

		// Filtering by display_name (iLike)
		if (params?.display_name) {
			filterConditions.display_name = { [Op.iLike]: `%${params.display_name}%` };
		}

		// Filtering by version (iLike)
		if (params?.version) {
			filterConditions.version = { [Op.iLike]: `%${params.version}%` };
		}

		// Filtering by release_type (exact)
		if (params?.release_type) {
			filterConditions.release_type = { [Op.eq]: params.release_type };
		}

		// Filtering by release_date range
		if (params?.release_date) {
			filterConditions.release_date = {
				[Op.eq]: params.release_date,
			};
		}

		// Enabled filter precedence: explicit param > role-based access
		if (typeof params.enabled !== "undefined") {
			if (params.enabled === true || params.enabled === "true" || params.enabled === 1 || params.enabled === "1") {
				filterConditions.enabled = { [Op.eq]: true };
			} else if (params.enabled === false || params.enabled === "false" || params.enabled === 0 || params.enabled === "0") {
				filterConditions.enabled = { [Op.eq]: false };
			} else {
				// include all statuses (e.g. 'all')
				filterConditions.enabled = { [Op.not]: null };
			}
		} else {
			if (params.access_read_all_data === true || params.access_read_all_data === "true") {
				filterConditions.enabled = { [Op.not]: null };
			} else {
				filterConditions.enabled = { [Op.eq]: true };
			}
		}

		// Global Search (q or search)
		const searchQuery = params?.q || params?.search;
		if (searchQuery) {
			filterConditions[Op.or] = [
				{ version: { [Op.iLike]: `%${searchQuery}%` } },
				{ display_name: { [Op.iLike]: `%${searchQuery}%` } },
				{ description: { [Op.iLike]: `%${searchQuery}%` } },
				{ release_type: { [Op.iLike]: `%${searchQuery}%` } },
				{ new_features: { [Op.iLike]: `%${searchQuery}%` } },
				{ improvements: { [Op.iLike]: `%${searchQuery}%` } },
				{ bug_fixes: { [Op.iLike]: `%${searchQuery}%` } },
				{ breaking_changes: { [Op.iLike]: `%${searchQuery}%` } },
			];
		}

		// Robust pagination bounds
		const rawSize = parseInt(params?.pageSize, 10);
		const pageSize = Number.isFinite(rawSize) && rawSize > 0 ? Math.min(rawSize, 100) : 10;
		const rawIndex = parseInt(params?.pageIndex, 10);
		const pageIndex = Number.isFinite(rawIndex) && rawIndex >= 0 ? rawIndex : 0;

		// Sorting - whitelist fields
		const allowedSortBy = ["modified", "release_date", "version", "display_name"];
		const sortBy = allowedSortBy.includes(params?.sortBy) ? params.sortBy : "modified";
		const sortDir = (params?.sortDir || "DESC").toString().toUpperCase() === "ASC" ? "ASC" : "DESC";

		const { rows, count } = await dbSAPPS.ReleaseNote.findAndCountAll({
			where: filterConditions,
			order: [[sortBy, sortDir]],
			offset: pageIndex * pageSize,
			limit: pageSize,
		});

		let releaseNotes = rows;

		releaseNotes = releaseNotes.map((releaseNote) => {
			return {
				...releaseNote.dataValues,
				release_date: releaseNote?.release_date ? releaseNote.release_date.toISOString().split("T")[0] : null,
			};
		});

		releaseNotes = await formatWithModifier(releaseNotes);

		// Mengembalikan respons dengan status 200 OK
		return {
			releaseNotes,
			totalCount: count,
			pageIndex,
			pageSize,
			sortBy,
			sortDir,
			newFeatures: releaseNotes.reduce((acc, curr) => acc + JSON.parse(curr.new_features || "[]").length, 0),
			improvements: releaseNotes.reduce((acc, curr) => acc + JSON.parse(curr.improvements || "[]").length, 0),
			bugFixes: releaseNotes.reduce((acc, curr) => acc + JSON.parse(curr.bug_fixes || "[]").length, 0),
			breakingChanges: releaseNotes.reduce((acc, curr) => acc + JSON.parse(curr.breaking_changes || "[]").length, 0),
			success: true,
			message: "releaseNotes loaded successfully!",
		};
	} catch (error) {
		// Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
		const errorMessage = error.message || "Failed to load releaseNotes!";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function getLastVersion() {
	try {
		const releaseNote = await dbSAPPS.ReleaseNote.findOne({
			where: {
				enabled: true,
			},
			order: [["modified", "DESC"]],
			limit: 1,
		});

		if (!releaseNote) {
			return {
				success: false,
				message: "No release notes found!",
			};
		}

		const formattedReleaseNote = {
			...releaseNote.dataValues,
			release_date: releaseNote?.release_date ? releaseNote.release_date.toISOString().split("T")[0] : null,
		};

		const modifier = await dbSAPPS.User.findOne({
			where: {
				id: formattedReleaseNote.modified_by,
			},
			attributes: ["full_name"],
		});

		formattedReleaseNote.modifier = modifier?.full_name;

		// Mengembalikan respons dengan status 200 OK
		return {
			data: formattedReleaseNote,
			success: true,
			message: "releaseNotes loaded successfully!",
		};
	} catch (error) {
		// Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
		const errorMessage = error.message || "Failed to load releaseNotes!";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function filter(params) {
	// Membuat objek filter dengan validasi
	const filterConditions = {};

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

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

	try {
		// Mencari pengguna berdasarkan filter conditions
		const releaseNotes = await dbSAPPS.ReleaseNote.findAll({
			where: filterConditions,
			order: [["modified", "DESC"]], // Opsional: Mengurutkan hasil berdasarkan kolom 'modified'
		});

		// Mengembalikan hasil pencarian
		return {
			success: true,
			releaseNotes,
			message: "releaseNotes loaded successfully!",
		};
	} catch (error) {
		// Logging error untuk keperluan debugging
		console.error("Error retrieving releaseNotes: ", error);
		const errorMessage = error.message || "Failed to retrieve releaseNotes. Please try again later.";
		// Mengembalikan respons dengan status 500 Internal Server Error
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function option() {
	try {
		// Mencari pengguna yang diaktifkan dengan atribut tertentu
		const releaseNotes = await dbSAPPS.ReleaseNote.findAll({
			attributes: ["id", "display_name", "code"],
			where: { enabled: true },
			order: [["display_name", "ASC"]], // Opsional: Mengurutkan hasil berdasarkan
		});

		// Mengembalikan hasil pencarian
		return {
			success: true,
			releaseNotes,
			message: "releaseNotes loaded successfully!",
		};
	} catch (error) {
		// Logging error untuk keperluan debugging
		console.error("Error retrieving releaseNotes: ", error);
		const errorMessage = error.message || "Failed to retrieve releaseNotes. Please try again later.";
		// Mengembalikan respons dengan status 500 Internal Server Error
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function count() {
	try {
		// Menghitung jumlah pengguna yang diaktifkan
		const count = await dbSAPPS.ReleaseNote.count({
			where: { enabled: true },
		});

		// Mengembalikan hasil hitung
		return {
			success: true,
			count,
			message: "releaseNotes loaded successfully!",
		};
	} catch (error) {
		// Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
		console.error("Error counting releaseNotes: ", error);
		return {
			success: false,
			message: "Failed to retrieve releaseNotes count. Please try again later.",
		};
	}
}

async function create(params) {
	try {
		if (!params.enabled) params.enabled = true;

		// Convert array fields to JSON string if they are arrays
		["new_features", "improvements", "bug_fixes", "breaking_changes"].forEach((field) => {
			if (Array.isArray(params[field])) {
				params[field] = JSON.stringify(params[field]);
			} else if (params[field] == null) {
				params[field] = "[]";
			}
		});

		const newRelease = await dbSAPPS.ReleaseNote.create(params);

		// Respons sukses
		return {
			success: true,
			message: "Data releaseNote has been successfully adeded!",
			releaseNote: newRelease,
		};
	} catch (error) {
		// Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
		const errorMessage = error.message || "An error occurred during releaseNote creation.";
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function update(id, params) {
	try {
		// Ambil dari database
		const releaseNote = await dbSAPPS.ReleaseNote.findByPk(id);
		if (!releaseNote)
			return {
				success: false,
				message: "Release not found!",
			};

		// Validasi perubahan
		if (params.version && params.version !== releaseNote.version) {
			const existingReleaseName = await dbSAPPS.ReleaseNote.findOne({
				where: { version: params.version },
			});
			if (existingReleaseName) {
				return {
					success: false,
					message: `Release Version "${params.version}" is already taken. Try again!`,
				};
			}
		}

		// Convert array fields to JSON string if they are arrays
		["new_features", "improvements", "bug_fixes", "breaking_changes"].forEach((field) => {
			if (Array.isArray(params[field])) {
				params[field] = JSON.stringify(params[field]);
			} else if (params[field] == null) {
				params[field] = "[]";
			}
		});

		// Perbarui data kota
		await releaseNote.update(params);

		// Respons sukses
		return {
			success: true,
			message: "Your data releaseNote has been saved!",
		};
	} catch (error) {
		const errorMessage = error.message || "Failed to update releaseNote data.";
		// Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
		return {
			success: false,
			message: errorMessage,
		};
	}
}

async function enabled(id, params) {
	try {
		const releaseNote = await dbSAPPS.ReleaseNote.findByPk(id);
		if (!releaseNote)
			return {
				success: false,
				message: "Release 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;

		// debug
		// console.log('id', id);
		// console.log('params', params);
		// console.log('updateData', updateData)

		await releaseNote.update(updateData);

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

async function _delete(id) {
	try {
		// Mengambil pengguna dari database
		const releaseNote = await dbSAPPS.ReleaseNote.findByPk(id);
		if (!releaseNote) return { success: false, message: "releaseNote not found!" };

		// Menghapus pengguna dari database
		await releaseNote.destroy();

		// Respons sukses
		return {
			success: true,
			message: "releaseNote successfully deleted!",
		};
	} catch (error) {
		const errorMessage = error.message || "Failed to delete releaseNote.";
		// Menangani error dan mengembalikan respons dengan status 500 Internal Server Error
		return {
			success: false,
			message: errorMessage,
		};
	}
}
