<?php
/**
 * CleverReach WordPress Integration.
 *
 * @package CleverReach
 */

namespace CleverReach\WordPress;

use CleverReach\WordPress\Components\Hook_Handler;
use CleverReach\WordPress\Components\InfrastructureServices\Config_Service;
use CleverReach\WordPress\Components\Shortcode_Handler;
use CleverReach\WordPress\Components\Sync\Clear_Completed_Tasks_Task;
use CleverReach\WordPress\Components\Utility\Database;
use CleverReach\WordPress\Components\Utility\Forms_Formatter;
use CleverReach\WordPress\Components\Utility\Helper;
use CleverReach\WordPress\Components\Utility\Initializer;
use CleverReach\WordPress\Components\Utility\Task_Queue;
use CleverReach\WordPress\Components\Utility\Update\Update_Schema;
use CleverReach\WordPress\Components\Utility\Versioned_File_Reader;
use CleverReach\WordPress\Components\Wp_Clever_Reach_Widget;
use CleverReach\WordPress\Controllers\Clever_Reach_CF7_Controller;
use CleverReach\WordPress\Controllers\Clever_Reach_Frontend_Controller;
use CleverReach\WordPress\Controllers\Clever_Reach_Index;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Forms\Models\Form;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Interfaces\Proxy;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\RepositoryRegistry;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Scheduler\Models\DailySchedule;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Scheduler\Models\HourlySchedule;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Sync\ClearCompletedScheduleCheckTasksTask;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Sync\FormCacheSyncTask;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Sync\InitialSyncTask;
use CleverReach\WordPress\IntegrationCore\BusinessLogic\Sync\RegisterEventHandlerTask;
use CleverReach\WordPress\IntegrationCore\Infrastructure\Interfaces\Required\Configuration;
use CleverReach\WordPress\IntegrationCore\Infrastructure\Interfaces\Required\TaskQueueStorage;
use CleverReach\WordPress\IntegrationCore\Infrastructure\Logger\Logger;
use CleverReach\WordPress\IntegrationCore\Infrastructure\ORM\Exceptions\QueryFilterInvalidParamException;
use CleverReach\WordPress\IntegrationCore\Infrastructure\ORM\Exceptions\RepositoryClassException;
use CleverReach\WordPress\IntegrationCore\Infrastructure\ORM\Exceptions\RepositoryNotRegisteredException;
use CleverReach\WordPress\IntegrationCore\Infrastructure\ORM\QueryFilter\Operators;
use CleverReach\WordPress\IntegrationCore\Infrastructure\ORM\QueryFilter\QueryFilter;
use CleverReach\WordPress\IntegrationCore\Infrastructure\ServiceRegister;
use CleverReach\WordPress\IntegrationCore\Infrastructure\TaskExecution\Exceptions\TaskRunnerStatusStorageUnavailableException;
use CleverReach\WordPress\IntegrationCore\Infrastructure\TaskExecution\QueueItem;

/**
 * Class Plugin
 *
 * @package CleverReach\WordPress
 */
class Plugin {

	const UNCHECKED = 'unchecked';
	const CHECKED = 'checked';
	const UPDATE_OPTION_CHECKED_KEY = 'cleverreach-wp-update-checked';

	/**
	 * Database session
	 *
	 * @var \wpdb
	 */
	public $db;

	/**
	 * Plugin instance
	 *
	 * @var Plugin
	 */
	protected static $instance = null;

	/**
	 * CleverReach plugin file
	 *
	 * @var string
	 */
	private $cleverreach_plugin_file;

	/**
	 * Base url
	 *
	 * @var string
	 */
	private $base_url;

	/**
	 * Config service
	 *
	 * @var Config_Service
	 */
	private $config_service;

	/**
	 * Plugin constructor.
	 *
	 * @param \wpdb  $wpdb WordPress database session.
	 * @param string $cleverreach_plugin_file Plugin file.
	 */
	public function __construct( $wpdb, $cleverreach_plugin_file ) {
		$this->db                      = $wpdb;
		$this->cleverreach_plugin_file = $cleverreach_plugin_file;
		$this->base_url                = Helper::get_clever_reach_base_url( '/resources/' );
	}

