<?php
namespace WPDRMS\ASP\Core;

use WPDRMS\ASP\Asset\Script;
use WPDRMS\ASP\Cache\ORM\CacheOptions;
use WPDRMS\ASP\Cache\ResultsCacheService;
use WPDRMS\ASP\Database;
use WPDRMS\PluginCore\Traits\SingletonTrait;
use WPDRMS\ASP\Statistics\ORM\StatisticsOptions;
use WPDRMS\ASP\Statistics\StatisticsService;
use WPDRMS\Utils\FileManager;
use WPDRMS\ASP\Analytics\AnalyticsMigration;
use WPDRMS\ASP\Compatibility\CompatibilityMigration;
use WPDRMS\ASP\Index\IndexService;
use WPDRMS\ASP\Index\IndexTableMigration;
use WPDRMS\ASP\Priorities\PrioritiesMigration;
use WPDRMS\ASP\Synonyms\SynonymsService;
use WPDRMS\ASP\AI\AIMigration;
use WPDRMS\ASP\Utils\Plugin;

defined('ABSPATH') or die("You can't access this file directly.");

/**
 * Class aspInit
 *
 * AJAX SEARCH PRO initializator Class
 */
class Init {
	use SingletonTrait;

	private static $new_install = false;

	private function __construct() {
		wd_asp()->db = Database\Manager::getInstance();

		// Before the ASP_Helpers::previousVersion is ever executed, _asp_version option does not exist
		if ( get_option('_asp_version', false) === false ) {
			self::$new_install = true;
		}
	}

	/**
	 * Runs on activation OR if this->safety_check() detects a silent change
	 */
	public function activate() {

		// Includes the index table creation as well
		Database\Manager::getInstance()->create();
		IndexService::instance()->createTables();
		SynonymsService::instance()->createTable();

		StatisticsService::instance()->createTables();
		ResultsCacheService::instance()->create();

		$this->activation_only_backwards_compatibility_fixes();
		FileManager::instance()->createRequiredDirectories();

		// Was the plugin previously installed, and updated?
		if ( Plugin::previousVersion(ASP_CURR_VER_STRING, '<') ) {
			update_option('asp_recently_updated', 1);
		}

		set_transient('asp_just_activated', 1);

		// Add functions to asp_scheduled_activation_events to schedule background process events to the activation hook
		wp_schedule_single_event( time() + 15, 'asp_scheduled_activation_events' );
	}

	/**
	 *  Checks if the user correctly updated the plugin and fixes if not
	 */
	public function safety_check() {

		// Run the re-activation actions if this is actually a newer version
		if ( Plugin::previousVersion(ASP_CURR_VER_STRING, '<', true) ) {
			$this->activate();
			// Run a backwards compatibility check
			$this->backwards_compatibility_fixes();
			wd_asp()->css_manager->generator->generate();
			// Take a note on the recent update
			update_option('asp_recently_updated', 1);
		} else {
			// Was the plugin just activated, without version change?
			if ( get_transient('asp_just_activated') !== false ) {
				// Check the folders, they might have been deleted by accident
				FileManager::instance()->createRequiredDirectories();
				// Run a backwards compatibility check
				$this->backwards_compatibility_fixes();
				wd_asp()->css_manager->generator->generate();
				delete_transient('asp_just_activated');
			}
		}
	}

