<?php
/**
 * Setup wizard.
 *
 * @since      1.0
 * @package    RankMathPro
 * @subpackage RankMathPro\Admin
 * @author     Rank Math <support@rankmath.com>
 */

namespace RankMathPro;

use RankMath\Helper;
use RankMath\Helpers\Param;
use RankMath\Traits\Ajax;
use RankMath\Traits\Hooker;
use RankMath\Admin\Admin_Helper;
use RankMathPro\Admin\Admin_Helper as ProAdminHelper;

defined( 'ABSPATH' ) || exit;

/**
 * Trends tool class.
 *
 * @codeCoverageIgnore
 */
class Setup_Wizard {

	use Hooker;
	use Ajax;

	/**
	 * Register hooks.
	 */
	public function __construct() {
		$this->action( 'admin_init', 'enqueue', 20 );

		$this->filter( 'rank_math/setup_wizard/sitemaps/localized_data', 'add_sitemap_localized_data' );
		$this->action( 'rank_math/setup_wizard/sitemaps/save_data', 'save_sitemap_data' );
		$this->filter( 'rank_math/setup_wizard/analytics/localized_data', 'add_analytics_localized_data' );
		$this->action( 'rank_math/setup_wizard/analytics/save_data', 'save_analytics_data' );

		$this->ajax( 'import_settings', 'ajax_import_settings' );
	}

	/**
	 * Enqueue assets.
	 *
	 * @return void
	 */
	public function enqueue() {
		if ( Param::get( 'page' ) !== 'rank-math-wizard' ) {
			return;
		}

		wp_enqueue_style(
			'rank-math-pro-setup-wizard',
			RANK_MATH_PRO_URL . 'assets/admin/css/setup-wizard.css',
			[],
			rank_math_pro()->version
		);
		wp_enqueue_script(
			'rank-math-pro-setup-wizard',
			RANK_MATH_PRO_URL . 'assets/admin/js/setup-wizard.js',
			[ 'jquery', 'wp-element', 'lodash', 'rank-math-components' ],
			rank_math_pro()->version,
			true
		);
	}

	/**
	 * Ajax import settings.
	 */
	public function ajax_import_settings() {
		$this->verify_nonce( 'rank-math-ajax-nonce' );
		$this->has_cap_ajax( 'general' );

		$file = $this->has_valid_import_file();
		if ( false === $file ) {
			return false;
		}

		// Parse Options.
		$wp_filesystem = Helper::get_filesystem();
		if ( is_null( $wp_filesystem ) ) {
			return false;
		}

		$settings = $wp_filesystem->get_contents( $file['file'] );
		$settings = json_decode( $settings, true );

		\wp_delete_file( $file['file'] );

		if ( is_array( $settings ) && $this->do_import_data( $settings ) ) {
			$this->success( __( 'Import successful.', 'rank-math-pro' ) );
			exit();
		}

		$this->error( __( 'No settings found to be imported.', 'rank-math-pro' ) );
		exit();
	}

	/**
	 * Add Localized data to be used in the Sitemap step.
	 *
	 * @param array $data Localized data.
	 *
	 * @return array
	 */
	public function add_sitemap_localized_data( $data ) {
		return array_merge(
			$data,
			[
				'news-sitemap'                  => Helper::is_module_active( 'news-sitemap' ),
				'news_sitemap_publication_name' => Helper::get_settings( 'sitemap.news_sitemap_publication_name' ),
				'news_sitemap_post_type'        => Helper::get_settings( 'sitemap.news_sitemap_post_type' ),
				'video-sitemap'                 => Helper::is_module_active( 'video-sitemap' ),
				'video_sitemap_post_type'       => Helper::get_settings( 'sitemap.video_sitemap_post_type', array_keys( $data['postTypes'] ) ),

			]
		);
	}

	/**
	 * Save Sitemap data.
	 *
	 * @param array $values Values to update.
	 */
	public function save_sitemap_data( $values ) {
		$settings      = rank_math()->settings->all_raw();
		$news_sitemap  = $values['news-sitemap'];
		$video_sitemap = $values['video-sitemap'];

		Helper::update_modules( [ 'news-sitemap' => $news_sitemap ? 'on' : 'off' ] );
		Helper::update_modules( [ 'video-sitemap' => $video_sitemap ? 'on' : 'off' ] );

		if ( $news_sitemap ) {
			$settings['sitemap']['news_sitemap_publication_name'] = ! empty( $values['news_sitemap_publication_name'] ) ? sanitize_text_field( $values['news_sitemap_publication_name'] ) : '';
			$settings['sitemap']['news_sitemap_post_type']        = ! empty( $values['news_sitemap_post_type'] ) ? $values['news_sitemap_post_type'] : [];

			Helper::update_all_settings( null, null, $settings['sitemap'] );
		}

		if ( $video_sitemap ) {
			$settings['sitemap']['video_sitemap_post_type'] = ! empty( $values['video_sitemap_post_type'] ) ? $values['video_sitemap_post_type'] : [];

			Helper::update_all_settings( null, null, $settings['sitemap'] );
		}
	}

