<?php
//namespace administrator\components\com_jrealtimeanalytics;
/**  
 * Application install script
 * @package JREALTIMEANALYTICS::administrator::components::com_jrealtimeanalytics 
 * @author Joomla! Extensions Store
 * @copyright (C) 2013 - Joomla! Extensions Store
 * @license GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html   
 */
defined ( '_JEXEC' ) or die ( 'Restricted access' ); 
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
use Joomla\CMS\Uri\Uri;
use Joomla\CMS\Installer\Installer;
use Joomla\CMS\Installer\InstallerScriptInterface;
use Joomla\CMS\Installer\InstallerAdapter;

/** 
 * Application install script class
 * @package JREALTIMEANALYTICS::administrator::components::com_jrealtimeanalytics  
 */
class JRealtimeAnalyticsBaseInstallerScript {
	/*
	* Find mimimum required joomla version for this extension. It will be read from the version attribute (install tag) in the manifest file
	*/
	private $minimum_joomla_release = '4.0';
	
	/*
	 * $parent is the class calling this method.
	 * $type is the type of change (install, update or discover_install, uninstall).
	 * preflight runs before anything else and while the extracted files are in the uploaded temp folder.
	 * If preflight returns false, Joomla will abort the update and undo everything already done.
	 */
	function preflight(string $type, InstallerAdapter $parent): bool {
		// Check for Joomla compatibility
		if(version_compare(JVERSION, '4', '<')) {
			Factory::getApplication()->enqueueMessage (Text::sprintf('COM_JREALTIME_INSTALLING_VERSION_NOTCOMPATIBLE', JVERSION), 'error');
			
			if(version_compare(JVERSION, '3.10', '<')) {
				Factory::getApplication()->enqueueMessage (Text::sprintf('Error, installation aborted. Pay attention! You are attempting to install a component package for Joomla 4 that does not match your actual Joomla version. Download and install the correct package for your Joomla %s version.', JVERSION ), 'error' );
			}
			return false;
		}

		// Set MySql 5.7.8+ strict mode off
		$installer = $parent->getParent ();
		Factory::getContainer ()->get ( 'DatabaseDriver' )->setQuery ( "SET @@SESSION.sql_mode = ''" )->execute ();
		if ($installer && method_exists ( $installer, 'getPath' )) {
			$source = $installer->getPath ( 'source' );

			if ($source && is_dir ( $source )) {
				$file = $source . '/admin/Framework/File/Mysql.php';
		 
			 if (is_file($file)) {
					require_once $file;
					JExtstore\Component\JRealtimeAnalytics\Administrator\Framework\Mysql::set($parent);
				 }
			 }
		}
		
		return true;
	}
	
