<?php

/**
 * VAPPV_TTW_Settings
 * TTW application settings
 */
final class VAPPV_TTW_Settings {

	/**
	 * user_loaded_settings
	 * Loaded user settings cache. Completed into $this->load_all_saved_settings() function
	 * @var array
	 */
	public $user_loaded_settings = array();

	/**
	 * Are settings loaded first time
	 */
	public $are_settings_loaded_once = false;

	/* ------------------------------------ */
	/*             Settings names           */

	//API key from ChatGPT account | type = string
	public static $settings_openai_api_key = 'settings_openai_api_key';
	public static $settings_openai_api_key__type = 'string';
	public static $settings_openai_api_key__default = null;

	//OpenAI API address (default direct address OR proxy API) [Draft]
	public static $settings_openai_api_address = 'settings_openai_api_address';
	public static $settings_openai_api_address__type = 'string';
	public static $settings_openai_api_address__default = 'https://api.openai.com';

	//Is primary settings saved once | type = string, values { 'yes', 'no' }
	public static $primary_settings_saved = 'primary_settings_saved';
	public static $primary_settings_saved__type = 'string';
	public static $primary_settings_saved__default = 'no';

	//ChatGPT active model | type = string
	public static $settings_chatgpt_model = 'settings_chatgpt_model';
	public static $settings_chatgpt_model__type = 'string';
	public static $settings_chatgpt_model__default = 'gpt-4o';

	//[NOT_USED_YET] ChatGPT temperature | type = double
	public static $settings_chatgpt_temperature = 'settings_chatgpt_temperature';
	public static $settings_chatgpt_temperature__type = 'double';
	public static $settings_chatgpt_temperature__default = 0.8;

	//Maximum characters per 1 question | type = integer
	public static $settings_max_characters_per_user_question = 'settings_max_characters_per_user_question';
	public static $settings_max_characters_per_user_question__type = 'integer';
	public static $settings_max_characters_per_user_question__default = 200;

	//Maximum words count in 1 answer | type = integer
	public static $settings_max_words_to_answer = 'settings_max_words_to_answer';
	public static $settings_max_words_to_answer__type = 'integer';
	public static $settings_max_words_to_answer__default = 100;

	//Maximum input words per 1 day | type = integer
	public static $settings_max_input_words_per_day_by_all_users = 'settings_max_input_words_per_day_by_all_users';
	public static $settings_max_input_words_per_day_by_all_users__type = 'integer';
	public static $settings_max_input_words_per_day_by_all_users__default = 10000;

	//Maximum input characters per 1 day | type = integer
	public static $settings_max_input_characters_per_day_by_all_users = 'settings_max_input_characters_per_day_by_all_users';
	public static $settings_max_input_characters_per_day_by_all_users__type = 'integer';
	public static $settings_max_input_characters_per_day_by_all_users__default = 40000;

	//Maximum output characters per 1 day | type = integer
	public static $settings_max_output_characters_per_day_by_ai = 'settings_max_output_characters_per_day_by_ai';
	public static $settings_max_output_characters_per_day_by_ai__type = 'integer';
	public static $settings_max_output_characters_per_day_by_ai__default = 40000;

	//Maximum output tokens per 1 day | type = integer
	public static $settings_max_output_tokens_per_day_by_ai = 'settings_max_output_tokens_per_day_by_ai';
	public static $settings_max_output_tokens_per_day_by_ai__type = 'integer';
	public static $settings_max_output_tokens_per_day_by_ai__default = 50000;

	//Website contacts page | type = string
	public static $settings_website_contacts_page = 'settings_website_contacts_page';
	public static $settings_website_contacts_page__type = 'string';
	public static $settings_website_contacts_page__default = null;

	//Website additional contacts, Email address | type = string
	public static $settings_website_contacts_company_email = 'settings_website_contacts_company_email';
	public static $settings_website_contacts_company_email__type = 'string';
	public static $settings_website_contacts_company_email__default = null;

	//Website additional contacts, Phone number | type = string
	public static $settings_website_contacts_company_phone = 'settings_website_contacts_company_phone';
	public static $settings_website_contacts_company_phone__type = 'string';
	public static $settings_website_contacts_company_phone__default = null;

	//Website additional contacts, Address | type = string
	public static $settings_website_contacts_company_address = 'settings_website_contacts_company_address';
	public static $settings_website_contacts_company_address__type = 'string';
	public static $settings_website_contacts_company_address__default = null;

	//Any direct instructions to the website | type = string
	public static $settings_any_direct_instructions = 'settings_any_direct_instructions';
	public static $settings_any_direct_instructions__type = 'string';
	public static $settings_any_direct_instructions__default = null;

	//Website common language (primary talk language) | type = string, values = VAPPV_TTW_Settings::ttw_available_languages
	public static $settings_primary_language = 'settings_primary_language';
	public static $settings_primary_language__type = 'string';
	public static $settings_primary_language__default = 'English (United States)';

	//Robot humor level | type = integer, values = VAPPV_TTW_Settings::ttw_available_humor_levels
	public static $settings_humor_level = 'settings_humor_level';
	public static $settings_humor_level__type = 'integer';
	public static $settings_humor_level__default = 15;

	//Try catch user on exit | type = integer
	public static $settings_try_intercept_leaving_users = 'settings_try_intercept_leaving_users';
	public static $settings_try_intercept_leaving_users__type = 'integer';
	public static $settings_try_intercept_leaving_users__default = 0;

	//Chat messages post scriptum | type = string
	public static $settings_robot_messages_post_scriptum = 'settings_robot_messages_post_scriptum';
	public static $settings_robot_messages_post_scriptum__type = 'string';
	public static $settings_robot_messages_post_scriptum__default = null;

	//Settings chatbot name | type = string
	public static $settings_chat_bot_name = 'settings_chat_bot_name';
	public static $settings_chat_bot_name__type = 'string';
	public static $settings_chat_bot_name__default = 'Mr. AI Assistant';

	//Current assistant data (OpenAI original format) | type = JSON
	public static $settings_current_assistant_data = 'settings_current_assistant_data';
	public static $settings_current_assistant_data__type = 'string';
	public static $settings_current_assistant_data__default = null;

	//Current assistant metadata (TTW data for system usage) | type = JSON
	public static $settings_current_assistant_meta = 'settings_current_assistant_meta';
	public static $settings_current_assistant_meta__type = 'string';
	public static $settings_current_assistant_meta__default = null;

	//Current vector store data
	public static $settings_current_main_vector_store_data = 'settings_current_main_vector_store_data';
	public static $settings_current_main_vector_store_data__type = 'string';
	public static $settings_current_main_vector_store_data__default = null;

	//Current training file data
	public static $settings_current_main_training_file_data = 'settings_current_main_training_file_data';
	public static $settings_current_main_training_file_data__type = 'string';
	public static $settings_current_main_training_file_data__default = null;

	//One dialogue lifetime, minutes | type = integer
	public static $settings_dialogue_lifetime_minutes = 'settings_dialogue_lifetime_minutes';
	public static $settings_dialogue_lifetime_minutes__type = 'integer';
	public static $settings_dialogue_lifetime_minutes__default = 1440; // 24 hours