	/**
	 * Initialize plugin
	 *
	 * @throws RepositoryClassException
	 */
	private function initialize() {
		Initializer::register();
		$this->load_plugin_init_hooks();

		if ( Helper::is_plugin_enabled() ) {
			$this->load_clever_reach_admin_menu_and_newsletter_field();
			$this->load_clever_reach_plugin_text_domain();
			$this->load_cf7_hooks();
			$hook_handler = new Hook_Handler();
			$hook_handler->register_hooks();

			$this->add_widgets_and_blocks();

			if ( $this->should_show_oauth_connection_lost_notification() ) {
				add_action( 'admin_notices', array( $this, 'show_oauth_connection_lost_message' ) );
			}
		}
	}

	/**
	 * Returns whether CleverReach OAuth connection lost notification should be shown.
	 *
	 * @return bool
	 */
	private function should_show_oauth_connection_lost_notification(  ) {
		return ! $this->is_cleverreach_page() && $this->get_config_service()->show_oauth_connection_lost_notice();
	}

	/**
	 * Returns whether the current page is a CleverReach plugin page.
	 *
	 * @return bool
	 */
	private function is_cleverreach_page() {
		return array_key_exists( 'page', $_REQUEST ) && ( 'wp-cleverreach' === $_REQUEST[ 'page' ] );
	}

	/**
	 * Ads widgets and text editor blocks
	 */
	private function add_widgets_and_blocks() {
		global $wp_version;
		if ( $this->is_user_connected() ) {
			$shortcode_handler = new Shortcode_Handler();
			$shortcode_handler->create_shortcodes();

			add_action( 'widgets_init', array( $this, 'register_widgets' ) );

			if ( version_compare( $wp_version, '5.0.0', 'ge' ) ) {
				if ( version_compare( $wp_version, '5.8', 'ge' ) ) {
					add_filter('block_categories_all', array($this, 'add_gutenberg_block_category'), 10, 2);
				} else {
					add_filter('block_categories', array($this, 'add_gutenberg_block_category'), 10, 2);
				}

				add_action( 'enqueue_block_editor_assets', array( $this, 'load_gutenberg_block' ) );
				register_block_type( 'cleverreach/subscription-form', array(
					'render_callback' => array( $this, 'render_subscription_form' ),
					'attributes'      => array(
						'formID' => array(
							'type' => 'string',
						),
						'renderForm' => array(
							'type' => 'boolean',
						),
						'className' => array(
							'type' => 'string',
						),
					),
				) );
			}

			$this->load_classic_editor_hooks();
		}
	}

	/**
	 * Add CleverReach block category to gutenberg editor
	 *
	 * @param array $categories list of categories
	 *
	 * @param       $post
	 *
	 * @return array
	 */
	public function add_gutenberg_block_category( $categories, $post ) {
		return array_merge(
			$categories,
			array(
				array(
					'slug' => 'cleverreach',
					'title' => 'CleverReach®',
				)
			)
		);
	}

	/**
	 * Creates block on gutenberg editor
	 *
	 * @throws RepositoryNotRegisteredException
	 */
	public function load_gutenberg_block() {
		wp_register_script(
			'cleverreach-forms-block',
			Helper::get_clever_reach_base_url( '/resources/js/cleverreach.gutenberg-block.js' ),
			array( 'wp-blocks', 'wp-editor', 'wp-components', 'wp-i18n', 'wp-element', 'underscore' )
		);

		wp_enqueue_script( 'cleverreach-forms-block' );

		/** @var Form[] $forms */
		$forms           = RepositoryRegistry::getRepository( Form::getClassName() )->select();
		$formatted_forms = array();
		foreach ( $forms as $form ) {
			$formatted_forms[] = array(
				'form_id' => $form->getFormId(),
				'name'    => $form->getName(),
				'content' => $form->getHtml(),
				'url'     => Helper::get_controller_url(
					'Forms',
					array(
						'action'  => 'open_form_in_cleverreach',
						'form_id' => $form->getFormId(),
					)
				),
			);
		}

		wp_localize_script( 'cleverreach-forms-block', 'cleverReachFormsBlock', array(
			'forms'            => $formatted_forms,
			'cleverreach_logo' => 'https://cloud-files.crsend.com/images/cleverreach-logo.png',
			'translations'     => $this->get_gutenberg_translations(),
		) );
	}