	/**
	 * Fix known backwards incompatibilities, only running at plugin activation
	 */
	public function activation_only_backwards_compatibility_fixes() {
		// Turn off the jquery script versions
		$comp = wd_asp()->o['asp_compatibility'];
		if ( !self::$new_install ) {
			if ( $comp['js_source'] == 'min' || $comp['js_source'] == 'min-scoped' ) {
				wd_asp()->o['asp_compatibility']['js_source'] = 'jqueryless-min';
			} elseif ( $comp['js_source'] == 'nomin' || $comp['js_source'] == 'nomin-scoped' ) {
				wd_asp()->o['asp_compatibility']['js_source'] = 'jqueryless-nomin';
			}
			asp_save_option('asp_compatibility');
		}
		// Old way of reatining the browser back button to new one
		if ( isset($comp['js_retain_popstate']) && $comp['js_retain_popstate'] == 1 ) {
			foreach ( wd_asp()->instances->get() as $si ) {
				$id                        = $si['id'];
				$sd                        = $si['data'];
				$sd['trigger_update_href'] = 1;
				wd_asp()->instances->update($id, $sd);
			}
			unset($comp['js_retain_popstate']);
			wd_asp()->o['asp_compatibility'] = $comp;
			asp_save_option('asp_compatibility');
		}
	}