	/**
	 * Add Localized data to be used in the Sitemap step.
	 *
	 * @param array $data Localized data.
	 *
	 * @return array
	 */
	public function add_analytics_localized_data( $data ) {
		return array_merge(
			$data,
			[
				'countriesChoices3'  => ProAdminHelper::choices_countries_3(),
				'countriesChoices'   => ProAdminHelper::choices_countries(),
				'consoleEmailSendTo' => Helper::get_settings( 'general.console_email_send_to', Admin_Helper::get_registration_data()['email'] ),
				'isBusinessPlan'     => ProAdminHelper::is_business_plan(),
			]
		);
	}

	/**
	 * Save Sitemap data.
	 *
	 * @param array $values Values to update.
	 */
	public function save_analytics_data( $values ) {
		$settings['general']['console_email_send_to'] = sanitize_text_field( $values['consoleEmailSendTo'] );
		Helper::update_all_settings( $settings['general'], null, null );
	}

	/**
	 * Import has valid file.
	 *
	 * @return mixed
	 */
	private function has_valid_import_file() {
		if ( empty( $_FILES['import-me'] ) ) {  // phpcs:ignore WordPress.Security -- Verficiation is handled in the Rest function.
			$this->error( __( 'No file selected.', 'rank-math-pro' ) );
			return false;
		}

		$file = Helper::handle_file_upload();
		if ( is_wp_error( $file ) ) {
			$this->error( __( 'Settings file could not be imported:', 'rank-math-pro' ) . ' ' . $file->get_error_message() );
			return false;
		}

		if ( isset( $file['error'] ) ) {
			$this->error( __( 'Settings could not be imported:', 'rank-math-pro' ) . ' ' . $file['error'] );
			return false;
		}

		if ( ! isset( $file['file'] ) ) {
			$this->error( __( 'Settings could not be imported: Upload failed.', 'rank-math-pro' ) );
			return false;
		}

		return $file;
	}

	/**
	 * Does import data.
	 *
	 * @param  array $data           Import data.
	 * @param  bool  $suppress_hooks Suppress hooks or not.
	 * @return bool
	 */
	private function do_import_data( array $data, $suppress_hooks = false ) {
		$this->run_import_hooks( 'pre_import', $data, $suppress_hooks );

		// Import options.
		$down = $this->import_set_options( $data );

		// Import capabilities.
		if ( ! empty( $data['role-manager'] ) ) {
			$down = true;
			Helper::set_capabilities( $data['role-manager'] );
		}

		// Import redirections.
		if ( ! empty( $data['redirections'] ) ) {
			$down = true;
			$this->import_set_redirections( $data['redirections'] );
		}

		$this->run_import_hooks( 'after_import', $data, $suppress_hooks );

		return $down;
	}

	/**
	 * Set options from data.
	 *
	 * @param array $data An array of data.
	 */
	private function import_set_options( $data ) {
		$set  = false;
		$hash = [
			'modules' => 'rank_math_modules',
			'general' => 'rank-math-options-general',
			'titles'  => 'rank-math-options-titles',
			'sitemap' => 'rank-math-options-sitemap',
		];

		foreach ( $hash as $key => $option_key ) {
			if ( ! empty( $data[ $key ] ) ) {
				$set = true;
				update_option( $option_key, $data[ $key ] );
			}
		}

		return $set;
	}

	/**
	 * Set redirections.
	 *
	 * @param array $redirections An array of redirections to import.
	 */
	private function import_set_redirections( $redirections ) {
		foreach ( $redirections as $key => $redirection ) {
			$matched = \RankMath\Redirections\DB::match_redirections_source( $redirection['sources'] );
			if ( ! empty( $matched ) ) {
				continue;
			}

			$sources = maybe_unserialize( $redirection['sources'] );
			if ( ! is_array( $sources ) ) {
				continue;
			}

			\RankMath\Redirections\DB::add(
				[
					'url_to'      => $redirection['url_to'],
					'sources'     => $sources,
					'header_code' => $redirection['header_code'],
					'hits'        => $redirection['hits'],
					'created'     => $redirection['created'],
					'updated'     => $redirection['updated'],
				]
			);
		}
	}

	/**
	 * Run import hooks
	 *
	 * @param string $hook     Hook to fire.
	 * @param array  $data     Import data.
	 * @param bool   $suppress Suppress hooks or not.
	 */
	private function run_import_hooks( $hook, $data, $suppress ) {
		if ( ! $suppress ) {
			/**
			 * Fires while importing settings.
			 *
			 * @since 0.9.0
			 *
			 * @param array $data Import data.
			 */
			$this->do_action( 'import/settings/' . $hook, $data );
		}
	}
}
