<?php
namespace JExtstore\Component\JRealtimeAnalytics\Administrator\Model;
/**
 *
 * @package JREALTIME::GOOGLE::administrator::components::com_jrealtimeanalytics
 * @subpackage models
 * @author Joomla! Extensions Store
 * @copyright (C) 2015 - 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\Uri\Uri;
use JExtstore\Component\JRealtimeAnalytics\Administrator\Framework\Model as JRealtimeModel;
use JExtstore\Component\JRealtimeAnalytics\Administrator\Framework\Exception as JRealtimeException;

/**
 * Google model responsibilities for access Google Analytics and Webmasters Tools API
 *
 * @package JREALTIME::SOURCES::administrator::components::com_jrealtimeanalytics
 * @subpackage models
 * @since 2.6
 */
interface IJRealtimeModelWebmasters {
	/**
	 * Get data method for webmasters tools stats
	 *
	 * @access public
	 * @return mixed Returns a data string if success or boolean if exceptions are trigged
	 */
	public function getDataWebmasters();

	/**
	 * Return the google token
	 *
	 * @access public
	 * @return string
	 */
	public function getToken();
}

/**
 * Sources model concrete implementation <<testable_behavior>>
 *
 * @package JREALTIME::GOOGLE::administrator::components::com_jrealtimeanalytics
 * @subpackage models
 * @since 2.6
 */
class WebmastersModel extends JRealtimeModel implements IJRealtimeModelWebmasters {
	/**
	 * Google_Client object
	 *
	 * @access private
	 * @var Google_Client
	 */
	private $client;
	
	/**
	 * Current profile found for Google Analytics
	 *
	 * @access private
	 * @var string
	 */
	private $currentProfile;
	
	/**
	 * Track the API connection mode, built in JRealtime Google App or user own
	 *
	 * @access private
	 * @var string
	 */
	private $hasOwnCredentials;
	
	/**
	 * Purify and normalize domain protocol
	 *
	 * @access private
	 * @return string
	 */
	private function purifyDomain($domain) {
		return str_replace ( array (
				"https://",
				"http://",
				" "
		), "", rtrim ( $domain, "/" ) );
	}
	
	/**
	 * Purify and normalize domain uri for webmasters tools stats
	 *
	 * @access private
	 * @return string
	 */
	private function purifyWebmastersDomain($domain) {
		return str_replace ( array (
				" "
		), "", rtrim ( $domain, "/" ) );
	}
	