	/**
	 * Fix known backwards incompatibilities
	 */
	public function backwards_compatibility_fixes() {
		// -------------------------- 4.28 ------------------------------
		if ( get_option('asp_stat', false) !== false ) {
			StatisticsOptions::instance()->status->value = true;
			StatisticsOptions::instance()->save();
			delete_option('asp_stat');
		}

		// Index table option fixes
		$ito = wd_asp()->o['asp_it_options'];
		if ( isset($ito['it_post_types']) && !is_array($ito['it_post_types']) ) {
			$ito['it_post_types'] = explode('|', $ito['it_post_types']);
			foreach ( $ito['it_post_types'] as $ck => $ct ) {
				if ( $ct == '' ) {
					unset($ito['it_post_types'][ $ck ]);
				}
			}
			wd_asp()->o['asp_it_options']['it_post_types'] = $ito['it_post_types'];
			asp_save_option('asp_it_options');
		}

		$ana = wd_asp()->o['asp_analytics'];
		// Analytics Options fixes 4.18
		if ( isset($ana['analytics']) && ( $ana['analytics'] == 1 || $ana['analytics'] == 'pageview' ) ) {
			wd_asp()->o['asp_analytics']['analytics'] = 'event';
			asp_save_option('asp_analytics');
		}

		AnalyticsMigration::run();
		IndexTableMigration::run();
		PrioritiesMigration::run();
		CompatibilityMigration::run();
		AIMigration::run();

		// 4.18.6 Pool sizes no longer slow down page load on index table options
		delete_option('_asp_it_pool_sizes');

		// #339 - _asp_script_data is no longer used (instance config is read from the
		// .asp_init_data div's data-settings attribute since the 4.26 WebPack front-end).
		delete_option('_asp_script_data');
		delete_site_option('_asp_script_data');

		// 4.22.6 - These were removed at the same time
		$comp = wd_asp()->o['asp_compatibility'];
		if ( isset($comp['forceinlinestyles']) ) {
			if ( $comp['forceinlinestyles'] ) {
				$comp['css_loading_method'] = 'inline';
			}
			unset($comp['forceinlinestyles']);
			unset($comp['css_async_load']);
			unset($comp['load_in_footer']);
			unset($comp['load_mcustom_js']);
			wd_asp()->o['asp_compatibility'] = $comp;
			asp_save_option('asp_compatibility');
		}

		// 4.28.3 New cache migration for image cropping
		$old_cache_options = get_option('asp_caching');
		if ( is_array($old_cache_options) && isset($old_cache_options['image_cropping']) ) {
			try {
				$cache_options                     = CacheOptions::instance();
				$cache_options->crop_images->value = boolval( $old_cache_options['image_cropping'] );
				$cache_options->save();
				delete_option('asp_caching');
			} catch ( \Exception $e ) {} // phpcs:ignore
		}

		/*
		 * Search instance option fixes
		 *
		 * - Get instances
		 * - Check options
		 * - Transition to new options based on old ones
		 * - Save instances
		 */
		foreach ( wd_asp()->instances->get() as $si ) {
			$id = $si['id'];
			$sd = $si['data'];

			// -------------------------- 4.10 ------------------------------
			// Primary and secondary fields
			$values     = array( '-1', '0', '1', '2', 'c__f' );
			$adv_fields = array(
				'primary_titlefield',
				'secondary_titlefield',
				'primary_descriptionfield',
				'secondary_descriptionfield',
			);
			foreach ( $adv_fields as $field ) {
				// Force string conversion for proper comparision
				if ( !in_array($sd[ $field ] . '', $values) ) {
					// Custom field value is selected
					$sd[ $field . '_cf' ] = $sd[ $field ];
					$sd[ $field ]         = 'c__f';
				}
			}
			// -------------------------- 4.10 ------------------------------

			// ------------------------- 4.10.4 -----------------------------
			// Autocomplete aggreagated to one option only.
			if ( isset($sd['autocomplete_mobile']) ) {
				if ( $sd['autocomplete_mobile'] == 1 && $sd['autocomplete'] == 1 ) {
					$sd['autocomplete'] = 1;
				} elseif ( $sd['autocomplete_mobile'] == 1 ) {
					$sd['autocomplete'] = 3;
				} elseif ( $sd['autocomplete'] == 1 ) {
					$sd['autocomplete'] = 2;
				} else {
					$sd['autocomplete'] = 0;
				}
				unset($sd['autocomplete_mobile']);
			}
			// ------------------------- 4.10.4 -----------------------------

			// ------------------------- 4.11 -------------------------------
			// Autocomplete aggreagated to one option only.
			if ( !isset($sd['frontend_fields']['unselected']) ) {
				$sd['frontend_fields']['unselected'] = array();
			}
			if ( isset($sd['showexactmatches'], $sd['exactmatchestext']) ) {
				$sd['frontend_fields']['labels']['exact'] = $sd['exactmatchestext'];
				if ( $sd['showexactmatches'] == 0 ) {
					$sd['frontend_fields']['unselected'][] = 'exact';
					$sd['frontend_fields']['selected']     =
						array_diff( $sd['frontend_fields']['selected'], array( 'exact' ) );
				}
			}
			if ( isset($sd['showsearchintitle'], $sd['searchintitletext']) ) {
				$sd['frontend_fields']['labels']['title'] = $sd['searchintitletext'];
				if ( $sd['showsearchintitle'] == 0 ) {
					$sd['frontend_fields']['unselected'][] = 'title';
					$sd['frontend_fields']['selected']     =
						array_diff( $sd['frontend_fields']['selected'], array( 'title' ) );
				}
			}
			if ( isset($sd['showsearchincontent'], $sd['searchincontenttext']) ) {
				$sd['frontend_fields']['labels']['content'] = $sd['searchincontenttext'];
				if ( $sd['showsearchincontent'] == 0 ) {
					$sd['frontend_fields']['unselected'][] = 'content';
					$sd['frontend_fields']['selected']     =
						array_diff( $sd['frontend_fields']['selected'], array( 'content' ) );
				}
			}
			if ( isset($sd['showsearchinexcerpt'], $sd['searchinexcerpttext']) ) {
				$sd['frontend_fields']['labels']['excerpt'] = $sd['searchinexcerpttext'];
				if ( $sd['showsearchinexcerpt'] == 0 ) {
					$sd['frontend_fields']['unselected'][] = 'excerpt';
					$sd['frontend_fields']['selected']     =
						array_diff( $sd['frontend_fields']['selected'], array( 'excerpt' ) );
				}
			}
			// ------------------------- 4.11 -------------------------------

			// ------------------------- 4.11.6 -----------------------------
			// User meta fields to array
			if ( isset($sd['user_search_meta_fields']) && !is_array($sd['user_search_meta_fields']) ) {
				$sd['user_search_meta_fields'] = explode(',', $sd['user_search_meta_fields']);
				foreach ( $sd['user_search_meta_fields'] as $umk =>$umv ) {
					$sd['user_search_meta_fields'][ $umk ] = trim($umv);
					if ( $sd['user_search_meta_fields'][ $umk ] == '' ) {
						unset($sd['user_search_meta_fields'][ $umk ]);
					}
				}
			}
			// ------------------------- 4.11.6 -----------------------------

			// ------------------------- 4.11.10 ----------------------------
			// Before, this was a string
			if ( isset($sd['customtypes']) && !is_array($sd['customtypes']) ) {
				$sd['customtypes'] = explode('|', $sd['customtypes']);
				foreach ( $sd['customtypes'] as $ck => $ct ) {
					if ( $ct == '' ) {
						unset($sd['customtypes'][ $ck ]);
					}
				}
			}
			// No longer exists
			if ( isset($sd['selected-customtypes']) ) {
				unset($sd['selected-customtypes']);
			}
			// No longer exists
			if ( isset($sd['searchinpages']) ) {
				if ( $sd['searchinpages'] == 1 && !in_array('page', $sd['customtypes']) ) {
					array_unshift($sd['customtypes'], 'page');
				}
				unset($sd['searchinpages']);
			}
			// No longer exists
			if ( isset($sd['searchinposts']) ) {
				if ( $sd['searchinposts'] == 1 && !in_array('post', $sd['customtypes']) ) {
					array_unshift($sd['customtypes'], 'post');
				}
				unset($sd['searchinposts']);
			}
			// ------------------------- 4.11.10 ----------------------------

			// ------------------------- 4.12 -------------------------------
			if ( is_numeric($sd['i_item_width']) ) {
				$sd['i_item_width'] = $sd['i_item_width'] . 'px';
			}
			// ------------------------- 4.12 -------------------------------

			// ------------------------- 4.13.1 -----------------------------
			$font_sources = array(
				'inputfont',
				'descfont',
				'titlefont',
				'authorfont',
				'datefont',
				'showmorefont',
				'groupfont',
				'exsearchincategoriestextfont',
				'groupbytextfont',
				'settingsdropfont',
				'prestitlefont',
				'presdescfont',
				'pressubtitlefont',
				'search_text_font',
			);
			if ( isset($sd['inputfont']) && strpos($sd['inputfont'], '--g--') !== false ) {
				/**
				 * Remove the unneccessary --g-- tags and quotes
				 */
				foreach ( $font_sources as $fk ) {
					if ( isset($sd[ $fk ]) ) {
						$sd[ $fk ] = str_replace(array( '--g--', '"', "'" ), '', $sd[ $fk ]);
					}
				}
			}
			if ( isset($sd['results_order']) && strpos($sd['results_order'], 'peepso') === false ) {
				$sd['results_order'] .= '|peepso_groups|peepso_activities';
			}
			if ( isset($sd['groupby_content_type']) && !isset($sd['groupby_content_type']['peepso_groups']) ) {
				$sd['groupby_content_type']['peepso_groups']     = 'Peepso Groups';
				$sd['groupby_content_type']['peepso_activities'] = 'Peepso Activities';
			}
			// ------------------------- 4.13.1 -----------------------------

			// ------------------------- 4.14.4 -----------------------------
			if ( isset($sd['frontend_fields']['labels']['comments']) ) {
				unset($sd['frontend_fields']['labels']['comments']);
			}
			$sd['frontend_fields']['selected']   = array_diff( $sd['frontend_fields']['selected'], array( 'comments' ) );
			$sd['frontend_fields']['unselected'] = array_diff( $sd['frontend_fields']['unselected'], array( 'comments' ) );
			$sd['frontend_fields']['checked']    = array_diff( $sd['frontend_fields']['checked'], array( 'comments' ) );
			// ------------------------- 4.14.4 -----------------------------

			// ------------------------- 4.14.5 -----------------------------
			// For non-existence checks use the raw_data array
			if ( !isset($si['raw_data']['i_item_width_tablet']) ) {
				$sd['i_item_width_tablet'] = $sd['i_item_width'];
				$sd['i_item_width_phone']  = $sd['i_item_width'];
			}
			// For non-existence checks use the raw_data array
			if ( !isset($si['raw_data']['i_item_height_tablet']) ) {
				$sd['i_item_height_tablet'] = $sd['i_item_height'];
				$sd['i_item_height_phone']  = $sd['i_item_height'];
			}
			// For non-existence checks use the raw_data array
			if ( !isset($si['raw_data']['box_width_tablet']) ) {
				$sd['box_width_tablet'] = $sd['box_width'];
				$sd['box_width_phone']  = $sd['box_width'];
			}
			// ------------------------- 4.14.5 -----------------------------

			// ------------------------- 4.15 -------------------------------
			if ( is_numeric($sd['i_item_height']) ) {
				$sd['i_item_height'] = $sd['i_item_height'] . 'px';
			}
			if ( is_numeric($sd['i_item_height_tablet']) ) {
				$sd['i_item_height_tablet'] = $sd['i_item_height_tablet'] . 'px';
			}
			if ( is_numeric($sd['i_item_height_phone']) ) {
				$sd['i_item_height_phone'] = $sd['i_item_height_phone'] . 'px';
			}
			// ------------------------- 4.15 -------------------------------

			// ------------------------- 4.17 -------------------------------
			if ( !empty($sd['image_default'])
				&& !isset($si['raw_data']['tax_image_default'], $si['raw_data']['tax_image_default']) ) {
				$sd['tax_image_default']  = $sd['image_default'];
				$sd['user_image_default'] = $sd['image_default'];
			}
			// ------------------------- 4.17 -------------------------------

			// ------------------------- 4.18.2 -----------------------------
			if ( isset($sd['jquery_chosen_nores']) ) {
				$sd['jquery_select2_nores'] = $sd['jquery_chosen_nores'];
			}
			// ------------------------- 4.18.2 -----------------------------

			// ------------------------- 4.18.8 -----------------------------
			if ( !isset($si['raw_data']['tax_res_showdescription']) ) {
				$sd['tax_res_showdescription']    = $sd['showdescription'];
				$sd['user_res_showdescription']   = $sd['showdescription'];
				$sd['tax_res_descriptionlength']  = $sd['descriptionlength'];
				$sd['user_res_descriptionlength'] = $sd['descriptionlength'];
			}
			// ------------------------- 4.18.8 -----------------------------

			// ------------------------- 4.20.5 -----------------------------
			// The mobile settings state can be forced without forcing the hover
			if ( Plugin::previousVersion('4.20.4') ) {
				if ( $sd['mob_force_sett_hover'] == 0 ) {
					$sd['mob_force_sett_state'] = 'none';
				}
			}
			// ------------------------- 4.20.5 -----------------------------

			// ------------------------- 4.26.16 ----------------------------
			if ( isset($sd['orderby']) ) {
				$sd['orderby_secondary'] = $sd['orderby'];
				unset($sd['orderby']);
			}
			if ( isset($sd['horizontal_res_height']) ) {
				$sd['h_item_height']        = $sd['horizontal_res_height'];
				$sd['h_item_height_tablet'] = $sd['horizontal_res_height'];
				$sd['h_item_height_phone']  = $sd['horizontal_res_height'];
				unset($sd['horizontal_res_height']);
			}
			if ( isset($sd['hreswidth']) ) {
				$sd['h_item_width']        = $sd['hreswidth'];
				$sd['h_item_width_tablet'] = $sd['hreswidth'];
				$sd['h_item_width_phone']  = $sd['hreswidth'];
				unset($sd['hreswidth']);
			}
			if ( isset($sd['hor_img_height']) ) {
				$sd['h_image_height']        = $sd['hor_img_height'];
				$sd['h_image_height_tablet'] = $sd['hor_img_height'];
				$sd['h_image_height_phone']  = $sd['hor_img_height'];
				unset($sd['hor_img_height']);
			}

			// ---------------------------- 4.27 ----------------------------
			if ( Plugin::previousVersion('4.26.16') ) {
				foreach ( array(
					'advtitlefield',
					'advdescriptionfield',
					'user_search_advanced_title_field',
					'user_search_advanced_description_field',
				) as $fk
				) {
					$sd[ $fk ] = str_replace(
						array( '{titlefield}', '{descriptionfield}' ),
						array( "{result_field field_name='title' hash='x'}", "{result_field field_name='content' hash='y'}" ),
						$sd[ $fk ]
					);
				}
			}

			// ----------------- Unset some unused search data --------------
			// Leave this here, so it is executed as last
			$values = array(
				// from 4.10
				'magnifierimage_selects',
				'settingsimage_selects',
				'loadingimage_selects',
				'i_res_magnifierimage_selects',
				'i_pagination_arrow_selects',
				'keyword_logic_def',
				'user_search_title_field_def',
				'frontend_search_settings_position_def',
				'term_logic_def',
				'cf_logic_def',
				'resultstype_def',
				'resultsposition_def',
				'box_compact_float_def',
				'box_compact_position_def',
				'keyword_suggestion_source_def',
				'bpgroupstitle_def',
				'bpgroupstitle',
				'settingsimagepos_def',
				'blogtitleorderby_def',
				'i_ifnoimage_def',
				'i_pagination_position_def',
				'weight_def',
				'user_search_description_field_def',
				'triggeronclick',
				'triggeronreturn',
				'redirectonclick',
				'redirect_click_to',
				'redirect_on_enter',
				'redirect_enter_to',
				'mob_trigger_on_click',
				// from 4.11
				'showexactmatches',
				'exactmatchestext',
				'showsearchintitle',
				'searchintitletext',
				'showsearchincontent',
				'searchincontenttext',
				'showsearchincomments',
				'searchincommentstext',
				'showsearchinexcerpt',
				'searchinexcerpttext',
				// from 4.18.2
				'jquery_chosen_nores',
			);
			foreach ( $values as $v ) {
				if ( isset($sd[ $v ]) ) {
					unset($sd[ $v ]);
				}
			}

			// At the end, update
			wd_asp()->instances->update($id, $sd);
		}
	}