	/**
	 * Returns translations used in gutenberg script
	 *
	 * @return array
	 */
	private function get_gutenberg_translations()
	{
		return array(
			'subscription_form'        => __( 'Subscription form', 'cleverreach-wp' ),
			'edit_in_cleverreach'      => __( 'Edit in CleverReach®', 'cleverreach-wp' ),
			'insert_form'              => __( 'Insert CleverReach® signup form', 'cleverreach-wp' ),
			'form_settings'            => __( 'Form settings', 'cleverreach-wp' ),
			'form'                     => __( 'Form', 'cleverreach-wp' ),
		);
	}

	/**
	 * Creates CleverReach button on TinyMCE editor.
	 */
	private function load_classic_editor_hooks() {
		add_filter( 'tiny_mce_before_init', array( $this, 'cleverreach_add_base_url' ) );
		add_filter( 'mce_buttons', array( $this, 'cleverreach_register_toolbar_button' ) );
		add_filter( 'mce_external_plugins', array( $this, 'cleverreach_display_toolbar_button' ) );

		// enable shortcodes in text widgets
		add_filter( 'widget_text', 'do_shortcode' );
		add_filter( 'widget_text', 'shortcode_unautop' );
	}

	/**
	 * Adds base site URL to TinyMCE settings array.
	 *
	 * @param array $settings TinyMCE settings array.
	 *
	 * @return array Updated array.
	 */
	public function cleverreach_add_base_url( $settings ) {
		$settings[ 'base_url' ] = get_site_url();

		return $settings;
	}

	/**
	 * Hooks on MCE buttons event.
	 *
	 * @param array $buttons
	 *
	 * @return mixed
	 */
	public function cleverreach_register_toolbar_button( $buttons ) {
		array_push( $buttons, 'separator', 'cleverreach' );

		return $buttons;
	}

	/**
	 * Hooks on MCE external plugins event.
	 *
	 * @param array $plugin_array
	 *
	 * @return mixed
	 */
	public function cleverreach_display_toolbar_button( $plugin_array ) {
		$plugin_array['cleverreach'] = Helper::get_clever_reach_base_url( '/resources/js/cleverreach.classic-editor.js' );

		return $plugin_array;
	}

	/**
	 * Loads CleverReach icon for the sidebar menu on administrator panel.
	 */
	public function load_cleverreach_icon() {
		echo '
		    <style>
		    .dashicons-cr {
		        background-image: url("'. Helper::get_clever_reach_base_url( '/resources/images/cr-envelope.png' ) . '");
		        background-repeat: no-repeat;
		        background-position: center; 
		    }
		    
		    .current .dashicons-cr {
		        background-image: url("'. Helper::get_clever_reach_base_url( '/resources/images/cr-envelope-white.png' ) . '");
		    }
		    </style>
		';
	}

	/**
	 * Shows OAuth connection lost notification.
	 */
	public function show_oauth_connection_lost_message() {
		$notification_data = $this->get_config_service()->get_admin_notification_data();
		$title             = __( 'Your connection between WordPress and CleverReach was interrupted!', 'cleverreach-wp' );
		$link_label        = __( 'Re-authenticate now', 'cleverreach-wp' );
		echo "
			<div class='notice notice-info is-dismissible'>
				<p>
					<b>{$title}</b>&nbsp;
					{$notification_data['description']}
					<a href='{$notification_data['url']}'>{$link_label}</a>
				</p>
			</div>";
	}

	/**
	 * Register CleverReach widget
	 */
	public function register_widgets() {
		$widget = new Wp_Clever_Reach_Widget();
		register_widget($widget);
	}

