export const PASSWORD_POLICY = Object.freeze({
	minLength: 8,
	requireLetter: true,
	requireNumber: true,
	disallowSameAsCurrent: true,
});

export const PASSWORD_POLICY_REASON = Object.freeze({
	MIN_LENGTH: "MIN_LENGTH",
	MISSING_LETTER: "MISSING_LETTER",
	MISSING_NUMBER: "MISSING_NUMBER",
	SAME_AS_CURRENT: "SAME_AS_CURRENT",
});

function hasLetter(value) {
	return /[A-Za-z]/.test(String(value || ""));
}

function hasNumber(value) {
	return /\d/.test(String(value || ""));
}

/**
 * Validate a new password against the project's explicit policy.
 *
 * @param {{ newPassword?: unknown, currentPassword?: unknown }} input
 * @returns {{
 *   ok: boolean,
 *   reasons: string[],
 *   policy: { minLength: number, requireLetter: boolean, requireNumber: boolean, disallowSameAsCurrent: boolean }
 * }}
 */
export function validateNewPassword({ newPassword, currentPassword } = {}) {
	const pw = typeof newPassword === "string" ? newPassword : "";
	const current = typeof currentPassword === "string" ? currentPassword : null;

	const reasons = [];

	if (pw.length < PASSWORD_POLICY.minLength) {
		reasons.push(PASSWORD_POLICY_REASON.MIN_LENGTH);
	}

	if (PASSWORD_POLICY.requireLetter && !hasLetter(pw)) {
		reasons.push(PASSWORD_POLICY_REASON.MISSING_LETTER);
	}

	if (PASSWORD_POLICY.requireNumber && !hasNumber(pw)) {
		reasons.push(PASSWORD_POLICY_REASON.MISSING_NUMBER);
	}

	if (
		PASSWORD_POLICY.disallowSameAsCurrent &&
		current !== null &&
		pw === current
	) {
		reasons.push(PASSWORD_POLICY_REASON.SAME_AS_CURRENT);
	}

	const uniqueReasons = Array.from(new Set(reasons));

	return {
		ok: uniqueReasons.length === 0,
		reasons: uniqueReasons,
		policy: { ...PASSWORD_POLICY },
	};
}
