DELIMITER $$
CREATE OR REPLACE DEFINER=`root`@`localhost` FUNCTION `account`.`passwordGenerate`()
	RETURNS text CHARSET utf8mb3 COLLATE utf8mb3_unicode_ci
	NOT DETERMINISTIC
	READS SQL DATA
BEGIN
/**
	* Generates a random password that meets the minimum requirements.
	*
	* @return Generated password
	*/
	DECLARE vMinLength TINYINT;
	DECLARE vMinAlpha TINYINT;
	DECLARE vMinUpper TINYINT;
	DECLARE vMinDigits TINYINT;
	DECLARE vMinPunct TINYINT;
	DECLARE vAlpha TINYINT DEFAULT 0;
	DECLARE vUpper TINYINT DEFAULT 0;
	DECLARE vDigits TINYINT DEFAULT 0;
	DECLARE vPunct TINYINT DEFAULT 0;
	DECLARE vRandIndex INT;
	DECLARE vPwd TEXT DEFAULT '';

	DECLARE vAlphaChars TEXT DEFAULT 'abcdefghijklmnopqrstuvwxyz';
	DECLARE vUpperChars TEXT DEFAULT 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
	DECLARE vDigitChars TEXT DEFAULT '1234567890';
	DECLARE vPunctChars TEXT DEFAULT '!$%&()=.';

	SELECT length, nAlpha, nUpper, nDigits, nPunct 
		INTO vMinLength, vMinAlpha, vMinUpper, vMinDigits, vMinPunct FROM userPassword;

	WHILE LENGTH(vPwd) < vMinLength OR vAlpha < vMinAlpha 
	OR vUpper < vMinUpper OR vDigits < vMinDigits OR vPunct < vMinPunct DO
		SET vRandIndex = FLOOR((RAND() * 4) + 1);

		CASE
			WHEN vRandIndex = 1 THEN
				SET vPwd = CONCAT(vPwd, SUBSTRING(vAlphaChars, FLOOR((RAND() * 26) + 1), 1));
				SET vAlpha = vAlpha + 1;
			WHEN vRandIndex = 2 THEN
				SET vPwd = CONCAT(vPwd, SUBSTRING(vUpperChars, FLOOR((RAND() * 26) + 1), 1));
				SET vUpper = vUpper + 1;
			WHEN vRandIndex = 3 THEN
				SET vPwd = CONCAT(vPwd, SUBSTRING(vDigitChars, FLOOR((RAND() * 10) + 1), 1));
				SET vDigits = vDigits + 1;
			WHEN vRandIndex = 4 THEN
				SET vPwd = CONCAT(vPwd, SUBSTRING(vPunctChars, FLOOR((RAND() * LENGTH(vPunctChars)) + 1), 1));
				SET vPunct = vPunct + 1;
		END CASE;
	END WHILE;
	RETURN vPwd;
END$$
DELIMITER ;