/**
 * Determines if the server can encrypt backups
 *
 * @return boolean
 */
function ai1wm_can_encrypt() {
	if ( ! function_exists( 'openssl_encrypt' ) ) {
		return false;
	}

	if ( ! function_exists( 'openssl_random_pseudo_bytes' ) ) {
		return false;
	}

	if ( ! function_exists( 'openssl_cipher_iv_length' ) ) {
		return false;
	}

	if ( ! function_exists( 'sha1' ) ) {
		return false;
	}

	if ( ! in_array( AI1WM_CIPHER_NAME, array_map( 'strtoupper', openssl_get_cipher_methods() ) ) ) {
		return false;
	}

	return true;
}

/**
 * Determines if the server can decrypt backups
 *
 * @return boolean
 */
function ai1wm_can_decrypt() {
	if ( ! function_exists( 'openssl_decrypt' ) ) {
		return false;
	}

	if ( ! function_exists( 'openssl_random_pseudo_bytes' ) ) {
		return false;
	}

	if ( ! function_exists( 'openssl_cipher_iv_length' ) ) {
		return false;
	}

	if ( ! function_exists( 'sha1' ) ) {
		return false;
	}

	if ( ! in_array( AI1WM_CIPHER_NAME, array_map( 'strtoupper', openssl_get_cipher_methods() ) ) ) {
		return false;
	}

	return true;
}

/**
 * Encrypts a string with a key
 *
 * @param string $string String to encrypt
 * @param string $key    Key to encrypt the string with
 * @return string
 * @throws Ai1wm_Not_Encryptable_Exception
 */
function ai1wm_encrypt_string( $string, $key ) {
	$iv_length = ai1wm_crypt_iv_length();
	$key       = substr( sha1( $key, true ), 0, $iv_length );

	$iv = openssl_random_pseudo_bytes( $iv_length );
	if ( $iv === false ) {
		throw new Ai1wm_Not_Encryptable_Exception( __( 'Unable to generate random bytes.', AI1WM_PLUGIN_NAME ) );
	}

	$encrypted_string = openssl_encrypt( $string, AI1WM_CIPHER_NAME, $key, OPENSSL_RAW_DATA, $iv );
	if ( $encrypted_string === false ) {
		throw new Ai1wm_Not_Encryptable_Exception( __( 'Unable to encrypt data.', AI1WM_PLUGIN_NAME ) );
	}

	return sprintf( '%s%s', $iv, $encrypted_string );
}

/**
 * Returns encrypt/decrypt iv length
 *
 * @return int
 * @throws Ai1wm_Not_Encryptable_Exception
 */
function ai1wm_crypt_iv_length() {
	$iv_length = openssl_cipher_iv_length( AI1WM_CIPHER_NAME );
	if ( $iv_length === false ) {
		throw new Ai1wm_Not_Encryptable_Exception( __( 'Unable to obtain cipher length.', AI1WM_PLUGIN_NAME ) );
	}

	return $iv_length;
}

/**
 * Decrypts a string with a eky
 *
 * @param string $encrypted_string String to decrypt
 * @param string $key              Key to decrypt the string with
 * @return string
 * @throws Ai1wm_Not_Encryptable_Exception
 * @throws Ai1wm_Not_Decryptable_Exception
 */
function ai1wm_decrypt_string( $encrypted_string, $key ) {
	$iv_length = ai1wm_crypt_iv_length();
	$key       = substr( sha1( $key, true ), 0, $iv_length );
	$iv        = substr( $encrypted_string, 0, $iv_length );

	$decrypted_string = openssl_decrypt( substr( $encrypted_string, $iv_length ), AI1WM_CIPHER_NAME, $key, OPENSSL_RAW_DATA, $iv );
	if ( $decrypted_string === false ) {
		throw new Ai1wm_Not_Decryptable_Exception( __( 'Unable to decrypt data.', AI1WM_PLUGIN_NAME ) );
	}

	return $decrypted_string;
}

/**
 * Checks if decryption password is valid
 *
 * @param string $encrypted_signature
 * @param string $password
 * @return bool
 */
function ai1wm_is_decryption_password_valid( $encrypted_signature, $password ) {
	try {
		$encrypted_signature = base64_decode( $encrypted_signature );

		return ai1wm_decrypt_string( $encrypted_signature, $password ) === AI1WM_SIGN_TEXT;
	} catch ( Ai1wm_Not_Decryptable_Exception $exception ) {
		return false;
	}
}