	//One dialogue lifetime, messages count | type = integer
	public static $settings_dialogue_lifetime_max_messages = 'settings_dialogue_lifetime_max_messages';
	public static $settings_dialogue_lifetime_max_messages__type = 'integer';
	public static $settings_dialogue_lifetime_max_messages__default = 30;

	//Is chatbot displayed on the website right now | type = integer, values = { 0, 1 }
	public static $settings_is_chatbot_displayed_right_now = 'settings_is_chatbot_displayed_right_now';
	public static $settings_is_chatbot_displayed_right_now__type = 'integer';
	public static $settings_is_chatbot_displayed_right_now__default = 1;

	//Chat bubble image url | type = string, values = VAPPV_TTW_Settings::ttw_available_chat_bubbles_types
	public static $settings_chat_bubble_image_url = 'settings_chat_bubble_image_url';
	public static $settings_chat_bubble_image_url__type = 'string';
	public static $settings_chat_bubble_image_url__default = 'chat-bubble-type-1.png';

	//Settings sugar for limits (slifer for quick limits jumps)
	public static $settings_sugar_limits_summary = 'settings_sugar_limits_summary';
	public static $settings_sugar_limits_summary__type = 'integer';
	public static $settings_sugar_limits_summary__default = 2;

	//Prohibited topics and words
	public static $settings_prohibited_topics_and_words = 'settings_prohibited_topics_and_words';
	public static $settings_prohibited_topics_and_words__type = 'string';
	public static $settings_prohibited_topics_and_words__default = null;

	//Plugin custom CSS
	public static $settings_plugin_appearance_custom_css = 'settings_plugin_appearance_custom_css';
	public static $settings_plugin_appearance_custom_css__type = 'string';
	public static $settings_plugin_appearance_custom_css__default = null;

	//Show a popup with a promotional message if the user hasn't clicked on the floating chat bubble themselves; -1 means 'Not show'
	public static $settings_show_promo_popup_after_n_seconds = 'settings_show_promo_popup_after_n_seconds';
	public static $settings_show_promo_popup_after_n_seconds__type = 'integer';
	public static $settings_show_promo_popup_after_n_seconds__default = -1;

	//Show a promo popup no more than once every specified number of minutes
	public static $settings_show_promo_popup_time_frequency_n_minutes = 'settings_show_promo_popup_time_frequency_n_minutes';
	public static $settings_show_promo_popup_time_frequency_n_minutes__type = 'integer';
	public static $settings_show_promo_popup_time_frequency_n_minutes__default = 10080; // (7 days by default)

	//Welcome message (HTML code)
	public static $settings_welcome_message_html = 'settings_welcome_message_html';
	public static $settings_welcome_message_html__type = 'string';
	public static $settings_welcome_message_html__default = null;

	//List of available GPT models
	public static $settings_available_gpt_models = 'settings_available_gpt_models';
	public static $settings_available_gpt_models__type = 'string';
	public static $settings_available_gpt_models__default = null;

	//Temp storage for last OpenAI response
	public static $settings_last_openai_answer = 'settings_last_openai_answer';
	public static $settings_last_openai_answer__type = 'string';
	public static $settings_last_openai_answer__default = null;

	//Store database during plugin deletion / uninstall
	public static $settings_store_db_on_deletion = 'settings_store_db_on_deletion';
	public static $settings_store_db_on_deletion__type = 'string';
	public static $settings_store_db_on_deletion__default = 'yes';

	//Store database during plugin deletion / uninstall
	public static $settings_show_powered_by_ttw_public_label = 'settings_show_powered_by_ttw_public_label';
	public static $settings_show_powered_by_ttw_public_label__type = 'string';
	public static $settings_show_powered_by_ttw_public_label__default = 'no';

	//List of site pages URL masks on which chat will not be displayed
	public static $settings_chat_restricted_pages_urlmasks = 'settings_chat_restricted_pages_urlmasks';
	public static $settings_chat_restricted_pages_urlmasks__type = 'string';
	public static $settings_chat_restricted_pages_urlmasks__default = null;

	//Chat bubble UI position. Available positions could be found here: VAPPV_TTW_Settings::$ttw_chat_bubble_ui_positions
	public static $settings_chat_bubble_ui_position = 'settings_chat_bubble_ui_position';
	public static $settings_chat_bubble_ui_position__type = 'string';
	public static $settings_chat_bubble_ui_position__default = 'ttw_chat_bubble_position_bottom_right';

	//Chat bubble margin from the window borders
	public static $settings_chat_bubble_ui_margin = 'settings_chat_bubble_ui_margin';
	public static $settings_chat_bubble_ui_margin__type = 'integer';
	public static $settings_chat_bubble_ui_margin__default = 40;

	//AI character
	public static $settings_ai_character = 'settings_ai_character';
	public static $settings_ai_character__type = 'string';
	public static $settings_ai_character__default = 'justaguy';

	/*             ~Settings names          */
	/* ------------------------------------ */

	/* ------------------------------------ */
	/*         Settings special values      */

	//Available ChatGPT models
	public static $chatgpt_available_models = array(
		array(
			'Name'        => 'gpt-3.5-turbo',
			'Description' => 'GPT-3.5 Turbo / 16k context length'
		),
		array(
			'Name'        => 'gpt-4-turbo',
			'Description' => 'GPT-4 Turbo / 128k context length'
		),
		array(
			'Name'        => 'gpt-4o',
			'Description' => 'GPT-4o (omni) / 128k context length'
		)
	);

	//Possible chat bubble position according to VAPPV_TTW_Settings::$settings_chat_bubble_ui_position
	public static $ttw_chat_bubble_ui_positions = array(
		'ttw_chat_bubble_position_bottom_left'   => 'Bottom left corner',
		'ttw_chat_bubble_position_bottom_center' => 'Bottom center',
		'ttw_chat_bubble_position_bottom_right'  => 'Bottom right corner'
	);

	//Humor levels
	public static $ttw_available_humor_levels = array(
		0   => '0%',
		15  => '15%',
		30  => '30%',
		50  => '50%',
		65  => '65%',
		80  => '80%',
		100 => '100%'
	);