	/**
	 * Manage the authentication form and action
	 *
	 * @param Object $params
	 * @access private
	 * @return mixed A string when auth is needed, null if performing an auth
	 */
	private function authentication($params) {
		$this->client = new \Google_Client ();
		$this->client->setAccessType ( 'offline' );
		$this->client->setScopes ( array('https://www.googleapis.com/auth/analytics.readonly', 'https://www.googleapis.com/auth/webmasters.readonly'));
		$this->client->setApplicationName ( 'JRealtime Analytics' );
		$this->client->setRedirectUri ( 'https://storejextensions.org/oauthauthentication.html' );
		$this->client->setPrompt("consent");
	
		$this->hasOwnCredentials = false;
		if ($params->get ( 'ga_api_key' ) && $params->get ( 'ga_client_id' ) && $params->get ( 'ga_client_secret' )) {
			$this->client->setClientId ( $params->get ( 'ga_client_id' ) );
			$this->client->setClientSecret ( $params->get ( 'ga_client_secret' ) );
			$this->client->setDeveloperKey ( $params->get ( 'ga_api_key' ) ); // API key
			$this->hasOwnCredentials = true;
		} else {
			$this->client->setClientId ( '872567856644-hqr0nu4a5hhf9opbjgmdn1giu055823b.apps.googleusercontent.com' );
			$this->client->setClientSecret ( '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' );
			$this->client->setDeveloperKey ( 'AIzaSyC-4AcgDEPvXZOJ1KMZky7VgOfz4QrQKyc' );
		}
	
		if ($this->getToken ()) { // extract token from session and configure client
			$token = $this->getToken ();
			$this->client->setAccessToken ( $token );
		}

		if (! $result = $this->client->getAccessToken ()) { // auth call to google
			$authUrl = $this->client->createAuthUrl ();
			// Trying to authenticate?
			if (!$this->app->getInput()->get('ga_dash_authorize')) {
				$JoomlaCMSLanguageText = '\Joomla\CMS\Language\Text';
				$htmlSnippet = <<<HTML
					<div id="google-authentication">
						<div class="card w-50 p-3 well">
							<div class="card-block">
								<span class="badge bg-primary">
									{$JoomlaCMSLanguageText::_ ( 'COM_JREALTIME_GOOGLE_STEP1_CODE_DESC' )}
								</span>
		  						<a class="btn btn-success btn-sm hasPopover google" role="button" data-bs-content="{$JoomlaCMSLanguageText::_ ( 'COM_JREALTIME_GOOGLE_CODE_INSTUCTIONS' )}" href="$authUrl" target="_blank">
		  							{$JoomlaCMSLanguageText::_ ( 'COM_JREALTIME_GOOGLE_CODE' )}
		  						</a>
							</div>
						</div>

  						<div class="card w-50 p-3 well">
	  						<div class="card-block">
	  							<span class="badge bg-primary">
	  								{$JoomlaCMSLanguageText::_ ( 'COM_JREALTIME_GOOGLE_STEP2_ACCESS_CODE_INSERT' )}
	  							</span>
	  							<input type="text" name="ga_dash_code" value="" size="61">
  							</div>
  						</div>

  						<div class="card w-50 p-3 well">
  							<div class="card-block">
	  							<span class="badge bg-primary">
	  								{$JoomlaCMSLanguageText::_ ( 'COM_JREALTIME_GOOGLE_STEP3_AUTHENTICATE' )}
	  							</span>
								<input type="submit" class="btn btn-success btn-sm waiter" role="button" name="ga_dash_authorize" value="{$JoomlaCMSLanguageText::_ ( 'COM_JREALTIME_GOOGLE_AUTHENTICATE' )}"/>
							</div>
						</div>
					</div>
HTML;
					return $htmlSnippet;
				} else {
				// Yes! This is an authentication attempt let's try it
				try {
					$this->client->authenticate ( $this->app->getInput()->getString('ga_dash_code'));
  				} catch ( JRealtimeException $e ) {
					$this->app->enqueueMessage ( $e->getMessage (), $e->getExceptionLevel () );
					return '<a class="btn btn-primary" href="index.php?option=com_jrealtimeanalytics&amp;task=webmasters.display">' . Text::_ ( 'COM_JREALTIME_GOBACK' ) . '</a>';
				} catch ( \Exception $e ) {
					$jrealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
					$this->app->enqueueMessage ( $jrealtimeException->getMessage (), $jrealtimeException->getExceptionLevel () );
					return '<a class="btn btn-primary" href="index.php?option=com_jrealtimeanalytics&amp;task=webmasters.display">' . Text::_ ( 'COM_JREALTIME_GOBACK' ) . '</a>';
				}

  				// Store the Google token in the DB for further login and authentication
				$this->storeToken ( $this->client->getAccessToken () );

				return null;
			}
		}
	}

	/**
	 * Store the Google token
	 *
	 * @access private
	 * @return boolean
	 */
	private function storeToken($token) {
		// Ensure that a token is present
		if(!$token) {
			return false;
		}
		
		// Ensure that only 1 record per each client exists in the database
		if($this->getToken()) {
			$this->deleteToken();
		}
		
		$clientID = (int)$this->app->getClientId();
		try {
			$dbToken = is_array($token) ? json_encode($token) : $token;
			$query = "INSERT IGNORE INTO #__realtimeanalytics_google (id, token) VALUES ($clientID," .  $this->dbInstance->quote($dbToken) . ")";
			$this->dbInstance->setQuery ( $query );
			$result = $this->dbInstance->execute ();
			
			// Store logged in status in session
			$session = $this->app->getSession();
			$session->set('jrealtime_ga_authenticate', true);
		} catch ( JRealtimeException $e ) {
			$this->app->enqueueMessage ( $e->getMessage (), $e->getExceptionLevel () );
			$result = false;
		} catch ( \Exception $e ) {
			$jrealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
			$this->app->enqueueMessage ( $jrealtimeException->getMessage (), $jrealtimeException->getExceptionLevel () );
			$result = false;
		}
		
		return $result;
	}
	