	/**
	 * Renders CleverReach form on wordpress admin
	 *
	 * @param array $attributes block attributes
	 *
	 * @return string
	 *
	 * @throws QueryFilterInvalidParamException
	 * @throws RepositoryNotRegisteredException
	 * @throws \Exception
	 */
	public function render_subscription_form( $attributes ) {
		if ( ! empty( $attributes[ 'formID' ] ) ) {
			$class_attributes = $this->get_class_attributes( $attributes );

			$filter = new QueryFilter();
			$filter->where( 'formId', Operators::EQUALS, (string) $attributes[ 'formID' ] );

			/** @var Form $form */
			$form = RepositoryRegistry::getRepository( Form::getClassName() )->selectOne( $filter );

			$html = $form !== null ? Forms_Formatter::get_form_code( $form->getHtml() ) : '';

			return "<div class='{$class_attributes}'>{$html}</div>";
		}

		return '';
	}

	/**
	 * Removes invalid classes and returns them in format 'class1 class2 class3....'
	 *
	 * @param array $attributes
	 *
	 * @return string
	 */
	private function get_class_attributes( $attributes ) {
		if ( empty( $attributes[ 'className' ] ) ) {
			return '';
		}

		$class_attributes = '';
		$classes          = $attributes[ 'className' ];
		$classes          = preg_replace( '/\s+/', ' ', $classes );
		$array_of_classes = explode( ' ', $classes );
		foreach ( $array_of_classes as $class ) {
			$class = trim( $class );
			if ( $this->is_class_name_valid( $class ) ) {
				$class_attributes .= ' ' . $class;
			}
		}

		return $class_attributes;
	}

	/**
	 * Checks if css class name is valid
	 *
	 * @param string $class_name css selector
	 *
	 * @return bool
	 */
	private function is_class_name_valid($class_name) {
		if ($class_name === '') {
			return true;
		}

		$class_name_pattern = '/^[[a-zA-Z-_]+[a-zA-Z0-9-_]*$/';

		return preg_match($class_name_pattern, $class_name) === 1;
	}

	/**
	 * Returns singleton instance of the plugin.
	 *
	 * @param \wpdb  $wpdb                    WordPress database session.
	 * @param string $cleverreach_plugin_file Plugin file.
	 *
	 * @return Plugin
	 *
	 * @throws RepositoryClassException
	 */
	public static function instance( $wpdb, $cleverreach_plugin_file ) {
		if ( null === self::$instance ) {
			self::$instance = new self( $wpdb, $cleverreach_plugin_file );
		}

		self::$instance->initialize();
		return self::$instance;
	}

	/**
	 * Load translation files
	 */
	public function load_clever_reach_plugin_text_domain() {
		unload_textdomain( 'cleverreach-wp' );
		load_plugin_textdomain( 'cleverreach-wp', false, plugin_basename( dirname( $this->cleverreach_plugin_file ) ) . '/i18n/languages' );
	}

	/**
	 * Add all init plugin hooks
	 */
	private function load_plugin_init_hooks() {
		register_activation_hook( $this->cleverreach_plugin_file, array( $this, 'cleverreach_activate' ) );
		add_action( 'init', array( $this, 'load_clever_reach_plugin_text_domain' ) );
		add_action( 'admin_init', array( $this, 'cleverreach_initialize_new_site' ) );
		add_action( 'upgrader_process_complete', array( $this, 'update_option_for_plugin_update_check' ), 100, 2 );
		add_filter( 'query_vars', array( $this, 'cleverreach_plugin_add_trigger' ) );
		add_action( 'template_redirect', array( $this, 'cleverreach_plugin_trigger_check' ) );
	}