	//Robot available languages
	public static $ttw_available_languages = array(
		'Albanian (Albania)',
		'Arabic (Arab World)',
		'Armenian (Armenia)',
		'Awadhi (India)',
		'Azerbaijani (Azerbaijan)',
		'Bashkir (Russia)',
		'Basque (Spain)',
		'Belarusian (Belarus)',
		'Bengali (Bangladesh)',
		'Bhojpuri (India)',
		'Bosnian (Bosnia and Herzegovina)',
		'Brazilian Portuguese (Brazil)',
		'Bulgarian (Bulgaria)',
		'Cantonese (Yue) (China)',
		'Catalan (Spain)',
		'Chhattisgarhi (India)',
		'Chinese (China)',
		'Croatian (Croatia)',
		'Czech (Czech Republic)',
		'Danish (Denmark)',
		'Dogri (India)',
		'Dutch (Netherlands)',
		'English (United Kingdom)',
		'English (United States)',
		'Estonian (Estonia)',
		'Faroese (Faroe Islands)',
		'Finnish (Finland)',
		'French (France)',
		'Galician (Spain)',
		'Georgian (Georgia)',
		'German (Germany)',
		'Greek (Greece)',
		'Gujarati (India)',
		'Haryanvi (India)',
		'Hindi (India)',
		'Hungarian (Hungary)',
		'Indonesian (Indonesia)',
		'Irish (Ireland)',
		'Italian (Italy)',
		'Japanese (Japan)',
		'Javanese (Indonesia)',
		'Kannada (India)',
		'Kashmiri (India)',
		'Kazakh (Kazakhstan)',
		'Konkani (India)',
		'Korean (South Korea)',
		'Kyrgyz (Kyrgyzstan)',
		'Latvian (Latvia)',
		'Lithuanian (Lithuania)',
		'Macedonian (North Macedonia)',
		'Maithili (India)',
		'Malay (Malaysia)',
		'Maltese (Malta)',
		'Mandarin (China)',
		'Mandarin Chinese (China)',
		'Marathi (India)',
		'Marwari (India)',
		'Min Nan (China)',
		'Moldovan (Moldova)',
		'Mongolian (Mongolia)',
		'Montenegrin (Montenegro)',
		'Nepali (Nepal)',
		'Norwegian (Norway)',
		'Oriya (India)',
		'Pashto (Afghanistan)',
		'Persian (Farsi) (Iran)',
		'Polish (Poland)',
		'Portuguese (Portugal)',
		'Punjabi (India)',
		'Rajasthani (India)',
		'Romanian (Romania)',
		'Russian (Russia)',
		'Sanskrit (India)',
		'Santali (India)',
		'Serbian (Serbia)',
		'Sindhi (Pakistan)',
		'Sinhala (Sri Lanka)',
		'Slovak (Slovakia)',
		'Slovene (Slovenia)',
		'Slovenian (Slovenia)',
		'Ukrainian (Ukraine)',
		'Urdu (Pakistan)',
		'Uzbek (Uzbekistan)',
		'Vietnamese (Vietnam)',
		'Welsh (Wales)',
		'Wu (China)'
	);

	//Available chat bubbles appearences
	public static $ttw_available_chat_bubbles_types = array(
		'chat-bubble-type-1.png',
		'chat-bubble-type-2.png',
		'chat-bubble-type-3.png',
		'chat-bubble-type-4.png',
		'chat-bubble-type-5.png',
		'chat-bubble-type-6.png',
		'chat-bubble-type-16.png',
		'chat-bubble-type-17.png',
		'chat-bubble-type-18.png',
		'chat-bubble-type-19.png',
		'chat-bubble-type-20.png',
		'chat-bubble-type-22.png',
	);

	//Available AI characters
	public static $ttw_available_ai_characters = array(
		'justaguy' => array(
			'img' => 'character-justaguy.png'
		),
		'businessman' => array(
			'img' => 'character-businessman.png'
		),
		'creator' => array(
			'img' => 'character-creator.png'
		)
	);

	/*        ~Settings special values      */
	/* ------------------------------------ */

	/**
	 * get_entity_table_name
	 * Gets the name of the table in the database where instances of this class are stored.
	 * @return string
	 */
	public function get_entity_table_name(): string {
		global $wpdb;

		//Get database tables prefix and table name
		$db_tables_prefix      = $wpdb->prefix;
		$db_settings_tablename = "{$db_tables_prefix}vappv_ttw_settings";

		return $db_settings_tablename;
	}

	/**
	 * update_setting
	 * Update specified setting into WP database
	 *
	 * @param string $setting_name Parameter name
	 * @param mixed $setting_value Parameter value
	 *
	 * @return void
	 */
	public function update_setting( string $setting_name, $setting_value ) {

		global $wpdb;

		//Get database tables prefix and other params
		$db_settings_tablename = $this->get_entity_table_name();

		//#1 Update settings into DB
		//Try get already saved setting
		$already_saved_row_count = $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i WHERE `tname`=%s', array( $db_settings_tablename, $setting_name ) ) );

		if ( 0 === (int)$already_saved_row_count ) {

			//Insert new setting entry
			$wpdb->insert(
				$db_settings_tablename,
				array(
					'tname'  => $setting_name,
					'tvalue' => $setting_value
				)
			);

			//Put new setting into local cache
			$setting_inserted_id  = $wpdb->insert_id;
			$next_setting = array(
				'id'     => $setting_inserted_id,
				'tname'  => $setting_name,
				'tvalue' => $setting_value
			);
			array_push( $this->user_loaded_settings, $next_setting );

		} else {

			//Update existing setting entry
			$wpdb->update(
				$db_settings_tablename,
				array( 'tvalue' => $setting_value ),
				array( 'tname' => $setting_name )
			);

		}

		//#2 Update setting into local variables cache with double-check
		$is_setting_updated_locally = false;
		for ( $i = 0; $i < count( $this->user_loaded_settings ); $i++ ) {
			if ( $this->user_loaded_settings[ $i ]['tname'] === $setting_name ) {
				$this->user_loaded_settings[ $i ]['tvalue'] = $setting_value;
				$is_setting_updated_locally = true;
				break;
			}
		}

		if ( false === $is_setting_updated_locally ) {
			//Probably very rare situation
			$next_setting = array(
				'id' => -1,
				'tname' => $setting_name,
				'tvalue' => $setting_value
			);
			array_push( $this->user_loaded_settings, $next_setting );
		}

	}