	/*
	 * $parent is the class calling this method.
	 * install runs after the database scripts are executed.
	 * If the extension is new, the install method is run.
	 * If install returns false, Joomla will abort the install and undo everything already done.
	 */
	function install(InstallerAdapter $parent, $isUpdate = false): bool {
		// Reset any previous messages queue, keep only strict installation messages since now on
		$app = Factory::getApplication();
		$currentMessageQueue = $app->getMessageQueue(true);
		if(!empty($currentMessageQueue)) {
			foreach ($currentMessageQueue as $message) {
				if($message['type'] == 'info') {
					$app->enqueueMessage($message['message'], 'info');
				}
			}
		}
		
		// Evaluate nonce csp feature 
		$appNonce = $app->get('csp_nonce', null);
		$nonce = $appNonce ? ' nonce="' . $appNonce . '"' : '';
		echo ('<link rel="stylesheet" type="text/css"' . $nonce . ' href="' . Uri::root ( true ) . '/administrator/components/com_jrealtimeanalytics/css/bootstrap-install.css' . '" />');
		echo ('<script type="text/javascript"' . $nonce . ' src="' . Uri::root ( true ) . '/media/vendor/jquery/js/jquery.min.js' .'"></script>' );
		echo ('<script type="text/javascript"' . $nonce . ' src="' . Uri::root ( true ) . '/administrator/components/com_jrealtimeanalytics/js/installer.js' .'" defer></script>' );
		
		$lang = Factory::getApplication()->getLanguage();
		$lang->load('com_jrealtimeanalytics.sys', JPATH_ADMINISTRATOR . '/components/com_jrealtimeanalytics', null, false, true) || $lang->load('com_jrealtimeanalytics.sys', JPATH_ADMINISTRATOR, null, false, true);

		$parentParent = $parent->getParent();
		
		$database = Factory::getContainer()->get('DatabaseDriver');
		
		// Component installer
		$componentInstaller = Installer::getInstance ();
		if(!$componentInstaller->getPath ( 'source' )) {
			$componentInstaller = $parent->getParent();
		}
		$pathToPlugin = $componentInstaller->getPath ( 'source' ) . '/plugin';
		$pathToModule = $componentInstaller->getPath ( 'source' ) . '/module';
		
		echo ('<div class="installcontainer">');
		// New plugin installer
		$pluginInstaller = new Installer ();
		$pluginInstaller->setDatabase($database);
		if (! $pluginInstaller->install ( $pathToPlugin )) {
			echo '<p>' . Text::_( 'COM_JREALTIME_ERROR_INSTALLING_PLUGINS' ) . '</p>';
			// Install failed, rollback changes
			$parentParent->abort(Text::_('COM_JREALTIME_ERROR_INSTALLING_PLUGINS'));
			return false;
		} else {
			$query = "UPDATE #__extensions" . "\n SET enabled = 1" . 
					 "\n WHERE type = 'plugin' AND element = " . $database->Quote ( 'jrealtimeanalytics' ) . 
					 "\n AND folder = " . $database->Quote ( 'system' );
			$database->setQuery ( $query );
			if (! $database->execute ()) {
				echo '<p>' . Text::_( 'COM_JREALTIME_ERROR_PUBLISHING_PLUGIN' ) . '</p>';
			}?>
			<div class="progress">
				<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
					<span class="step_details"><?php echo Text::_('COM_JREALTIME_OK_INSTALLING_PLUGINS');?></span>
				</div>
			</div>
			<?php 
		}
		
		// New module installer
		$moduleInstaller = new Installer ();
		$moduleInstaller->setDatabase($database);
		if (! $moduleInstaller->install ( $pathToModule )) {
			echo '<p>' . Text::_ ( 'COM_JREALTIME_ERROR_INSTALLING_MODULE' ) . '</p>';
			// Install failed, rollback changes
			$parentParent->abort(Text::_('COM_JREALTIME_ERROR_INSTALLING_MODULE'));
			return false;
		} else {
			?>
			<div class="progress">
				<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
					<span class="step_details"><?php echo Text::_('COM_JREALTIME_OK_INSTALLING_MODULE');?></span>
				</div>
			</div>
			<?php 
		}
		?>
		<div class="progress">
			<div class="progress-bar" role="progressbar" aria-valuenow="60" aria-valuemin="0" aria-valuemax="100">
				<span class="step_details"><?php echo Text::_('COM_JREALTIME_OK_INSTALLING_COMPONENT');?></span>
		  	</div>
		</div>
		
		<div class="alert alert-success"><?php echo Text::_('COM_JREALTIME_ALL_COMPLETED');?></div>
		<?php 
		echo ('</div>');
		
		// Update tables to Utf8mb4 utf8_unicode_ci collation if the Joomla database has been upgraded, use feature detection on the #__session core table
		try {
			$db = Factory::getContainer()->get('DatabaseDriver');
			
			// Get Third Party table current collation
			$thirdpartyCollationQuery = "SHOW FULL COLUMNS FROM " . $db->quoteName(('#__realtimeanalytics_serverstats'));
			$thirdpartyResultTableInfo = $db->setQuery($thirdpartyCollationQuery)->loadObjectList();
			$thirdpartyResultTableFieldInfo = $thirdpartyResultTableInfo[0]; // session_id_person field
			
			// Get Joomla core table current collation
			$testCollationQuery = "SHOW FULL COLUMNS FROM " . $db->quoteName(('#__session'));
			$resultTableInfo = $db->setQuery($testCollationQuery)->loadObject();
			if(isset($resultTableInfo->Collation) && isset($thirdpartyResultTableFieldInfo->Collation) && $resultTableInfo->Collation != $thirdpartyResultTableFieldInfo->Collation) {
				// #__realtimeanalytics_serverstats table Utf8mb4 utf8_unicode_ci
				$charset = strpos($resultTableInfo->Collation, 'utf8mb4') !== false ? 'utf8mb4' : 'utf8';
				$alterSessiontablesCollation = "ALTER TABLE " . $db->quoteName('#__realtimeanalytics_serverstats') . " CHANGE " . $db->quoteName('session_id_person') . " " . $db->quoteName('session_id_person') ." VARCHAR( 191 ) CHARACTER SET " . $charset . " COLLATE " . $resultTableInfo->Collation . " NOT NULL ;";
				$db->setQuery($alterSessiontablesCollation)->execute();
					
				// #__realtimeanalytics_realstats table Utf8mb4 utf8_unicode_ci
				$alterSessiontablesCollation = "ALTER TABLE " . $db->quoteName('#__realtimeanalytics_realstats') . " CHANGE " . $db->quoteName('session_id_person') . " " . $db->quoteName('session_id_person') ." VARCHAR( 191 ) CHARACTER SET " . $charset . " COLLATE " . $resultTableInfo->Collation . " NOT NULL ;";
				$db->setQuery($alterSessiontablesCollation)->execute();
					
				// #__realtimeanalytics_eventstats_track table Utf8mb4 utf8_unicode_ci
				$alterSessiontablesCollation = "ALTER TABLE " . $db->quoteName('#__realtimeanalytics_eventstats_track') . " CHANGE " . $db->quoteName('session_id') . " " . $db->quoteName('session_id') ." VARCHAR( 191 ) CHARACTER SET " . $charset . " COLLATE " . $resultTableInfo->Collation . " NOT NULL ;";
				$db->setQuery($alterSessiontablesCollation)->execute();
			} else {
				// Align tables to the newest varbinary
				if(isset($resultTableInfo->Type) && isset($thirdpartyResultTableFieldInfo->Type) && stripos($resultTableInfo->Type, 'varbinary') !== false && $resultTableInfo->Type != $thirdpartyResultTableFieldInfo->Type) {
					// #__realtimeanalytics_serverstats table varbinary
					$alterSessiontablesCollation = "ALTER TABLE " . $db->quoteName('#__realtimeanalytics_serverstats') . " CHANGE " . $db->quoteName('session_id_person') . " " . $db->quoteName('session_id_person') ." VARBINARY( 192 ) NOT NULL ;";
					$db->setQuery($alterSessiontablesCollation)->execute();
					
					// #__realtimeanalytics_realstats table varbinary
					$alterSessiontablesCollation = "ALTER TABLE " . $db->quoteName('#__realtimeanalytics_realstats') . " CHANGE " . $db->quoteName('session_id_person') . " " . $db->quoteName('session_id_person') ." VARBINARY( 192 ) NOT NULL ;";
					$db->setQuery($alterSessiontablesCollation)->execute();
					
					// #__realtimeanalytics_eventstats_track table varbinary
					$alterSessiontablesCollation = "ALTER TABLE " . $db->quoteName('#__realtimeanalytics_eventstats_track') . " CHANGE " . $db->quoteName('session_id') . " " . $db->quoteName('session_id') ." VARBINARY( 192 ) NOT NULL ;";
					$db->setQuery($alterSessiontablesCollation)->execute();
				}
			}
		} catch (\Exception $e) {
			// Do nothing for user
		}
		
		// Processing complete
		return true;
	}
	