	/**
	 * Registers all Contact Form 7 related hooks.
	 */
	private function load_cf7_hooks() {
		if ( Helper::is_initial_sync_finished()
		     && Helper::is_plugin_enabled( 'contact-form-7/wp-contact-form-7.php' )
		) {
			$cr7_controller = new Clever_Reach_CF7_Controller( $this->cleverreach_plugin_file );

			add_action( 'admin_init', array( $cr7_controller, 'add_signup_tag' ), 1000 );
			add_action( 'wpcf7_init', array( $cr7_controller, 'render_signup_tag' ) );
			add_action( 'wpcf7_editor_panels', array( $cr7_controller, 'add_settings_tab' ) );
			add_action( 'wpcf7_after_save', array( $cr7_controller, 'save_tag_settings' ) );
			add_action( 'after_delete_post', array( $cr7_controller, 'delete_tag_settings' ) );
			add_action( 'wpcf7_submit', array( $cr7_controller, 'submit_form' ), 10, 2 );
		}
	}

	/**
	 * Add CleverReach admin menu and newsletter field hooks
	 */
	private function load_clever_reach_admin_menu_and_newsletter_field() {
		if ( is_admin() && ! is_network_admin() ) {
			add_action( 'admin_menu', array( $this, 'cleverreach_create_admin_menu' ) );

			if ( $this->get_config_service()->is_recipient_sync_enabled() ) {
				add_action( 'user_new_form', array( $this, 'cleverreach_register_form_field_newsletter' ) );
				add_action( 'show_user_profile', array( $this, 'cleverreach_register_form_field_newsletter' ) );
				add_action( 'edit_user_profile', array( $this, 'cleverreach_register_form_field_newsletter' ) );
			}
		}
	}

	/**
	 * Plugin install method
	 *
	 * @param bool $is_network_wide Is plugin activate network wide.
	 *
	 * @throws RepositoryClassException
	 * @throws RepositoryNotRegisteredException
	 * @throws TaskRunnerStatusStorageUnavailableException Task runner status storage unavailable exception.
	 */
	public function cleverreach_activate( $is_network_wide ) {
		if ( ! Helper::is_curl_enabled() ) {
			deactivate_plugins( plugin_basename( __FILE__ ) );
			wp_die(
				esc_html(
					__(
						'cURL is not installed or enabled in your PHP installation. This is required for background task to work. Please install it and then refresh this page.',
						'cleverreach-wp'
					)
				),
				'Plugin dependency check',
				array( 'back_link' => true )
			);
		}

		if ( Helper::is_plugin_initialized() ) {
			Task_Queue::wakeup();
		} elseif ( is_multisite() && $is_network_wide ) {
			$site_ids = get_sites();
			foreach ( $site_ids as $site_id ) {
				switch_to_blog( $site_id->blog_id );
				$this->init_database();
				$this->init_config();
				$this->add_scheduled_tasks();
				restore_current_blog();
			}
		} else {
			$this->init_database();
			$this->init_config();
			$this->add_scheduled_tasks();
		}
	}

	/**
	 * Plugin update method
	 */
	private function cleverreach_update_if_version_changed() {
		if ( is_multisite() ) {
			$site_ids = get_sites();
			foreach ( $site_ids as $site_id ) {
				switch_to_blog( $site_id->blog_id );
				$this->update_plugin_on_single_site();
				restore_current_blog();
			}
		} else {
			$this->update_plugin_on_single_site();
		}
	}

	/**
	 * Adds cleverreach query variable.
	 *
	 * @param array $vars Filter variables.
	 *
	 * @return array Filter variables.
	 */
	public function cleverreach_plugin_add_trigger( $vars ) {
		$vars[] = 'cleverreach_wp_controller';
		return $vars;
	}

	/**
	 * Trigger action on calling cleverreach controller.
	 */
	public function cleverreach_plugin_trigger_check() {
		$controller_name = get_query_var( 'cleverreach_wp_controller' );
		if ( ! empty( $controller_name ) ) {
			$controller = new Clever_Reach_Index();
			$controller->index();
		}
	}

	/**
	 * Updates option for plugin update check when hook for update is triggered
	 */
	public function update_option_for_plugin_update_check() {
		update_site_option(self::UPDATE_OPTION_CHECKED_KEY, self::UNCHECKED);
	}