	/**
	 * Update all plugin settings
	 *
	 * @param string $settings_chatgpt_model ChatGPT model gpt3, gpt4, etc.)
	 * @param float $settings_chatgpt_temperature ChatGPT's temperature from 0.1 to 1. Higher = more creativity. Lower = more precision.
	 * @param int $settings_max_characters_per_user_question Max characters per one user question
	 * @param int $settings_max_words_to_answer The maximum number of words the AI can use to respond to the user.
	 * @param string $settings_website_contacts_page Link to the website contacts page
	 * @param string $settings_any_direct_instructions Any direct instructions to the AI
	 * @param string $settings_primary_language Primary conversation language
	 * @param int $settings_humor_level AI humor level from 0% to 100%
	 * @param int $settings_try_intercept_leaving_users Try intercept leaving users (not used at the moment)
	 * @param string $settings_chat_bot_name AI name
	 * @param string $settings_robot_messages_post_scriptum Post scriptum after each AI message
	 * @param int $settings_dialogue_lifetime_minutes Dialogue lifetime, minutes
	 * @param int $settings_is_chatbot_displayed_right_now Is chatbot displayed at the moment
	 * @param string $settings_chat_bubble_image_url URL to the chat bubble image
	 * @param string $settings_website_contacts_company_email Company contact Email
	 * @param string $settings_website_contacts_company_phone Company contact phone
	 * @param string $settings_website_contacts_company_address Company address
	 * @param int $settings_max_input_words_per_day_by_all_users Max input words per day from all users (limit)
	 * @param int $settings_max_input_characters_per_day_by_all_users Max input characters per day from all users (limit)
	 * @param int $settings_max_output_characters_per_day_by_ai Max output characters per day by AI (limit)
	 * @param int $settings_max_output_tokens_per_day_by_ai Max output tokens per day by AI (limit)
	 * @param int $settings_sugar_limits_summary Summary limit (syntax sugar for settings page)
	 * @param string $settings_prohibited_topics_and_words Prohibited topics and words
	 * @param string $settings_plugin_appearance_custom_css Plugin custom CSS
	 * @param int $settings_show_promo_popup_after_n_seconds Show promo popup after N seconds
	 * @param int $settings_show_promo_popup_time_frequency_n_minutes Promo popup re-display frequency, minutes
	 * @param int $settings_dialogue_lifetime_max_messages Dialogue lifetime (messages count)
	 * @param string $settings_welcome_message_html AI welcome message text
	 * @param string $settings_store_db_on_deletion Is it necessary to keep all plugin data on deletion / updating ({ "yes" / "no" })
	 * @param string $settings_show_powered_by_ttw_public_label Show 'Powered by talktowebsite.com' label after the chat window (public page)
	 * @param string $settings_chat_restricted_pages_urlmasks A list of URL substrings (masks) to restrict chat displaying
	 * @param string $settings_openai_api_address OpenAI connection API endpoint
	 * @param string $settings_chat_bubble_ui_position Chat bubble position (top left, top center, top right, bottom left, bottom center, bototm right)
	 * @param int $settings_chat_bubble_ui_margin Margin between chat bubble and the screen
	 *
	 * @return array
	 * @throws Exception
	 */
	public function update_all_plugin_settings(
		string $settings_chatgpt_model,
		float $settings_chatgpt_temperature,
		int $settings_max_characters_per_user_question,
		int $settings_max_words_to_answer,
		string $settings_website_contacts_page,
		string $settings_any_direct_instructions,
		string $settings_primary_language,
		int $settings_humor_level,
		int $settings_try_intercept_leaving_users,
		string $settings_chat_bot_name,
		string $settings_robot_messages_post_scriptum,
		int $settings_dialogue_lifetime_minutes,
		int $settings_is_chatbot_displayed_right_now,
		string $settings_chat_bubble_image_url,
		string $settings_website_contacts_company_email,
		string $settings_website_contacts_company_phone,
		string $settings_website_contacts_company_address,
		int $settings_max_input_words_per_day_by_all_users,
		int $settings_max_input_characters_per_day_by_all_users,
		int $settings_max_output_characters_per_day_by_ai,
		int $settings_max_output_tokens_per_day_by_ai,
		int $settings_sugar_limits_summary,
		string $settings_prohibited_topics_and_words,
		string $settings_plugin_appearance_custom_css,
		int $settings_show_promo_popup_after_n_seconds,
		int $settings_show_promo_popup_time_frequency_n_minutes,
		int $settings_dialogue_lifetime_max_messages,
		string $settings_welcome_message_html,
		string $settings_store_db_on_deletion,
		string $settings_show_powered_by_ttw_public_label,
		string $settings_chat_restricted_pages_urlmasks,
		string $settings_openai_api_address,
		string $settings_chat_bubble_ui_position,
		int $settings_chat_bubble_ui_margin,
		string $settings_ai_character
	): array {

		//Load current settings
		$this->load_all_saved_settings();

		//Cast input params to it's values
		$settings_chatgpt_model                             = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_chatgpt_model, $settings_chatgpt_model );
		$settings_chatgpt_temperature                       = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_chatgpt_temperature, $settings_chatgpt_temperature );
		$settings_max_characters_per_user_question          = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_max_characters_per_user_question, $settings_max_characters_per_user_question );
		$settings_max_words_to_answer                       = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_max_words_to_answer, $settings_max_words_to_answer );
		$settings_website_contacts_page                     = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_website_contacts_page, $settings_website_contacts_page );
		$settings_any_direct_instructions                   = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_any_direct_instructions, $settings_any_direct_instructions );
		$settings_primary_language                          = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_primary_language, $settings_primary_language );
		$settings_humor_level                               = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_humor_level, $settings_humor_level );
		$settings_try_intercept_leaving_users               = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_try_intercept_leaving_users, $settings_try_intercept_leaving_users );
		$settings_chat_bot_name                             = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_chat_bot_name, $settings_chat_bot_name );
		$settings_robot_messages_post_scriptum              = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_robot_messages_post_scriptum, $settings_robot_messages_post_scriptum );
		$settings_dialogue_lifetime_minutes                 = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_dialogue_lifetime_minutes, $settings_dialogue_lifetime_minutes );
		$settings_is_chatbot_displayed_right_now            = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_is_chatbot_displayed_right_now, $settings_is_chatbot_displayed_right_now );
		$settings_chat_bubble_image_url                     = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_chat_bubble_image_url, $settings_chat_bubble_image_url );
		$settings_website_contacts_company_email            = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_website_contacts_company_email, $settings_website_contacts_company_email );
		$settings_website_contacts_company_phone            = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_website_contacts_company_phone, $settings_website_contacts_company_phone );
		$settings_website_contacts_company_address          = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_website_contacts_company_address, $settings_website_contacts_company_address );
		$settings_max_input_words_per_day_by_all_users      = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_max_input_words_per_day_by_all_users, $settings_max_input_words_per_day_by_all_users );
		$settings_max_input_characters_per_day_by_all_users = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_max_input_characters_per_day_by_all_users, $settings_max_input_characters_per_day_by_all_users );
		$settings_max_output_characters_per_day_by_ai       = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_max_output_characters_per_day_by_ai, $settings_max_output_characters_per_day_by_ai );
		$settings_max_output_tokens_per_day_by_ai           = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_max_output_tokens_per_day_by_ai, $settings_max_output_tokens_per_day_by_ai );
		$settings_sugar_limits_summary                      = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_sugar_limits_summary, $settings_sugar_limits_summary );
		$settings_prohibited_topics_and_words               = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_prohibited_topics_and_words, $settings_prohibited_topics_and_words );
		$settings_plugin_appearance_custom_css              = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_plugin_appearance_custom_css, $settings_plugin_appearance_custom_css );
		$settings_show_promo_popup_after_n_seconds          = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_show_promo_popup_after_n_seconds, $settings_show_promo_popup_after_n_seconds );
		$settings_show_promo_popup_time_frequency_n_minutes = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_show_promo_popup_time_frequency_n_minutes, $settings_show_promo_popup_time_frequency_n_minutes );
		$settings_dialogue_lifetime_max_messages            = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_dialogue_lifetime_max_messages, $settings_dialogue_lifetime_max_messages );
		$settings_welcome_message_html                      = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_welcome_message_html, $settings_welcome_message_html );
		$settings_store_db_on_deletion                      = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_store_db_on_deletion, $settings_store_db_on_deletion );
		$settings_show_powered_by_ttw_public_label          = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_show_powered_by_ttw_public_label, $settings_show_powered_by_ttw_public_label );
		$settings_chat_restricted_pages_urlmasks            = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_chat_restricted_pages_urlmasks, $settings_chat_restricted_pages_urlmasks );
		$settings_openai_api_address                        = $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_openai_api_address, $settings_openai_api_address );
		$settings_chat_bubble_ui_position					= $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_chat_bubble_ui_position, $settings_chat_bubble_ui_position );
		$settings_chat_bubble_ui_margin						= $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_chat_bubble_ui_margin, $settings_chat_bubble_ui_margin );
		$settings_ai_character								= $this->cast_setting_value_to_its_type( VAPPV_TTW_Settings::$settings_ai_character, $settings_ai_character );

		//Compare settings to add log entry
		$changes_list = array();
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_chatgpt_model ) !== $settings_chatgpt_model ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chatgpt_model );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'ChatGPT model changed from \'%1$s\' to \'%2$s\'.', 'talk-to-website' ),
					$old_setting,
					$settings_chatgpt_model
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_chatgpt_temperature ) !== $settings_chatgpt_temperature ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chatgpt_temperature );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'ChatGPT temperature changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_chatgpt_temperature
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_characters_per_user_question ) !== $settings_max_characters_per_user_question ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_characters_per_user_question );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__(  'Max user characters per question changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_max_characters_per_user_question
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_words_to_answer ) !== $settings_max_words_to_answer ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_words_to_answer );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Max words per 1 AI answer changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_max_words_to_answer
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_page ) !== $settings_website_contacts_page ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_page );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Website contacts page changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_website_contacts_page
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_any_direct_instructions ) !== $settings_any_direct_instructions ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_any_direct_instructions );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'AI direct instructions changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_any_direct_instructions
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_humor_level ) !== $settings_humor_level ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_humor_level );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'AI humor level changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_humor_level
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_primary_language ) !== $settings_primary_language ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_primary_language );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'AI primary language level changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_primary_language
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_try_intercept_leaving_users ) !== $settings_try_intercept_leaving_users ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_try_intercept_leaving_users );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Try intercept users on exit changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_try_intercept_leaving_users
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bot_name ) !== $settings_chat_bot_name ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bot_name );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Robot name changed from \'%1$s\' to \'%2$s\'', 'talk-to-website' ),
					$old_setting,
					$settings_chat_bot_name
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_robot_messages_post_scriptum ) !== $settings_robot_messages_post_scriptum ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_robot_messages_post_scriptum );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'AI messages post scriptum changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_robot_messages_post_scriptum
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_dialogue_lifetime_minutes ) !== $settings_dialogue_lifetime_minutes ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_dialogue_lifetime_minutes );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__(  'Dialogue lifetime (duration in minutes) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_dialogue_lifetime_minutes
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_dialogue_lifetime_max_messages ) !== $settings_dialogue_lifetime_max_messages ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_dialogue_lifetime_max_messages );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Dialogue lifetime (messages count) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_dialogue_lifetime_max_messages
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_is_chatbot_displayed_right_now ) !== $settings_is_chatbot_displayed_right_now ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_is_chatbot_displayed_right_now );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Is chatbot displayed changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_is_chatbot_displayed_right_now
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bubble_image_url ) !== $settings_chat_bubble_image_url ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bubble_image_url );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Chat bubble image changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_chat_bubble_image_url
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_email ) !== $settings_website_contacts_company_email ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_email );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Company Email changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_website_contacts_company_email
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_phone ) !== $settings_website_contacts_company_phone ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_phone );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Company contact phone changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_website_contacts_company_phone
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_address ) !== $settings_website_contacts_company_address ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_address );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Company address changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_website_contacts_company_address
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_input_words_per_day_by_all_users ) !== $settings_max_input_words_per_day_by_all_users ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_input_words_per_day_by_all_users );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Max input words per all users (daily limit) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_max_input_words_per_day_by_all_users
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_input_characters_per_day_by_all_users ) !== $settings_max_input_characters_per_day_by_all_users ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_input_characters_per_day_by_all_users );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Max input characters per all users (daily limit) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_max_input_characters_per_day_by_all_users
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_output_characters_per_day_by_ai ) !== $settings_max_output_characters_per_day_by_ai ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_output_characters_per_day_by_ai );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Max output characters by AI (daily limit) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_max_output_characters_per_day_by_ai
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_output_tokens_per_day_by_ai ) !== $settings_max_output_tokens_per_day_by_ai ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_max_output_tokens_per_day_by_ai );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Max output tokens by AI (daily limit) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_max_output_tokens_per_day_by_ai
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_sugar_limits_summary ) !== $settings_sugar_limits_summary ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_sugar_limits_summary );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Summary limits level changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_sugar_limits_summary
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_prohibited_topics_and_words ) !== $settings_prohibited_topics_and_words ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_prohibited_topics_and_words );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Prohibited topics and words changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_prohibited_topics_and_words
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_plugin_appearance_custom_css ) !== $settings_plugin_appearance_custom_css ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_plugin_appearance_custom_css );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Plugin custom CSS changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_plugin_appearance_custom_css
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_show_promo_popup_after_n_seconds ) !== $settings_show_promo_popup_after_n_seconds ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_show_promo_popup_after_n_seconds );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Displaying time of the promo popup (seconds) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_show_promo_popup_after_n_seconds
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_show_promo_popup_time_frequency_n_minutes ) !== $settings_show_promo_popup_time_frequency_n_minutes ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_show_promo_popup_time_frequency_n_minutes );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Promo popup re-displaying frequency (minutes) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_show_promo_popup_time_frequency_n_minutes
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_welcome_message_html ) !== $settings_welcome_message_html ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_welcome_message_html );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Chat welcome message changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_welcome_message_html
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_store_db_on_deletion ) !== $settings_store_db_on_deletion ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_store_db_on_deletion );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Store DB data on plugin update / deletion changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_store_db_on_deletion
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_show_powered_by_ttw_public_label ) !== $settings_show_powered_by_ttw_public_label ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_show_powered_by_ttw_public_label );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Public plugin label (powered by talktowebsite.com) changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_show_powered_by_ttw_public_label
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_restricted_pages_urlmasks ) !== $settings_chat_restricted_pages_urlmasks ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_restricted_pages_urlmasks );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Restrict the display of chat on specified pages of the site changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_chat_restricted_pages_urlmasks
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_openai_api_address ) !== $settings_openai_api_address ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_openai_api_address );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'OpenAI API address changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_openai_api_address
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bubble_ui_position ) !== $settings_chat_bubble_ui_position ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bubble_ui_position );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Chat bubble UI position changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_chat_bubble_ui_position
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bubble_ui_margin ) !== $settings_chat_bubble_ui_margin ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bubble_ui_margin );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'Chat bubble UI margin changed from \'%1$spx\' to \'%2$spx\'.', 'talk-to-website'),
					$old_setting,
					$settings_chat_bubble_ui_margin
				)
			);
		}
		if ( $this->try_get_setting( VAPPV_TTW_Settings::$settings_ai_character ) !== $settings_ai_character ) {
			$old_setting = $this->try_get_setting( VAPPV_TTW_Settings::$settings_ai_character );
			array_push(
				$changes_list,
				sprintf(
					/* translators: 1. old parameter value 2. new parameter value */
					__( 'AI character changed from \'%1$s\' to \'%2$s\'', 'talk-to-website'),
					$old_setting,
					$settings_ai_character
				)
			);
		}

		//Add log about saved settings
		if ( count( $changes_list ) > 0 ) {
			$changes_joined_info = implode( '; ', $changes_list );
			VAPPV_TTW_Core::add_log_entry(
				'info',
				sprintf(
					/* translators: 1. new parameters details */
					__( 'Settings updated. Details = %1$s.', 'talk-to-website' ),
					$changes_joined_info
				)
			);
		}

		//Check is it necessary to update the assistant (check VAPPV_TTW_Training::build_assistant_magic_instructions for details)
		$is_chatgpt_assistant_update_needed = false;
		if (
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_page )             !== $settings_website_contacts_page             ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_humor_level )                       !== $settings_humor_level                       ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_max_words_to_answer )               !== $settings_max_words_to_answer               ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_primary_language )                  !== $settings_primary_language                  ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_any_direct_instructions )           !== $settings_any_direct_instructions           ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_bot_name )                     !== $settings_chat_bot_name                     ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_email )    !== $settings_website_contacts_company_email    ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_phone )    !== $settings_website_contacts_company_phone    ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_address )  !== $settings_website_contacts_company_address  ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_prohibited_topics_and_words )       !== $settings_prohibited_topics_and_words       ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_chatgpt_model )                     !== $settings_chatgpt_model                     ||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_chatgpt_temperature )               !== $settings_chatgpt_temperature				||
			$this->try_get_setting( VAPPV_TTW_Settings::$settings_ai_character )						!== $settings_ai_character
		) {
			$is_chatgpt_assistant_update_needed = true;
		}

		//Update all settings one by one
		$this->update_setting( VAPPV_TTW_Settings::$primary_settings_saved, 'yes' );
		$this->update_setting( VAPPV_TTW_Settings::$settings_chatgpt_model, $settings_chatgpt_model );
		$this->update_setting( VAPPV_TTW_Settings::$settings_chatgpt_temperature, $settings_chatgpt_temperature );
		$this->update_setting( VAPPV_TTW_Settings::$settings_max_characters_per_user_question, $settings_max_characters_per_user_question );
		$this->update_setting( VAPPV_TTW_Settings::$settings_max_words_to_answer, $settings_max_words_to_answer );
		$this->update_setting( VAPPV_TTW_Settings::$settings_website_contacts_page, $settings_website_contacts_page );
		$this->update_setting( VAPPV_TTW_Settings::$settings_any_direct_instructions, $settings_any_direct_instructions );
		$this->update_setting( VAPPV_TTW_Settings::$settings_primary_language, $settings_primary_language );
		$this->update_setting( VAPPV_TTW_Settings::$settings_humor_level, $settings_humor_level );
		$this->update_setting( VAPPV_TTW_Settings::$settings_try_intercept_leaving_users, $settings_try_intercept_leaving_users );
		$this->update_setting( VAPPV_TTW_Settings::$settings_chat_bot_name, $settings_chat_bot_name );
		$this->update_setting( VAPPV_TTW_Settings::$settings_robot_messages_post_scriptum, $settings_robot_messages_post_scriptum );
		$this->update_setting( VAPPV_TTW_Settings::$settings_dialogue_lifetime_minutes, $settings_dialogue_lifetime_minutes );
		$this->update_setting( VAPPV_TTW_Settings::$settings_dialogue_lifetime_max_messages, $settings_dialogue_lifetime_max_messages );
		$this->update_setting( VAPPV_TTW_Settings::$settings_is_chatbot_displayed_right_now, $settings_is_chatbot_displayed_right_now );
		$this->update_setting( VAPPV_TTW_Settings::$settings_chat_bubble_image_url, $settings_chat_bubble_image_url );
		$this->update_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_email, $settings_website_contacts_company_email );
		$this->update_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_phone, $settings_website_contacts_company_phone );
		$this->update_setting( VAPPV_TTW_Settings::$settings_website_contacts_company_address, $settings_website_contacts_company_address );
		$this->update_setting( VAPPV_TTW_Settings::$settings_max_input_words_per_day_by_all_users, $settings_max_input_words_per_day_by_all_users );
		$this->update_setting( VAPPV_TTW_Settings::$settings_max_input_characters_per_day_by_all_users, $settings_max_input_characters_per_day_by_all_users );
		$this->update_setting( VAPPV_TTW_Settings::$settings_max_output_characters_per_day_by_ai, $settings_max_output_characters_per_day_by_ai );
		$this->update_setting( VAPPV_TTW_Settings::$settings_max_output_tokens_per_day_by_ai, $settings_max_output_tokens_per_day_by_ai );
		$this->update_setting( VAPPV_TTW_Settings::$settings_sugar_limits_summary, $settings_sugar_limits_summary );
		$this->update_setting( VAPPV_TTW_Settings::$settings_prohibited_topics_and_words, $settings_prohibited_topics_and_words );
		$this->update_setting( VAPPV_TTW_Settings::$settings_plugin_appearance_custom_css, $settings_plugin_appearance_custom_css );
		$this->update_setting( VAPPV_TTW_Settings::$settings_show_promo_popup_after_n_seconds, $settings_show_promo_popup_after_n_seconds );
		$this->update_setting( VAPPV_TTW_Settings::$settings_show_promo_popup_time_frequency_n_minutes, $settings_show_promo_popup_time_frequency_n_minutes );
		$this->update_setting( VAPPV_TTW_Settings::$settings_welcome_message_html, $settings_welcome_message_html );
		$this->update_setting( VAPPV_TTW_Settings::$settings_store_db_on_deletion, $settings_store_db_on_deletion );
		$this->update_setting( VAPPV_TTW_Settings::$settings_chat_restricted_pages_urlmasks, $settings_chat_restricted_pages_urlmasks );
		$this->update_setting( VAPPV_TTW_Settings::$settings_openai_api_address, $settings_openai_api_address );
		$this->update_setting( VAPPV_TTW_Settings::$settings_chat_bubble_ui_position, $settings_chat_bubble_ui_position );
		$this->update_setting( VAPPV_TTW_Settings::$settings_chat_bubble_ui_margin, $settings_chat_bubble_ui_margin );
		$this->update_setting( VAPPV_TTW_Settings::$settings_ai_character, $settings_ai_character );

		//Try to get OpenAI connection key and current assistant information
		$current_openai_api_address = $this->try_get_setting( VAPPV_TTW_Settings::$settings_openai_api_address );
		$current_chatgpt_api_key 	= $this->try_get_setting( VAPPV_TTW_Settings::$settings_openai_api_key );
		$current_assistant_data  	= $this->try_get_setting( VAPPV_TTW_Settings::$settings_current_assistant_data );
		$current_assistant_meta  	= $this->try_get_setting( VAPPV_TTW_Settings::$settings_current_assistant_meta );

		//Check is it necessary to update assistant
		if (
			! is_null( $current_assistant_data ) &&
			strlen( $current_assistant_data ) > 0 &&
			true === $is_chatgpt_assistant_update_needed
		) {
			//Decode assistant data
			$current_assistant_data = json_decode( $current_assistant_data, true );
			$current_assistant_meta = json_decode( $current_assistant_meta, true );

			//Try to figure out is it real assistant, or only first time saving
			if (
				isset( $current_assistant_data['id'] ) &&
				! is_null( $current_assistant_data['id'] ) &&
				strlen( trim ( (string)$current_assistant_data['id'] ) ) > 0
			) {

				//Rebuild magic instructions
				$training_controller                    = new VAPPV_TTW_Training();
				$ttw_chatbot_new_magic_instructions     = $training_controller->build_assistant_magic_instructions( $this );

				//Re-set assistant parameters (local object)
				$current_assistant_data['instructions'] = $ttw_chatbot_new_magic_instructions;
				$current_assistant_data['model']        = $settings_chatgpt_model;
				$current_assistant_data['temperature']  = $settings_chatgpt_temperature;

				//Update assistant data in OpenAI
				$openai_api_controller = new VAPPV_TTW_OpenAI_API_Connector( $current_openai_api_address, $current_chatgpt_api_key );
				$openai_api_controller->modify_assistant_primary_params(
					$current_assistant_data['id'],
					$settings_chatgpt_model,
					$ttw_chatbot_new_magic_instructions,
					$settings_chatgpt_temperature,
					array()
				);

				//Update assistant data into local DB
				$this->update_setting( VAPPV_TTW_Settings::$settings_current_assistant_data, wp_json_encode( $current_assistant_data ) );

				//Update assistant meta into local DB
				$current_assistant_meta['updated_date'] = gmdate( 'Y-m-d H:i:s' );
				$this->update_setting( VAPPV_TTW_Settings::$settings_current_assistant_meta, wp_json_encode( $current_assistant_meta ) );

				//Log the update
				VAPPV_TTW_Core::add_log_entry(
					'info',
					esc_html(
						__( 'The settings related to the AI assistant have been updated. The assistant object in ChatGPT has also been updated.', 'talk-to-website' )
					),
					null
				);
			}
		}

		return VAPPV_TTW_Core::ajax_pack_success( array(
			'Result' => 'SETTINGS_UPDATED'
		) );
	}

	/**
	 * Get all user settings and complete $this->user_loaded_settings storage
	 * @return array
	 * @throws Exception
	 */
	public function load_all_saved_settings(): array {

		global $wpdb;

		//Get database tables prefix and other params
		$db_settings_tablename = $this->get_entity_table_name();
		$results = array();
		$rows = $wpdb->get_results( $wpdb->prepare( 'SELECT * FROM %i', array( $db_settings_tablename ) ) );

		foreach ( $rows as $row ) {
			$next_setting = array(
				'id' => $row->id,
				'tname' => $row->tname,
				'tvalue' => $this->cast_setting_value_to_its_type( $row->tname, $row->tvalue )
			);
			array_push( $results, $next_setting );
		}

		$this->user_loaded_settings = $results;
		$this->are_settings_loaded_once = true;

		return $results;
	}

	/**
	 * Get setting before output to the UI (textarea / input type=text / select, etc.).
	 * Empty string will be passed in case of empty / null values
	 * @param string $setting_name
	 *
	 * @return string
	 * @throws Exception
	 */
	public function try_get_setting_as_string(
		string $setting_name
	) {
		$setting_value = $this->try_get_setting( $setting_name );
		if ( is_null( $setting_value ) || '' === trim( strval( $setting_value ) ) ) {
			return '';
		}

		return strval( $setting_value );
	}

	/**
	 * Try get specified setting by name
	 *
	 * @param string $setting_name Setting name
	 * @param bool $use_setting_defaults_if_not_set Use default setting f value not set yet
	 * @param mixed $default_returning_value_if_not_set If setting value not set, return this value
	 * @param mixed $default_returning_value_if_null_or_empty If setting value is null, return this value
	 *
	 * @return false|mixed
	 * @throws Exception
	 */
	public function try_get_setting(
		string $setting_name,
		bool $use_setting_defaults_if_not_set = true,
		$default_returning_value_if_not_set = false,
		$default_returning_value_if_null_or_empty = false
	) {

		//Try loaded value
		foreach ( $this->user_loaded_settings as $setting_object ) {

			if ( $setting_object['tname'] === $setting_name ) {

				// Get returning value
				$returning_value = $this->cast_setting_value_to_its_type( $setting_name, $setting_object['tvalue'] );

				// Check for nullable cases
				if ( ( is_null( $returning_value ) || '' === $returning_value ) && false !== $default_returning_value_if_null_or_empty ) {
					return $default_returning_value_if_null_or_empty;
				}
				else {
					return $returning_value;
				}

			}

		}

		//Try to use default setting
		if ( true === $use_setting_defaults_if_not_set ) {

			$property_name = "{$setting_name}__default";
			if ( true === property_exists( 'VAPPV_TTW_Settings', $property_name ) ) {

				// Get default value from the storage
				$vars = get_class_vars( 'VAPPV_TTW_Settings' );
				$returning_value = $this->cast_setting_value_to_its_type( $setting_name, $vars[ $property_name ] );

				// Check for nullable cases
				if ( ( is_null( $returning_value ) || '' === $returning_value ) && false !== $default_returning_value_if_null_or_empty ) {
					return $default_returning_value_if_null_or_empty;
				}
				else {
					return $returning_value;
				}

			}

		}

		//Try to use override value
		return $default_returning_value_if_not_set;
	}

	/**
	 * Try get default setting value by it's name
	 *
	 * @param string $setting_name Setting name
	 *
	 * @return mixed|string
	 * @throws Exception
	 */
	public function try_get_default_setting( string $setting_name ) {
		$property_name = "{$setting_name}__default";
		if ( true === property_exists( 'VAPPV_TTW_Settings', $property_name ) ) {
			$vars = get_class_vars( 'VAPPV_TTW_Settings' );
			return $vars[ $property_name ];
		}
		return '';
	}

	/**
	 * Get setting before output to the UI (textarea / input type=text / select, etc.).
	 * Empty string will be passed in case of empty / null values
	 * @param string $setting_name
	 *
	 * @return string
	 * @throws Exception
	 */
	public function try_get_default_setting_as_string(
		string $setting_name
	) {
		$setting_value = $this->try_get_default_setting( $setting_name );
		if ( is_null( $setting_value ) || '' === trim( strval( $setting_value ) ) ) {
			return '';
		}

		return strval( $setting_value );
	}

	/**
	 * Cast setting value to its original type
	 *
	 * @param string $setting_name Setting name
	 * @param mixed $setting_value Setting value
	 *
	 * @return float|int|mixed|string|null
	 * @throws Exception
	 */
	public function cast_setting_value_to_its_type( string $setting_name, $setting_value ) {

		//Return null for empty values
		if ( '' === $setting_value || null === $setting_value ) {
			return null;
		}

		//Get setting type and cast value
		$property_type_field = "{$setting_name}__type";
		if ( true === property_exists( 'VAPPV_TTW_Settings', $property_type_field ) ) {

			$vars          = get_class_vars( 'VAPPV_TTW_Settings' );
			$property_type = $vars[ $property_type_field ];

			switch ( $property_type ) {
				case 'integer':
				case 'int':
					return intval( $setting_value );
				case 'double':
				case 'float':
					return floatval( $setting_value );
				case 'string':
					return (string) $setting_value;
			}
		}

		return $setting_value;
	}

	/**
	 * Check is the plugin enabled and active right now
	 * @return array
	 * @throws Exception
	 */
	public function is_plugin_active_right_now(): array {

		$plugin_current_activity_state = array(
			'IsActive'                          => true,
			'PluginIsNotActiveCode'             => null,
			'PluginIsNotActiveExtraInformation' => null
		);

		//Check is activeded, check is ChatGPT key set, check working time, check is enabled now
		if ( false === $this->are_settings_loaded_once ) {
			$this->load_all_saved_settings();
		}

		//Are settings saved once (at least)
		$primary_settings_saved = $this->try_get_setting( VAPPV_TTW_Settings::$primary_settings_saved );
		if (
			is_null( $primary_settings_saved ) ||
			'no' === $primary_settings_saved
		) {
			$plugin_current_activity_state['IsActive']                          = false;
			$plugin_current_activity_state['PluginIsNotActiveCode']             = 'PLUGIN_IS_NOT_CONFIGURED_YET';
			$plugin_current_activity_state['PluginIsNotActiveExtraInformation'] = esc_html(
				__( 'Plugin is not configured yet.', 'talk-to-website' )
			);
			return $plugin_current_activity_state;
		}

		//Is ChatGPT key configured
		$settings_openai_api_key = $this->try_get_setting( VAPPV_TTW_Settings::$settings_openai_api_key );
		if (
			is_null( $settings_openai_api_key ) ||
			'' === $settings_openai_api_key
		) {
			$plugin_current_activity_state['IsActive']                          = false;
			$plugin_current_activity_state['PluginIsNotActiveCode']             = 'CHATGPT_API_KEY_IS_NOT_SET';
			$plugin_current_activity_state['PluginIsNotActiveExtraInformation'] = esc_html(
				__( 'Plugin is not connected to OpenAI. Please set API key.', 'talk-to-website' )
			);
			return $plugin_current_activity_state;
		}

		//Is plugin (AI) trained
		$settings_current_assistant_data = $this->try_get_setting( VAPPV_TTW_Settings::$settings_current_assistant_data );
		if (
			is_null( $settings_current_assistant_data ) ||
			'' === $settings_current_assistant_data
		) {
			$plugin_current_activity_state['IsActive']                          = false;
			$plugin_current_activity_state['PluginIsNotActiveCode']             = 'CHATGPT_AI_IS_NOT_TRAINED_YET';
			$plugin_current_activity_state['PluginIsNotActiveExtraInformation'] = esc_html(
				__( 'Plugin is not trained. Please train AI to start using the plugin.', 'talk-to-website' )
			);
			return $plugin_current_activity_state;
		}

		//Is plugin displayed right now (direct property)
		$settings_is_chatbot_displayed_right_now = $this->try_get_setting( VAPPV_TTW_Settings::$settings_is_chatbot_displayed_right_now );
		if (
			! is_null( $settings_is_chatbot_displayed_right_now ) &&
			(
				'0' === $settings_is_chatbot_displayed_right_now ||
				0 === (integer)$settings_is_chatbot_displayed_right_now
			)
		) {
			$plugin_current_activity_state['IsActive']                          = false;
			$plugin_current_activity_state['PluginIsNotActiveCode']             = 'PLUGIN_IS_DISABLED_DIRECTLY';
			$plugin_current_activity_state['PluginIsNotActiveExtraInformation'] = esc_html(
				__( 'Plugin is disabled by Admin. Please check "Is chat-bot displayed on the website right now" setting.', 'talk-to-website' )
			);
			return $plugin_current_activity_state;
		}

		//Can we show the plugin on specified page
		$settings_chat_restricted_pages_urlmasks = $this->try_get_setting( VAPPV_TTW_Settings::$settings_chat_restricted_pages_urlmasks );

		if (
			isset( $_SERVER['HTTP_HOST'] ) &&
			isset( $_SERVER['REQUEST_URI'] )
		) {

			$page_current_url = sanitize_url(
				sprintf(
					'%1$s://%2$s',
					( empty( $_SERVER['HTTPS'] ) ? 'http' : 'https' ),
					sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) .
					sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) )
				),
				array(
					'http',
					'https'
				)
			);

			if (
				! is_null( $settings_chat_restricted_pages_urlmasks ) &&
				'' !== trim( $settings_chat_restricted_pages_urlmasks )
			) {

				//Compare current page URL and restricted pages list
				$restricted_pages_masks = explode( ',', $settings_chat_restricted_pages_urlmasks );
				for ( $q = 0; $q < count( $restricted_pages_masks ); $q++ ) {
					if ( false !== mb_strpos( $page_current_url, $restricted_pages_masks[ $q ], 0, 'utf-8' ) ) {
						$plugin_current_activity_state['IsActive']                          = false;
						$plugin_current_activity_state['PluginIsNotActiveCode']             = 'PLUGIN_IS_RESTRICTED_ON_THIS_PAGE';
						$plugin_current_activity_state['PluginIsNotActiveExtraInformation'] = esc_html(
							__( 'Plugin is hidden on this page. Please check "Restrict the display of chat on specified pages of the site" setting.', 'talk-to-website' )
						);
						return $plugin_current_activity_state;
						break;
					}
				}

			}

		}

		return $plugin_current_activity_state;
	}

	/**
	 * Change "Is enabled" setting to 1 (enabled)
	 * @return array
	 * @throws Exception
	 */
	public function quick_action_enable_plugin(): array {
		$this->load_all_saved_settings();
		$this->update_setting( VAPPV_TTW_Settings::$settings_is_chatbot_displayed_right_now, 1 );
		VAPPV_TTW_Core::add_log_entry(
			'info',
			esc_html(
				__( 'Plugin enabled by administrator (Quick action).', 'talk-to-website' )
			),
			null
		);
		return VAPPV_TTW_Core::ajax_pack_success( array(
			'Result' => 'PLUGIN_ENABLED'
		) );
	}

	/**
	 * Change "Is enabled" setting to 0 (disabled)
	 * @return array
	 * @throws Exception
	 */
	public function quick_action_disable_plugin(): array {
		$this->load_all_saved_settings();
		$this->update_setting( VAPPV_TTW_Settings::$settings_is_chatbot_displayed_right_now, 0 );
		VAPPV_TTW_Core::add_log_entry(
			'info',
			esc_html(
				__( 'Plugin disabled by administrator (Quick action).', 'talk-to-website' )
			),
			null
		);
		return VAPPV_TTW_Core::ajax_pack_success( array(
			'Result' => 'PLUGIN_DISABLED'
		) );
	}
}

/*
	© 2024 Copyright Vitalii A. Popov. All rights reserved.
*/

?>