	public function pluginReset( $triggerActivate = true ) {
		$options = array(
			'asp_version',
			'_asp_version',
			'asp_glob_d',
			'asp_it_def',
			'asp_it',
			'asp_it_options',
			'asp_analytics_def',
			'asp_analytics',
			'asp_caching_def',
			'asp_caching',
			'asp_compatibility_def',
			'asp_compatibility',
			'asp_defaults',
			'asp_st_override',
			'asp_woo_override',
			'asp_stat',
			'asp_updates',
			'asp_updates_lc',
			'asp_media_query',
			'asp_recently_updated',
			'asp_fonts',
			'_asp_tables',
			'_asp_priority_groups',
			'_asp_it_pool_sizes',
			'asp_license_data',
		);
		foreach ( $options as $o ) {
			delete_option($o);
			delete_site_option($o);
		}

		wp_clear_scheduled_hook('asp_cron_it_extend');

		Script\Manager::getInstance()->cleanup();

		if ( $triggerActivate ) {
			$this->activate();
		}
	}

	public function pluginWipe() {

		// Options
		$this->pluginReset( false );

		// Meta
		if ( is_multisite() ) {
			global $switched;
			$sites = get_sites(array( 'fields' => 'ids' ));
			foreach ( $sites as $site ) {
				switch_to_blog($site);
				delete_metadata('post', 1, '_asp_additional_tags', '', true);
				delete_metadata('post', 1, '_asp_metadata', '', true);
				restore_current_blog();
			}
		} else {
			delete_metadata('post', 1, '_asp_additional_tags', '', true);
			delete_metadata('post', 1, '_asp_metadata', '', true);
		}

		// Database
		wd_asp()->db->delete();
		StatisticsService::instance()->dropTables();
		ResultsCacheService::instance()->destroy();

		FileManager::instance()->removeRequiredDirectories();

		// Deactivate
		deactivate_plugins(ASP_FILE);
	}
}