	/**
	 * Initializes base CleverReach tables and values if plugin is accessed from a new site
	 *
	 * @throws TaskRunnerStatusStorageUnavailableException Task runner status storage unavailable exception.
	 */
	public function cleverreach_initialize_new_site() {
		if ( ! Helper::is_plugin_initialized() ) {
			$this->init_database();
			$this->init_config();
		}

		$is_checked = get_site_option( self::UPDATE_OPTION_CHECKED_KEY );
		if ( $is_checked !== self::CHECKED ) {
			$this->cleverreach_update_if_version_changed();
			update_site_option( self::UPDATE_OPTION_CHECKED_KEY, self::CHECKED );
		}
	}

	/**
	 * Creates CleverReach admin menu tab
	 */
	public function cleverreach_create_admin_menu() {
		$controller = new Clever_Reach_Frontend_Controller();
		add_menu_page(
			'CleverReach',
			'CleverReach®',
			'manage_options',
			'wp-cleverreach',
			array( $controller, 'render' ),
			'dashicons-cr',
			31
		);
		add_action( 'admin_head', array( $this, 'load_cleverreach_icon' ) );
	}

	/**
	 * Creates 'Subscribe to newsletter' field on user form
	 */
	public function cleverreach_register_form_field_newsletter() {
		include plugin_dir_path( $this->cleverreach_plugin_file ) . 'resources/views/register-form-newsletter.php';
	}

	/**
	 * Install database tables
	 */
	private function init_database() {
		$installer = new Database( $this->db );
		$installer->install();
	}

	/**
	 * Set initial config values
	 *
	 * @throws TaskRunnerStatusStorageUnavailableException Task runner status storage unavailable exception.
	 */
	private function init_config() {
		$config = $this->get_config_service();
		$config->setTaskRunnerStatus( '', null );
		$config->setProductSearchEndpointPassword( md5( time() ) );
		$config->set_language( Helper::get_site_language() );
		$config->set_database_version( Helper::get_plugin_version() );
		$config->set_plugin_opened_for_the_first_time( false );
		$config->set_entity_table_created();
	}

	/**
	 * @throws RepositoryClassException
	 * @throws RepositoryNotRegisteredException
	 */
	private function add_scheduled_tasks() {
		$schedule_repository = RepositoryRegistry::getScheduleRepository();
		$config = $this->get_config_service();

		$clear_scheduled_check_tasks_schedule = new HourlySchedule(
			new ClearCompletedScheduleCheckTasksTask(),
			$config->getQueueName()
		);

		$clear_scheduled_check_tasks_schedule->setNextSchedule();
		$schedule_repository->save( $clear_scheduled_check_tasks_schedule );

		$clear_completed_tasks_schedule = new DailySchedule(
			new Clear_Completed_Tasks_Task(),
			$config->getQueueName()
		);

		$clear_completed_tasks_schedule->setMinute( 1 );
		$clear_completed_tasks_schedule->setNextSchedule();
		$schedule_repository->save( $clear_completed_tasks_schedule );
	}

	/**
	 * Updates plugin on single WordPress site.
	 *
	 * @return bool
	 *
	 * @throws IntegrationCore\Infrastructure\TaskExecution\Exceptions\QueueStorageUnavailableException
	 * @throws QueryFilterInvalidParamException
	 * @throws RepositoryClassException
	 * @throws RepositoryNotRegisteredException
	 */
	private function update_plugin_on_single_site() {
		if ( Helper::is_plugin_enabled() && $this->is_plugin_version_changed()) {
			$previous_version = $this->config_service->get_database_version();
			$migration_directory = realpath( __DIR__ ) . '/database/migrations/';
			$version_file_reader = new Versioned_File_Reader( $migration_directory, $previous_version );
			while ( $version_file_reader->has_next() ) {
				/** @var Update_Schema $update_schema */
				$update_schema = $version_file_reader->read_next();
				try {
					$update_schema->update();
				} catch ( \Exception $ex ) {
					Logger::logError( $ex->getMessage(), 'Database Update' );

					return false;
				}
			}

			if ( $this->should_delete_receiver_event()
			     && version_compare( $this->get_config_service()->get_database_version(), '1.3.0', 'lt' )
			) {
				ServiceRegister::getService( Proxy::CLASS_NAME )->deleteReceiverEvent();
			}

			if ( version_compare( $this->get_config_service()->get_database_version(), '1.5.0', 'lt' ) ) {
				Task_Queue::enqueue( new FormCacheSyncTask() );
			}

			if ( version_compare( $this->get_config_service()->get_database_version(), '1.5.1', 'lt' ) ) {
				Task_Queue::enqueue( new RegisterEventHandlerTask() );
				$this->delete_form_schedulers();
				$this->delete_old_forms();
				Task_Queue::enqueue( new FormCacheSyncTask() );
			}

			if ( version_compare( $this->get_config_service()->get_database_version(), '1.5.2', 'lt' ) ) {
				Task_Queue::enqueue( new RegisterEventHandlerTask() );
			}

			$this->get_config_service()->set_database_version( Helper::get_plugin_version() );
		}

		return true;
	}