	/**
	 * Delete the Google token
	 *
	 * @access private
	 * @return boolean
	 */
	private function deleteToken() {
		$clientID = (int)$this->app->getClientId();
		try {
			$query = "DELETE FROM #__realtimeanalytics_google WHERE id = " . $clientID;
			$this->dbInstance->setQuery ( $query )->execute();
			
			// Store logged in status in session
			$session = $this->app->getSession();
			$session->remove('jrealtime_ga_authenticate');
		} catch ( JRealtimeException $e ) {
			$this->app->enqueueMessage ( $e->getMessage (), $e->getExceptionLevel () );
			return false;
		} catch ( \Exception $e ) {
			$jrealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
			$this->app->enqueueMessage ( $jrealtimeException->getMessage (), $jrealtimeException->getExceptionLevel () );
			return false;
		}
		
		return true;
	}
	
	/**
	 * Get data method for webmasters tools stats
	 *
	 * @access public
	 * @return mixed Returns a data string if success or boolean if exceptions are trigged
	 */
	public function getDataWebmasters() {
		$params = $this->getComponentParams ();
	
		// Perform the authentication management before going on
		$authenticationData = $this->authentication ( $params );
		if($authenticationData) {
			$this->state->set('loggedout', true);
			return $authenticationData;
		}

		// Set the analyzed domain in the model state
		$webmastersStatsDomain = $this->purifyWebmastersDomain( $params->get ( 'wm_domain', Uri::root() )) ;
		$this->state->set('stats_domain', $webmastersStatsDomain);
		$this->state->set('has_own_credentials', $this->hasOwnCredentials);

		$results = array();

		try {
			// New Service instance for the API, Google_Service_Webmasters
			$service = new \Google_Service_Webmasters ( $this->client );
			$postBody = new \Google_Service_Webmasters_SearchAnalyticsQueryRequest();
			
			$postBody->setStartDate($this->getState('fromPeriod'));
			$postBody->setEndDate($this->getState('toPeriod'));
			
			// Fetch data metric
			$postBody->setDimensions(array('query'));
			$results['results_query'] = $service->searchanalytics->query($webmastersStatsDomain, $postBody);
				
			// Fetch data metric
			$postBody->setDimensions(array('page'));
			$results['results_page'] = $service->searchanalytics->query($webmastersStatsDomain, $postBody);
		}  catch ( \Google_Exception $e ) {
			$jrealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
			$this->app->enqueueMessage ( $jrealtimeException->getMessage (), $jrealtimeException->getExceptionLevel () );
			$result = array();
		} catch ( \Exception $e ) {
			$jrealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
			$this->app->enqueueMessage ( $jrealtimeException->getMessage (), $jrealtimeException->getExceptionLevel () );
			$result = array();
		}

		return $results;
	}

	/**
	 * Return the google token
	 *
	 * @access public
	 * @return string
	 */
	public function getToken() {
		$clientID = (int)$this->app->getClientId();
		try {
			$query = "SELECT token FROM #__realtimeanalytics_google WHERE id = " . $clientID;
			$this->dbInstance->setQuery ( $query );
			$result = $this->dbInstance->loadResult ();
		} catch ( JRealtimeException $e ) {
			$this->app->enqueueMessage ( $e->getMessage (), $e->getExceptionLevel () );
			$result = null;
		} catch ( \Exception $e ) {
			$jrealtimeException = new JRealtimeException ( $e->getMessage (), 'error' );
			$this->app->enqueueMessage ( $jrealtimeException->getMessage (), $jrealtimeException->getExceptionLevel () );
			$result = null;
		}
		return $result;
	}

	/**
	 * Return select lists used as filter for editEntity
	 *
	 * @access public
	 * @param Object $record
	 * @return array
	 */
	public function getLists($record = null): array {
		$lists = [];
		return $lists;
	}
	
	/**
	 * Return select lists used as filter for listEntities
	 *
	 * @access public
	 * @return array
	 */
	public function getFilters(): array {
		$filters = [];
		return $filters;
	}
	
	/**
	 * Delete entity
	 *
	 * @param array $ids
	 * @access public
	 * @return bool
	 */
	public function deleteEntity($ids): bool {
		return $this->deleteToken();
	}
	
}