	/*
	 * $parent is the class calling this method.
	 * update runs after the database scripts are executed.
	 * If the extension exists, then the update method is run.
	 * If this returns false, Joomla will abort the update and undo everything already done.
	 */
	function update(InstallerAdapter $parent): bool {
		// Execute always SQL install file to get added updates in that file, disregard DBMS messages and Joomla queue for user
		$parentParent = $parent->getParent();
		$parentManifest = $parentParent->getManifest();
		try {
			// Install/update always without error handling case legacy J Error
			if (isset($parentManifest->install->sql)) {
				$parentParent->parseSQLFiles($parentManifest->install->sql);
			}
		} catch (\Exception $e) {
			// Do nothing for user for Joomla 3.x case, case Exception handling
		}

		// Indifferentemente gestiamo l'installazione del plugin
		$this->install($parent, true);
		
		return true;
	}
	
	/*
	 * $parent is the class calling this method.
	 * $type is the type of change (install, update or discover_install, uninstall).
	 * postflight is run after the extension is registered in the database.
	 */
	function postflight(string $type, InstallerAdapter $parent): bool {
		// Preferences general
		$params ['daemonrefresh'] = '6';
		$params ['realtimerefresh'] = '6';
		$params ['maxlifetime_session'] = '10';
		$params ['daemontimeout'] = '0';
		$params ['guestprefix'] = 'Visitor';
		$params ['cpanelstats_period_interval'] = 'day';
		$params ['geolocation_mode'] = 'ip';
		$params ['devicedectection_mode'] = 'useragent';
		$params ['heatmap_status'] = '1';
		$params ['heatmap_max_valid_width'] = '350';
		$params ['heatmap_max_valid_height'] = '50';
		$params ['heatmap_css_selectors_exclusion'] = '';
		$params ['heatmap_timeout'] = '200';
		$params ['stats_calendar_type'] = 'date';
		$params ['track_query_string'] = '1';
		$params ['registration_email'] = '';

		// Preferences stats report 
		$params ['default_period_interval'] = 'week';
		$params ['details_stats'] = '1';
		$params ['geolocation_stats'] = '1';
		$params ['os_stats'] = '1';
		$params ['browser_stats'] = '1';
		$params ['device_stats'] = '1';
		$params ['landing_stats'] = '1';
		$params ['leaveoff_stats'] = '1';
		$params ['visitsbypage_stats'] = '1';
		$params ['visitsbyuser_stats'] = '1';
		$params ['visitsbyip_stats'] = '1';
		$params ['referral_stats'] = '1';
		$params ['searchkeys_stats'] = '1';
		$params ['xtd_singleuser_stats'] = '0';
		$params ['show_usergroup'] = '0';
		$params ['show_referral'] = '0';
		$params ['show_email_address'] = '0';
		$params ['auto_execute_sitespeed'] = '1';
		
		// Exclusions
		$params ['ipaddress'] = '';
		$params ['iprange_start'] = '';
		$params ['iprange_end'] = '';
		$params ['ip_multiple'] = '';
		$params ['iprange_multiple'] = '';
		$params ['ipv6address'] = '';
		$params ['ipv6range_start'] = '';
		$params ['ipv6range_end'] = '';
		$params ['ipv6_multiple'] = '';
		$params ['ipv6range_multiple'] = '';
		$params ['daemon_exclusions'] = array('0');
		$params ['groups_exclusions'] = array('0');
		$params ['countrycode_exclusions'] = array('0');
		$params ['useragents_exclusions'] = 'googlebot,bingbot,acontbot,baiduspider,slurp,google,duckduckbot,yandexbot,Sogou,facebookexternalhit,ia_archiver';
		$params ['useragent_empty_exclude'] = '0';
		
		// Stats module
		$params ['daily_stats'] = '1';
		$params ['realtime_stats'] = '0';
		$params ['visualmap_stats'] = '0';
		$params ['visitors_counter'] = '0';
		$params ['visitors_counter_position'] = '0';
		$params ['module_default_period_interval'] = 'day';
		$params ['visitors_counter_bypage'] = '0';
		$params ['module_start_date'] = '';
		$params ['module_end_date'] = '';

		// Advanced
		$params ['gdpr_integration'] = '0';
		$params ['gcenabled'] = '1'; 
 		$params ['probability'] = '20';
 		$params ['gc_serverstats_enabled'] = '0';
 		$params ['gc_serverstats_period'] = '24';
 		$params ['caching'] = '0';
 		$params ['cache_lifetime'] = '60';
 		$params ['offset_type'] = 'joomla';
 		$params ['anonymize_ipaddress'] = '0';
 		$params ['gdpr_ip_pseudonymisation'] = '0';
 		$params ['direct_track_extensions'] = array('0');
 		$params ['shared_session_support'] = '1';
 		$params ['geolocation_php_func'] = 'file';
 		$params ['use_gd_ttf_font'] = '1';
 		$params ['cloudflare_ip_masking'] = '0';
 		$params ['server_ip_override'] = '';
 		$params ['backend_host_info'] = '0';
 		$params ['backend_geolocation_service'] = 'geoiplookup';
 		$params ['stats_geolocation_service'] = 'geoplugin';
 		
 		// Report
 		$params ['report_mailfrom'] = '';
 		$params ['report_fromname'] = '';
 		$params ['report_byemail'] = '0';
 		$params ['report_addresses'] = '';
 		$params ['report_format'] = 'emailxls';
 		$params ['report_frequency'] = '7';
 		$params ['overview_report_type'] = '0';
 		$params ['report_script_jquery_onload_event'] = '0';

 		// JS management
		$params ['includejquery'] = '1';
		$params ['noconflict'] = '1';
		$params ['scripts_loading'] = 'defer';
		$params ['start_application_event'] = 'afterdispatch';
		$params ['enable_debug'] = '0';

		// Analytics settings
		$params ['analytics_api'] = 'data';
		$params ['analytics_service'] = 'google';
		$params ['ga_property_id'] = '';
		$params ['ga_domain'] = '';
		$params ['wm_domain'] = '';
		$params ['ga_api_key'] = '';
		$params ['ga_client_id'] = '';
		$params ['ga_client_secret'] = '';
		$params ['matomo_analytics_url'] = '';
		$params ['matomo_analytics_idsite'] = '';
		$params ['matomo_token_auth'] = '';
		$params ['matomo_api_request_mode'] = 'post';
		$params ['ai_analysis_enabled'] = '0';
		$params ['ai_provider'] = 'gemini';
		$params ['ai_gemini_api_key'] = '';
		$params ['ai_gemini_model'] = 'gemini-2.5-flash';
		$params ['ai_openai_api_key'] = '';
		$params ['ai_openai_model'] = 'gpt-4o-mini';
		$params ['ai_max_tokens'] = '2000';
		$params ['ai_temperature'] = '0.4';
		$params ['ai_email_report_enabled'] = '0';
		$params ['ai_analysis_prompt'] = "You are a senior web analytics consultant. Analyze this {channel_title} data for period \"{period_label}\" on website \"{site_name}\".\n\nOutput in concise natural language with these sections:\n1) Executive summary\n2) Key insights (max 5 bullets)\n3) Critical issues/anomalies\n4) Actionable recommendations (max 5 actions)\n5) Suggested KPI focus for next period\n\nDataset:\n{dataset}";

		// PageSpeed settings
		$params ['pagespeed_insights_analysis'] = '1';
		$params ['pagespeed_api_key'] = '';
		$params ['pagespeed_http_transport'] = 'curl';
		$params ['pagespeed_analysis_strategy'] = 'desktop';

		// Insert all params settings default first time, merge and insert only new one if any on update, keeping current settings
		if ($type == 'install') {  
			$this->setParams ( $params );  
		} elseif ($type == 'update') {
			// Load and merge existing params, this let add new params default and keep existing settings one
			$db = Factory::getContainer()->get('DatabaseDriver');
			$query = method_exists ( $db, 'createQuery' ) ? $db->createQuery () : $db->getQuery ( true );
			$query->select('params');
			$query->from('#__extensions');
			$query->where($db->quoteName('name') . '=' . $db->quote('jrealtimeanalytics'));
			$db->setQuery($query);
			$existingParamsString = $db->loadResult();
			// store the combined new and existing values back as a JSON string
			$existingParams = json_decode ( $existingParamsString, true );
			if(!is_array($existingParams)) {
				$existingParams = [];
			}
			
			$updatedParams = array_merge($params, $existingParams);
			
			$this->setParams($updatedParams);
		}
		
		return true;
	}
	
