<?php

namespace DeliciousBrains\WPMDB\Common\Migration;

use DeliciousBrains\WPMDB\Common\Filesystem\Filesystem;
use DeliciousBrains\WPMDB\Common\MigrationPersistence\Persistence;
use DeliciousBrains\WPMDB\Common\Multisite\Multisite;
use DeliciousBrains\WPMDB\Common\Plugin\Assets;
use DeliciousBrains\WPMDB\Common\Properties\Properties;
use DeliciousBrains\WPMDB\Common\Settings\Settings;
use DeliciousBrains\WPMDB\Common\Sql\Table;
use DeliciousBrains\WPMDB\Common\Util\Util;
use DeliciousBrains\WPMDB\Data\Stage;
use DeliciousBrains\WPMDB\Common\Compatibility\Layers\Platforms\Platforms;

class MigrationHelper {
	/**
	 * The delimiter used to separate positional data elements in returned data.
	 */
	const DATA_DELIMITER = '##MDB_SEPARATOR##';

	/**
	 * @var Multisite
	 */
	private $multisite;

	/**
	 * @var Util
	 */
	private $util;

	/**
	 * @var Table
	 */
	private $tables;

	/**
	 * @var Filesystem
	 */
	private $filesystem;

	/**
	 * @var Properties
	 */
	private $props;

	/**
	 * @var Settings
	 */
	private $settings;

	/**
	 * @var Assets
	 */
	private $assets;

	public function __construct(
		Multisite $multisite,
		Util $util,
		Table $tables,
		Filesystem $filesystem,
		Properties $props,
		Settings $settings,
		Assets $assets

	) {
		$this->multisite  = $multisite;
		$this->util       = $util;
		$this->tables     = $tables;
		$this->filesystem = $filesystem;
		$this->props      = $props;
		$this->settings   = $settings->get_settings();
		$this->assets     = $assets;
	}

	/**
	 * Merge local and remote site details.
	 *
	 * @param array $state_data
	 *
	 * @return array
	 **/
	public function getMergedSiteDetails( $state_data ) {
		$local       = $this->util->site_details( $state_data );
		$remote_info = get_site_option( WPMDB_REMOTE_RESPONSE_OPTION );
		$remote      = ! empty( $remote_info ) ? $remote_info['site_details'] : '';

		return [
			'local'  => $local,
			'remote' => $remote,
		];
	}

