<?php
/**
 * Controller: DB Connection.
 *
 * Connection class file.
 *
 * @since     4.6
 *
 * @package   wsal
 * @subpackage controllers
 *
 * @author Stoil Dobrev <sdobreff@gmail.com>
 */

declare(strict_types=1);

namespace WSAL\Controllers;

use WSAL\Helpers\Classes_Helper;
use WSAL\Helpers\Settings_Helper;
use WSAL\Entities\Metadata_Entity;
use WSAL\Entities\Occurrences_Entity;
use WSAL\Entities\Archive\Archive_Records;
use WSAL\Entities\DBConnection\MySQL_Connection;

// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( '\WSAL\Controllers\Connection' ) ) {
	/**
	 * Provides connection to the DB (WPDB instance).
	 *
	 * @since 4.6.0
	 */
	class Connection {
		/**
		 * Holds the configuration of the connection (if there is one).
		 *
		 * @var bool
		 *
		 * @since 4.6.0
		 */
		private static $connection_config = false;

		/**
		 * Holds the connection (if there is one).
		 *
		 * @var bool|\WPDB
		 *
		 * @since 4.6.0
		 */
		private static $connection = false;

		/**
		 * Enabled archive mode. It forces archive connector by default.
		 *
		 * @var bool
		 *
		 * @since 4.6.0
		 */
		private static $archive_mode = false;

		/**
		 * Local cache for mirror types.
		 *
		 * @var array
		 *
		 * @since 5.0.0
		 */
		private static $mirror_types;

		/**
		 * Archive DB Connection Object.
		 *
		 * @var object
		 *
		 * @since 5.0.0
		 */
		private static $archive_db = null;

		/**
		 * Get the adapter config stored in the DB.
		 *
		 * @param string|null $connection_name - The connection name to extract the configuration for. Default is used if null.
		 *
		 * @return array|null adapter config
		 *
		 * @since 4.6.0
		 */
		public static function get_config( $connection_name = null ) {
			if ( null !== $connection_name ) {
				$connection_config = self::load_connection_config( $connection_name );

				return $connection_config;
			}
			if ( false === self::$connection_config ) {
				$connection_name = Settings_Helper::get_option_value( 'adapter-connection' );

				if ( empty( $connection_name ) ) {
					self::$connection_config = null;
				}

				self::$connection_config = self::load_connection_config( $connection_name );
			}

			return self::$connection_config;
		}

		/**
		 * Loads connection config using its name.
		 *
		 * @param string $connection_name Connection name.
		 *
		 * @return array|null
		 *
		 * @since 4.6.0
		 */
		public static function load_connection_config( $connection_name ) {
			if ( empty( $connection_name ) ) {
				// No connection - means default \WPDB connection.
				return null;
			}

			/**
			 * Reused code from the external DB module.
			 *
			 * @see WSAL_Ext_Common::get_connection()
			 */
			$connection_raw = maybe_unserialize( Settings_Helper::get_option_value( 'connection-' . $connection_name ) );

			$connection = ( $connection_raw instanceof \stdClass ) ? json_decode( json_encode( $connection_raw ), true ) : $connection_raw;
			if ( ! is_array( $connection ) || empty( $connection ) ) {
				return null;
			}

			return $connection;
		}

		/**
		 * Returns the connection to specified connection name or the default used if no name is specified.
		 *
		 * @param string|null $connection_name - The connection name to extract the configuration and create connection. Default is used if null.
		 *
		 * @return \wpdb
		 *
		 * @since 4.6.0
		 */
		public static function get_connection( $connection_name = null ) {
			return self::create_connection( $connection_name );
		}

		/**
		 * Destroys the current connection
		 *
		 * @return void
		 *
		 * @since 4.6.0
		 */
		public static function destroy_connection() {
			self::$connection = false;
		}

		/**
		 * Closes the DB connection.
		 *
		 * @return bool
		 *
		 * @since 4.6.0
		 */
		public static function close_connection() {
			$current_wpdb = self::get_connection();

			return $current_wpdb->close();
		}

		/**
		 * Decrypt the encrypted string.
		 * Decrypt string, after reads it from the DB.
		 *
		 * @param string $ciphertext_base64 - encrypted string.
		 *
		 * @return string
		 *
		 * @since 4.6.0
		 */
		public static function decrypt_string( $ciphertext_base64 ) {
			$encrypt_method = 'AES-256-CBC';
			$secret_key     = self::truncate_key();
			$secret_iv      = self::get_openssl_iv();

			// Hash the key.
			$key = hash( 'sha256', $secret_key );

			// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning.
			$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );

			return openssl_decrypt( base64_decode( $ciphertext_base64 ), $encrypt_method, $key, 0, $iv );
		}

		/**
		 * Enables archive mode.
		 *
		 * @since 4.6.0
		 */
		public static function enable_archive_mode() {
			self::$archive_mode = true;
		}

		/**
		 * Is that an archive connection or not?
		 *
		 * @return boolean
		 *
		 * @since 4.6.0
		 */
		public static function is_archive_mode() {
			return self::$archive_mode;
		}

		/**
		 * Disables archive mode.
		 *
		 * @since 4.6.0
		 */
		public static function disable_archive_mode() {
			self::$archive_mode = false;
		}

		/**
		 * Test the connection.
		 *
		 * @param array $connection_config - Connection configuration to test.
		 *
		 * @return bool
		 * @throws \Exception - Connection failed.
		 *
		 * @since 4.6.0
		 */
		public static function test_connection( ?array $connection_config = null ) {
			error_reporting( E_ALL ^ ( E_NOTICE | E_WARNING | E_DEPRECATED ) );
			if ( ! $connection_config ) {
				$connection_config = self::get_config();
			}

			if ( ! $connection_config ) {
				// No configuration provided or config is empty - that means that local DB is in use - return true.
				return true;
			}
			$password = self::decrypt_string( $connection_config['password'] );

			$db_port_value = $connection_config['port'] ?? '';

			$new_wpdb = new MySQL_Connection( $connection_config['user'], $password, $connection_config['db_name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'], $db_port_value ); // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_connection

			if ( isset( $new_wpdb->error ) && isset( $new_wpdb->dbh ) ) {
				throw new \Exception( $new_wpdb->dbh->error, $new_wpdb->dbh->errno ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			} elseif ( ! isset( $new_wpdb->dbh ) ) {
				$error_code = mysqli_connect_errno(); // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_connect_errno

				if ( 1045 === $error_code ) {
					throw new \Exception( __( 'Error establishing a database connection. DB username or password are not valid.' ), $error_code ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
				} else {
					$error_message = mysqli_connect_error(); // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysqli_connect_error
					// if we get an error message from mysqli then use it otherwise use a generic message.
					if ( $error_message ) {
						throw new \Exception(
							sprintf(
							/* translators: 1 - mysqli error code, 2 - mysqli error message */
								__( 'Code %1$d: %2$s', 'wp-security-audit-log' ), // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
								\esc_attr( $error_code ),
								\esc_attr( $error_message )
							),
							$error_code  // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
						);
					}
				}
			} elseif ( isset( $new_wpdb->db_select_error ) ) {
				throw new \Exception( 'Error: Database ' . $connection_config['db_name'] . ' is unknown.', 1046 ); // phpcs:ignore WordPress.Security.EscapeOutput.ExceptionNotEscaped
			} elseif ( ! $new_wpdb->has_connected ) {
				throw new \Exception( 'Error establishing a database connection.' );
			} else {
				return true;
			}
		}

		/**
		 * Displays admin notice if database connection is not available.
		 *
		 * @since 4.6.0
		 */
		public static function display_notice_if_connection_not_available() {
			// Check database connection.
			$wsal_db = self::get_connection();

			// Add connectivity notice.
			if ( ! $wsal_db->check_connection( false ) ) {
				?>
			<div class="notice notice-error">
				<p><?php esc_html_e( 'There are connectivity issues with the database where the WordPress activity log is stored.', 'wp-security-audit-log' ); ?></p>
			</div>
				<?php
			}
		}

		/**
		 * Check the adapter config with a test connection.
		 *
		 * @param array $config Configuration data.
		 *
		 * @return boolean true|false
		 *
		 * @throws \Exception - Connection failed.
		 *
		 * @since 4.6.0
		 */
		public static function check_config( $config ) {
			// Only mysql supported at the moment.
			if ( array_key_exists( 'type', $config ) && 'mysql' === $config['type'] ) {
				try {
					return self::test_connection( $config );
				} catch ( \Exception $e ) {
					return false;
				}
			}

			return false;
		}

		/**
		 * Encrypt plain text.
		 * Encrypt string, before saves it to the DB.
		 *
		 * @param string $plaintext - Plain text that is going to be encrypted.
		 *
		 * @return string
		 * @since  2.6.3
		 */
		public static function encrypt_string( $plaintext ) {

			$ciphertext     = false;
			$encrypt_method = 'AES-256-CBC';
			$secret_key     = self::truncate_key();
			$secret_iv      = self::get_openssl_iv();

			// Hash the key.
			$key = hash( 'sha256', $secret_key );

			// iv - encrypt method AES-256-CBC expects 16 bytes - else you will get a warning.
			$iv = substr( hash( 'sha256', $secret_iv ), 0, 16 );

			$ciphertext = openssl_encrypt( $plaintext, $encrypt_method, $key, 0, $iv );
			$ciphertext = base64_encode( $ciphertext ); // phpcs:ignore

			return $ciphertext;
		}

		/**
		 * Truncate string longer than 32 characters.
		 * Authentication Unique Key.
		 *
		 * @return string AUTH_KEY
		 *
		 * @see wp-config.php
		 *
		 * @since 4.6.0
		 */
		private static function truncate_key() {
			if ( ! defined( 'AUTH_KEY' ) ) {
				return 'x4>Tg@G-Kr6a]o-eJeP^?UO)KW;LbV)I';
			}
			$key_size = strlen( AUTH_KEY );
			if ( $key_size > 32 ) {
				return substr( AUTH_KEY, 0, 32 );
			} else {
				return AUTH_KEY;
			}
		}

		/**
		 * Get OpenSSL IV for DB.
		 *
		 * @since 4.6.0
		 */
		private static function get_openssl_iv() {
			$secret_openssl_iv = 'і-(аэ┤#≥и┴зейН';
			$key_size          = strlen( $secret_openssl_iv );
			if ( $key_size > 32 ) {
				return substr( $secret_openssl_iv, 0, 32 );
			} else {
				return $secret_openssl_iv;
			}
		}

		/**
		 * Creates a connection and returns it.
		 *
		 * @param string|null $connection_name - The connection name to extract the configuration and create connection. Default is used if null.
		 *
		 * @return wpdb Instance of WPDB.
		 *
		 * @since 4.6.0
		 */
		private static function create_connection( $connection_name = null ) {
			if ( 'local' === $connection_name ) {
				global $wpdb;

				return $wpdb;
			}
			if ( null !== $connection_name ) {
				$connection_config = self::load_connection_config( $connection_name );

				return self::build_connection( $connection_config );
			}
			if ( false === self::$connection ) {
				$connection_config = self::get_config( $connection_name );

				self::$connection = self::build_connection( $connection_config );

				return self::$connection;
			} elseif ( self::$connection instanceof \wpdb ) {
				return self::$connection;
			} else {
				global $wpdb;

				self::$connection = $wpdb;

				return self::$connection;
			}
		}

		/**
		 * Creates a new connection and returns it.
		 *
		 * @param array $connection_config - All of the connection parameters.
		 *
		 * @return \wpdb
		 *
		 * @since 4.6.0
		 */
		public static function build_connection( $connection_config = null ) {
			if ( empty( $connection_config ) ) {
				global $wpdb;

				return $wpdb;
			}

			$password = (string) $connection_config['password'] ?? '';

			$db_port_value = $connection_config['port'] ?? '';

			$password   = self::decrypt_string( $password );
			$connection = new MySQL_Connection( $connection_config['user'], $password, $connection_config['db_name'], $connection_config['hostname'], $connection_config['is_ssl'], $connection_config['is_cc'], $connection_config['ssl_ca'], $connection_config['ssl_cert'], $connection_config['ssl_key'], $db_port_value ); // phpcs:ignore WordPress.DB.RestrictedFunctions.mysql_mysql_connection

			if ( array_key_exists( 'baseprefix', $connection_config ) ) {
				$connection->set_prefix( $connection_config['baseprefix'] );
			}

			return $connection;
		}

		/**
		 * Checks is the connection is for an external database.
		 *
		 * @since 4.6.0
		 * @return boolean
		 */
		public static function is_external() {
			$db_config = self::get_config();

			return is_array( $db_config ) && ! empty( $db_config );
		}

		/**
		 * Should we write directly to the database connection or use a cron job for this.
		 *
		 * @return boolean
		 *
		 * @since 4.6.0
		 */
		public static function is_writing_directly(): bool {
			$db_config = self::get_config();
			if ( is_array( $db_config ) && ! empty( $db_config ) ) {
				if ( isset( $db_config['direct'] ) && true === (bool) $db_config['direct'] ) {
					return true;
				} else {
					return false;
				}
			}

			return true;
		}

		/**
		 * Migrate to external database.
		 *
		 * @param string $connection_name External connection name.
		 * @param int    $limit           - Limit.
		 *
		 * @return int
		 *
		 * @since 5.0.0
		 */
		public static function migrate_occurrence( $connection_name, $limit ) {
			$args['limit']      = $limit;
			$args['archive_db'] = self::get_connection( $connection_name );
			$count              = 0;

			Archive_Records::archive( $args, $count );

			return $count;
		}

		/**
		 * Migrate back to WP database
		 *
		 * @param int $limit - Limit.
		 *
		 * @return int
		 *
		 * @since 5.0.0
		 */
		public static function migrate_back_occurrence( $limit ) {
			global $wpdb;

			$args['limit']      = $limit;
			$args['archive_db'] = $wpdb;
			$count              = 0;

			Archive_Records::archive( $args, $count );

			return $count;
		}

		/**
		 * Recreate DB tables on WP.
		 *
		 * @since 5.0.0
		 */
		public static function recreate_tables() {
			Occurrences_Entity::create_table();
			Metadata_Entity::create_table();
		}

		/**
		 * Set Connection Object.
		 *
		 * @since 5.0.0
		 *
		 * @param array|\stdClass $connection - Connection object.
		 */
		public static function save_connection( $connection ) {
			// Stop here if no connection provided.
			if ( empty( $connection ) ) {
				return;
			}

			if ( $connection instanceof \stdClass ) {
				$connection = (array) $connection;
			}

			if ( isset( $connection['name'] ) ) {
				$connection_name = $connection['name'];

				Settings_Helper::set_option_value( WSAL_CONN_PREFIX . $connection_name, $connection );
			}
		}

		/**
		 * Delete Connection Object.
		 *
		 * @param string $connection_name - Connection name.
		 *
		 * @since 5.0.0
		 */
		public static function delete_connection( $connection_name ) {
			$connection = self::load_connection_config( $connection_name );

			if ( is_array( $connection ) && array_key_exists( 'type', $connection ) ) {
				Alert_MAnager::trigger_event_if(
					6320,
					array(
						'EventType' => 'deleted',
						'type'      => $connection['type'],
						'name'      => $connection_name,
					),
					function () {
						return ! Alert_Manager::will_trigger( 6321 );
					}
				);
			}

			Settings_Helper::delete_option_value( WSAL_CONN_PREFIX . $connection_name );
		}

		/**
		 * Remove External DB config.
		 *
		 * @since 5.0.0
		 */
		public static function remove_external_storage_config() {
			// Get archive connection.
			$adapter_conn_name = Settings_Helper::get_option_value( 'adapter-connection' );
			if ( $adapter_conn_name ) {
				$adapter_connection             = self::load_connection_config( $adapter_conn_name );
				$adapter_connection['used_for'] = '';
				self::save_connection( $adapter_connection );
			}

			Settings_Helper::delete_option_value( 'adapter-connection' );
		}

		/**
		 * Updates given connection to be used for external storage.
		 *
		 * @param string $connection_name Connection name.
		 * @since 5.0.0
		 */
		public static function update_connection_as_external( $connection_name ) {
			// Set external storage to be used for logging events from now on.
			$db_connection = self::load_connection_config( $connection_name );

			// Error handling.
			if ( empty( $db_connection ) ) {
				return false;
			}

			// Set connection's used_for attribute.
			$db_connection['used_for'] = __( 'External Storage', 'wp-security-audit-log' );
			Settings_Helper::set_option_value( 'adapter-connection', $connection_name, true );
			self::save_connection( $db_connection );

			return true;
		}

		/**
		 * Finds all mirrors using a specific connection.
		 *
		 * @param string $connection_name Connection name.
		 *
		 * @return array[]
		 * @since 5.0.0
		 */
		public static function get_mirrors_by_connection_name( $connection_name ) {
			$mirrors = Settings_Helper::get_all_mirrors();
			$result  = array();
			if ( ! empty( $mirrors ) ) {
				foreach ( $mirrors as $mirror ) {
					if ( $connection_name === $mirror['connection'] ) {
						array_push( $result, $mirror );
					}
				}
			}

			return $result;
		}

		/**
		 * Gets mirror types.
		 *
		 * @return array List of mirror types.
		 *
		 * @since 5.0.0
		 */
		public static function get_mirror_types() {
			if ( ! isset( self::$mirror_types ) ) {

				$mirrors = Classes_Helper::get_classes_by_namespace( 'WSAL\Extensions\ExternalDB\Mirrors' );

				$result = array();

				foreach ( $mirrors as $mirror ) {
					$result [ $mirror::get_type() ] = array(
						'name'   => $mirror::get_name(),
						'config' => $mirror::get_config_definition(),
						'class'  => $mirror,
					);
				}

				// $file_filter = $this->get_base_dir() . 'classes' . DIRECTORY_SEPARATOR . 'mirrors' . DIRECTORY_SEPARATOR . '*Connection.php';
				// foreach ( glob( $file_filter ) as $file ) {
				// $base_filename = basename( $file );
				// $class_name    = 'WSAL_Ext_Mirrors_' . substr( $base_filename, 0, strlen( $base_filename ) - 4 );
				// try {
				// require_once $file;
				// $result [ $class_name::get_type() ] = array(
				// 'name'   => $class_name::get_name(),
				// 'config' => $class_name::get_config_definition(),
				// 'class'  => $class_name,
				// );
				// } catch ( Exception $exception ) {  // phpcs:ignore
				// Skip unsuitable class.
				// TODO log to debug log.
				// }
				// }

				self::$mirror_types = $result;
			}

			return self::$mirror_types;
		}

		/**
		 * Delete mirror.
		 *
		 * @param string $mirror_name - Mirror name.
		 *
		 * @since 5.0.0
		 */
		public static function delete_mirror( $mirror_name ) {

			Alert_Manager::trigger_event(
				6326,
				array(
					'EventType' => 'deleted',
					'name'      => $mirror_name,
				)
			);

			Settings_Helper::delete_option_value( \WSAL_MIRROR_PREFIX . $mirror_name );
		}

		/**
		 * Set Mirror Object.
		 *
		 * @since 5.0.0
		 *
		 * @param array|\stdClass $mirror Mirror data.
		 */
		public static function save_mirror( $mirror ) {
			if ( empty( $mirror ) ) {
				return;
			}

			$mirror_name = ( $mirror instanceof \stdClass ) ? $mirror->name : $mirror['name'];

			$old_value = Settings_Helper::get_option_value( \WSAL_MIRROR_PREFIX . $mirror_name );

			if ( ! isset( $old_value['state'] ) ) {
				Alert_Manager::trigger_event(
					6323,
					array(
						'EventType'  => 'added',
						'connection' => ( $mirror instanceof \stdClass ) ? $mirror->connection : $mirror['connection'],
						'name'       => $mirror_name,
					)
				);
			} elseif ( isset( $old_value['state'] ) && $old_value['state'] !== $mirror['state'] ) {
				Alert_Manager::trigger_event(
					6325,
					array(
						'EventType'  => ( $mirror['state'] ) ? 'enabled' : 'disabled',
						'connection' => ( $mirror instanceof \stdClass ) ? $mirror->connection : $mirror['connection'],
						'name'       => $mirror_name,
					)
				);
			} else {
				Alert_Manager::trigger_event(
					6324,
					array(
						'EventType'  => 'modified',
						'connection' => ( $mirror instanceof \stdClass ) ? $mirror->connection : $mirror['connection'],
						'name'       => $mirror_name,
					)
				);
			}

			Settings_Helper::set_option_value( \WSAL_MIRROR_PREFIX . $mirror_name, $mirror );
		}

		/**
		 * Return Mirror Object.
		 *
		 * @since 5.0.0
		 *
		 * @param string $mirror_name - Mirror name.
		 * @return array|bool
		 */
		public static function get_mirror( $mirror_name ) {
			if ( empty( $mirror_name ) ) {
				return false;
			}
			$result_raw = Settings_Helper::get_option_value( \WSAL_MIRROR_PREFIX . $mirror_name );
			$result     = maybe_unserialize( $result_raw );
			return ( $result instanceof \stdClass ) ? json_decode( json_encode( $result ), true ) : $result; // phpcs:ignore
		}

		/**
		 * Returns the archive connection or null
		 *
		 * @return \WPDB|null
		 *
		 * @since 5.0.0
		 */
		public static function get_archive_database_connection() {
			if ( ! empty( self::$archive_db ) ) {
				return self::$archive_db;
			} else {
				$connection_config = Settings_Helper::get_archive_config();
				if ( empty( $connection_config ) ) {
					return null;
				} else {
					// Get archive DB connection.
					self::$archive_db = self::build_connection( $connection_config );

					// Check object for disconnection or other errors.
					$connected = true;
					if ( isset( self::$archive_db->dbh->errno ) ) {
						$connected = ! ( 0 !== (int) self::$archive_db->dbh->errno ); // Database connection error check.
					} elseif ( is_wp_error( self::$archive_db->error ) ) {
						$connected = false;
					}

					if ( $connected ) {
						return self::$archive_db;
					} else {
						return null;
					}
				}
			}
		}

		/**
		 * Enable/Disable archiving cron job started option.
		 *
		 * @param bool $value - Value.
		 *
		 * @since 5.0.0
		 */
		public static function set_archiving_cron_started( $value ) {
			if ( ! empty( $value ) ) {
				Settings_Helper::set_option_value( 'archiving-cron-started', 1 );
			} else {
				Settings_Helper::delete_option_value( 'archiving-cron-started' );
			}
		}

		/**
		 * Archive alerts (Occurrences table)
		 *
		 * @param array $args - Arguments array.
		 *
		 * @return array|false|null
		 *
		 * @since 5.0.0
		 */
		public static function archive( $args ) {
			$args['archive_db'] = self::get_archive_database_connection();
			if ( empty( $args['archive_db'] ) ) {
				return false;
			}
			$last_created_on = Settings_Helper::get_option_value( 'archiving-last-created' );
			if ( ! empty( $last_created_on ) ) {
				$args['last_created_on'] = $last_created_on;
			}

			return Archive_Records::archive( $args );
		}

		/**
		 * Archiving alerts.
		 *
		 * @since 5.0.0
		 */
		public static function archiving_alerts() {
			if ( ! Settings_Helper::is_archiving_cron_started() ) {
				set_time_limit( 0 );
				// Start archiving.
				self::set_archiving_cron_started( true );

				$args          = array();
				$args['limit'] = 500;
				$args_result   = false;

				$num             = Settings_Helper::get_archiving_date();
				$type            = Settings_Helper::get_archiving_date_type();
				$now             = current_time( 'timestamp' );
				$args['by_date'] = strtotime( '-' . $num . ' ' . $type, $now );
				$args_result     = self::archive( $args );

				// End archiving.
				self::set_archiving_cron_started( false );
			}
		}

		/**
		 * Remove the archiving config.
		 *
		 * @since 5.0.0
		 */
		public static function remove_archiving_config() {
			// Get archive connection.
			$archive_conn_name = Settings_Helper::get_option_value( 'archive-connection' );

			if ( $archive_conn_name ) {
				$archive_connection             = self::load_connection_config( $archive_conn_name );
				$archive_connection['used_for'] = '';
				self::save_connection( $archive_connection );
			}

			Settings_Helper::delete_option_value( 'archive-connection' );
			Settings_Helper::delete_option_value( 'archiving-date' );
			Settings_Helper::delete_option_value( 'archiving-date-type' );
			Settings_Helper::delete_option_value( 'archiving-run-every' );
			Settings_Helper::delete_option_value( 'archiving-daily-e' );
			Settings_Helper::delete_option_value( 'archiving-weekly-e' );
			Settings_Helper::delete_option_value( 'archiving-week-day' );
			Settings_Helper::delete_option_value( 'archiving-time' );
			Settings_Helper::delete_option_value( 'archiving-stop' );
		}

		/**
		 * Enable/Disable archiving.
		 *
		 * @param bool $enabled - Value.
		 *
		 * @since 5.0.0
		 */
		public static function set_archiving_enabled( $enabled ) {
			Settings_Helper::set_option_value( 'archiving-e', $enabled );
			if ( empty( $enabled ) ) {
				self::remove_archiving_config();
				Settings_Helper::delete_option_value( 'archiving-last-created' );
			}
		}

		/**
		 * Returns all the connections currently stored in the options.
		 *
		 * @return array
		 *
		 * @since 4.4.3
		 */
		public static function get_all_connections() {
			$connections_options = Settings_Helper::get_options_by_prefix( WSAL_CONN_PREFIX, true );

			$connections = array();

			foreach ( $connections_options as $connection ) {

				$connection = \maybe_unserialize( $connection['option_value'] );
				if ( ! is_array( $connection ) ) {
					$connection = (array) $connection;

					self::save_connection( $connection );
				}
				$connections[] = $connection;
			}

			return $connections;
		}
	}
}