	/*
	 * $parent is the class calling this method
	 * uninstall runs before any other action is taken (file removal or database processing).
	 */
	function uninstall(InstallerAdapter $parent): bool {
		$database = Factory::getContainer()->get('DatabaseDriver');
		
		$lang = Factory::getApplication()->getLanguage();
		$lang->load('com_jrealtimeanalytics.sys', JPATH_ADMINISTRATOR . '/components/com_jrealtimeanalytics', null, false, true) || $lang->load('com_jrealtimeanalytics.sys', JPATH_ADMINISTRATOR, null, false, true);
		 
		// Controllo esistenza del plugin
		$query = "SELECT extension_id" .
				 "\n FROM #__extensions" .
				 "\n WHERE type = 'plugin' AND element = " . $database->Quote('jrealtimeanalytics') .
				 "\n AND folder = " . $database->Quote('system');
		$database->setQuery($query);
		$pluginID = $database->loadResult();
		if(!$pluginID) {
			echo '<p>' . Text::_('COM_JREALTIME_PLUGIN_ALREADY_REMOVED') . '</p>';
		} else {
			// Si necessita una nuova istanza dell'installer per il plugin
			$pluginInstaller = new Installer ();
			$pluginInstaller->setDatabase($database);
			if(!$pluginInstaller->uninstall('plugin', $pluginID)) {
				echo '<p>' . Text::_('COM_JREALTIME_ERROR_UNINSTALLING_PLUGINS') . '</p>';
			} 
		}
		
		// Check if module exists
		$query = "SELECT extension_id" .
				 "\n FROM #__extensions" .
				 "\n WHERE type = 'module' AND element = " . $database->quote('mod_jrealtimeanalytics') .
				 "\n AND client_id = 0";
		$database->setQuery($query);
		$moduleID = $database->loadResult();
		if(!$moduleID) {
			echo '<p>' . Text::_('COM_JREALTIME_MODULE_ALREADY_REMOVED') . '</p>';
		} else {
			// New plugin installer
			$moduleInstaller = new Installer ();
			$moduleInstaller->setDatabase($database);
			if(!$moduleInstaller->uninstall('module', $moduleID)) {
				echo '<p>' . Text::_('COM_JREALTIME_ERROR_UNINSTALLING_MODULE') . '</p>';
			}
		}
		
		// Processing completo
		return true;
	}
	