	/**
	 * Get extended site details info.
	 *
	 * @return array
	 */
	public function siteDetails() {
		$site_details = $this->util->site_details();
		$url          = esc_html( addslashes( Util::home_url() ) );

		return [
			'connection_info'               => $this->get_connection_info(),
			'this_url'                      => $url,
			'this_path'                     => esc_html( addslashes( Util::get_absolute_root_file_path() ) ),
			'this_domain'                   => esc_html( $this->multisite->get_domain_current_site() ),
			'this_platform'					=> Platforms::get_platform(),
			'this_tables'                   => $this->tables->get_tables(),
			'this_prefixed_tables'          => $this->tables->get_tables( 'prefix' ),
			'this_table_sizes'              => $this->tables->get_table_sizes(),
			'this_table_sizes_hr'           => array_map(
				array(
					$this->tables,
					'format_table_sizes',
				),
				$this->tables->get_table_sizes()
			),
			'this_table_rows'               => $this->tables->get_table_row_counts(),
			'this_upload_url'               => esc_html( addslashes( trailingslashit( Filesystem::get_upload_info( 'url' ) ) ) ),
			'this_upload_dir_long'          => esc_html( addslashes( trailingslashit( Filesystem::get_upload_info( 'path' ) ) ) ),
			'this_wp_upload_dir'            => $this->filesystem->get_wp_upload_dir(),
			// TODO: Remove backwards compatibility.
			'this_uploads_dir'              => $site_details['uploads_dir'],
			'this_plugin_url'               => trailingslashit( plugins_url( $this->props->plugin_folder_name ) ),
			'this_website_name'             => sanitize_title_with_dashes( DB_NAME ),
			'this_download_url'             => network_admin_url( $this->props->plugin_base . '&download=' ),
			// TODO: Remove backwards compatibility.
			'this_prefix'                   => $site_details['prefix'],
			'this_temp_prefix'              => $this->props->temp_prefix,
			'this_plugin_base'              => esc_html( $this->props->plugin_base ),
			'this_post_types'               => $this->tables->get_post_types(),
			'url'                           => $url,
			// TODO: Remove backwards compatibility.
			'is_multisite'                  => $site_details['is_multisite'],
			'openssl_available'             => esc_html( $this->util->open_ssl_enabled() ? 'true' : 'false' ),
			'max_request'                   => esc_html( $this->settings['max_request'] ),
			'delay_between_requests'        => esc_html( $this->settings['delay_between_requests'] ),
			'prog_tables_hidden'            => ( bool ) $this->settings['prog_tables_hidden'],
			'pause_before_finalize'         => ( bool ) $this->settings['pause_before_finalize'],
			'bottleneck'                    => esc_html( $this->util->get_bottleneck( 'max' ) ),
			// TODO: Use WP_Filesystem API.
			'write_permissions'             => esc_html( is_writable( Filesystem::get_upload_info( 'path' ) ) ? 'true' : 'false' ),
			'themes_permissions'            => is_writeable( Util::get_stage_base_dir( Stage::THEME_FILES ) ) ? 'true' : 'false',
			'plugins_permissions'           => is_writeable( Util::get_stage_base_dir( Stage::PLUGIN_FILES ) ) ? 'true' : 'false',
			'muplugins_permissions'         => is_writeable( Util::get_stage_base_dir( Stage::MUPLUGIN_FILES ) ) ? 'true' : 'false',
			'others_permissions'            => is_writeable( Util::get_stage_base_dir( Stage::OTHER_FILES ) ) ? 'true' : 'false',
			'root_permissions'              => is_writeable( Util::get_stage_base_dir( 'root' ) ) ? 'true' : 'false',
			'firewall_plugins'              => $site_details['firewall_plugins'],
			'profile'                       => isset( $_GET['wpmdb-profile'] ) ? $_GET['wpmdb-profile'] : '-1',
			'is_pro'                        => esc_html( $this->props->is_pro ? 'true' : 'false' ),
			'lower_case_table_names'        => esc_html( $this->tables->get_lower_case_table_names_setting() ),
			// TODO: Remove backwards compatibility.
			'subsites'                      => $site_details['subsites'],
			'site_details'                  => $site_details,
			'alter_table_name'              => $this->tables->get_alter_table_name(),
			'allow_tracking'                => $this->settings['allow_tracking'],
			'MDB_API_BASE'                  => $this->util->rest_url(),
			'diagnostic_log_download_url'   => network_admin_url( $this->props->plugin_base . '&nonce=' . Util::create_nonce( 'wpmdb-download-log' ) . '&wpmdb-download-log=1' ),
			'migration_profiles'            => $this->assets->get_saved_migration_profiles(),
			'mst_available'                 => Util::isPro() && Util::is_addon_registered( 'mst' ),
			'tpf_available'                 => Util::is_addon_registered( 'tpf' ),
			'mf_available'                  => Util::is_addon_registered( 'mf' ),
			'mst_required_message_push'     => $this->multisite->mst_required_message( 'push' ),
			'mst_required_message_pull'     => $this->multisite->mst_required_message( 'pull' ),
			'time_format'                   => get_option( 'time_format' ),
			'theoreticalTransferBottleneck' => apply_filters(
				'wpmdb_theoretical_transfer_bottleneck',
				0
			),
		];
	}

	/**
	 * Returns the local site's connection info.
	 *
	 * @return array
	 */
	public function get_connection_info() {
		return apply_filters(
			'wpmdb_get_connection_info',
			array(
				site_url( '', 'https' ),
				$this->settings['key'],
			)
		);
	}

	/**
	 * Get the migration ID that is currently being processed.
	 *
	 * @return false|string
	 */
	public static function get_current_migration_id() {
		global $wpmdb_current_migration_id;

		// The functions that respond to remote requests always set this.
		if ( ! empty( $wpmdb_current_migration_id ) ) {
			return $wpmdb_current_migration_id;
		}

		// Otherwise, should be handling a local process where options data is available.
		$options = Persistence::getMigrationOptions();

		if ( empty( $options['current_migration']['migration_id'] ) || ! is_string( $options['current_migration']['migration_id'] ) ) {
			return false;
		}

		static::set_current_migration_id( $options['current_migration']['migration_id'] );

		return $options['current_migration']['migration_id'];
	}

	/**
	 * Set the current migration ID so that it can be retrieved easily.
	 *
	 * @param string $migration_id
	 *
	 * @return void
	 */
	public static function set_current_migration_id( $migration_id ) {
		global $wpmdb_current_migration_id;

		if ( ! empty( $migration_id ) && is_string( $migration_id ) ) {
			$wpmdb_current_migration_id = $migration_id;
		}
	}

	/**
	 * Are we handling a request as the remote?
	 *
	 * @return bool
	 */
	public static function is_remote() {
		global $wpmdb_is_remote;

		return (bool) $wpmdb_is_remote;
	}

	/**
	 * Set this process as handling a request as the remote.
	 *
	 * @return void
	 */
	public static function set_is_remote() {
		global $wpmdb_is_remote;

		$wpmdb_is_remote = true;
	}

	/**
	 * Should any processing continue?
	 *
	 * @return bool
	 */
	public static function should_continue() {
		// At the moment, processing on the remote carries on until natural
		// bottlenecks are met, but in the future we could pass across time
		// or other limits to be adhered to.
		return static::is_remote() || apply_filters( 'wpmdb_should_continue', true );
	}
}