	/**
	 * Deletes form schedulers.
	 *
	 * @throws QueryFilterInvalidParamException
	 * @throws RepositoryClassException
	 * @throws RepositoryNotRegisteredException
	 */
	private function delete_form_schedulers() {
		$schedule_repository = RepositoryRegistry::getScheduleRepository();
		$filter              = new QueryFilter();
		$filter->where( 'taskType', Operators::EQUALS, FormCacheSyncTask::getClassName() );

		$schedule_repository->deleteBy( $filter );
	}

	/**
	 * Deletes old forms that do not belong to the integration list.
	 *
	 * @throws QueryFilterInvalidParamException
	 * @throws RepositoryNotRegisteredException
	 */
	private function delete_old_forms() {
		$form_repository = RepositoryRegistry::getRepository( Form::CLASS_NAME );
		$filter          = new QueryFilter();
		$filter->where( 'groupId', Operators::NOT_EQUALS, $this->get_config_service()->getIntegrationId() );

		$form_repository->deleteBy( $filter );
	}

	/**
	 * Check if update script should execute
	 *
	 * @return bool
	 */
	private function is_plugin_version_changed() {
		$previous_version = $this->get_config_service()->get_database_version();
		$current_version  = Helper::get_plugin_version();
		if ( ! $this->get_config_service()->is_entity_table_created() ) {
			$this->config_service->set_database_version( '1.3.0' );

			return true;
		}

		return version_compare( $previous_version, $current_version, 'lt' );
	}

	/**
	 * Returns whether receiver event should be deleted upon plugin update.
	 *
	 * @return bool
	 */
	private function should_delete_receiver_event() {
		/** @var TaskQueueStorage $task_queue_service */
		$task_queue_service     = ServiceRegister::getService( TaskQueueStorage::CLASS_NAME );
		$initial_sync_task_item = $task_queue_service->findLatestByType( InitialSyncTask::getClassName() );

		return $initial_sync_task_item
		       && $initial_sync_task_item->getStatus() === QueueItem::COMPLETED
		       && ( $this->get_config_service()->is_recipient_sync_enabled()
		            || $this->get_config_service()->is_integration_recipient_sync_enabled( 'CF7' )
		       );
	}

	/**
	 * Check if user is authenticated and if initial sync is finished
	 *
	 * @return bool
	 */
	private function is_user_connected() {
		/** @var TaskQueueStorage $task_queue */
		$task_queue = ServiceRegister::getService( TaskQueueStorage::CLASS_NAME );
		$initial_sync_task = $task_queue->findLatestByType( 'Initial_Sync_Task' );
		$access_token = $this->get_config_service()->getAccessToken();
		if (empty($access_token) || !$initial_sync_task) {
			return false;
		}

		return $initial_sync_task->getStatus() === QueueItem::COMPLETED;
	}

	/**
	 * Gets config service
	 *
	 * @return Config_Service
	 */
	private function get_config_service() {
		if ( null === $this->config_service ) {
			$this->config_service = ServiceRegister::getService( Configuration::CLASS_NAME );
		}

		return $this->config_service;
	}
}