	/*
	 * get a variable from the manifest file (actually, from the manifest cache).
	 */
	function getParam($name) {
		$db = Factory::getContainer()->get('DatabaseDriver');
		$db->setQuery ( 'SELECT manifest_cache FROM #__extensions WHERE name = "jrealtimeanalytics"' );
		$manifest = json_decode ( $db->loadResult (), true );
		return $manifest [$name];
	}
	
	/*
	 * sets parameter values in the component's row of the extension table
	 */
	function setParams($param_array) {
		if (count ( $param_array ) > 0) { 
			$db = Factory::getContainer()->get('DatabaseDriver'); 
			// store the combined new and existing values back as a JSON string
			$paramsString = json_encode ( $param_array );
			$db->setQuery ( 'UPDATE #__extensions SET params = ' . $db->quote ( $paramsString ) . ' WHERE name = "jrealtimeanalytics"' );
			$db->execute ();
		}
	}
}

// Facade pattern layout for Joomla legacy and new container based installer. Legacy installer up to 4.2, new container installer from 4.3+
if(version_compare(JVERSION, '4.3', '>=') && interface_exists('\\Joomla\\CMS\\Installer\\InstallerScriptInterface')) {
	return new class () extends JRealtimeAnalyticsBaseInstallerScript implements InstallerScriptInterface {
	};
} else {
	class com_jrealtimeanalyticsInstallerScript extends JRealtimeAnalyticsBaseInstallerScript {
	}
}