<?php
/**
 * Magento 2 Google Analytics 4 (GA4) GTM
 *
 * NOTICE OF LICENSE
 *
 * This source file is subject to the Anowave license that is
 * available through the world-wide-web at this URL:
 * https://www.anowave.com/license-agreement/
 *
 * DISCLAIMER
 *
 * Do not edit or add to this file if you wish to upgrade this extension to newer
 * version in the future.
 *
 * @category 	Anowave
 * @package 	Anowave_Ec
 * @copyright 	Copyright (c) 2026 Anowave (https://www.anowave.com/)
 * @license  	https://www.anowave.com/license-agreement/
 */

namespace Anowave\Ec\Model;

use Anowave\Ec\vendor\Google\Client as Google_Client;
use Anowave\Ec\vendor\Google\Service\TagManager as Google_Service_TagManager;
use Anowave\Ec\vendor\Google\Service\TagManager\Variable as Google_Service_TagManager_Variable;
use Anowave\Ec\vendor\Google\Service\TagManager\Trigger as Google_Service_TagManager_Trigger;
use Anowave\Ec\vendor\Google\Service\TagManager\Tag as Google_Service_TagManager_Tag;

class Api
{
	const TAG_MANAGER_VARIABLE_TYPE_DATALAYER_VARIABLE 		= 'v';
	const TAG_MANAGER_VARIABLE_TYPE_CONSTANT_VARIABLE 		= 'c';
	const TAG_MANAGER_VARIABLE_TYPE_JAVASCRIPT 				= 'jsm';
	const TAG_MANAGER_VARIABLE_TYPE_GA_SETTINGS 			= 'gas';
	const TAG_MANAGER_VARIABLE_TYPE_USER_DATA 				= 'awec';
	
	/**
	 * Custom event trigger type
	 * 
	 * @var string
	 */
	const TAG_MANAGER_TRIGGER_TYPE_CUSTOM_EVENT 			= 'customEvent';
	
	
	/**
	 * Tag types
	 */
	const TAG_MANAGER_TAG_TYPE_UNIVERSAL_ANALYTICS 			= 'ua';
	const TAG_MANAGER_TAG_TYPE_SOCIAL			 			= 'social';
	const TAG_MANAGER_TAG_TYPE_ADWORDS_DYNAMIC_REMARKETING  = 'sp';
	const TAG_MANAGER_TAG_TYPE_JAVASCRIPT_ERROR				= 'jsError';
	
	/**
	 * All pages trigger 
	 * 
	 * @var integer
	 */
	const TRIGGER_ALL_PAGES = 2147479553;
	
	/*
	 * Trigger names
	 */
	const TRIGGER_ADD_TO_CART 								= 'Event Equals Add To Cart';
	const TRIGGER_REMOVE_FROM_CART 							= 'Event Equals Remove From Cart';
	const TRIGGER_CHECKOUT 									= 'Event Equals Checkout';
	const TRIGGER_CHECKOUT_OPTION 							= 'Event Equals Checkout Option';
	const TRIGGER_PRODUCT_CLICK								= 'Event Equals Product Click';
	const TRIGGER_REMARKETING_TAG							= 'Event Equals Dynamic Remarketing';
	const TRIGGER_SOCIAL_INTERACTION 						= 'Event Equals Social Interaction';
	const TRIGGER_USER_TIMING								= 'Event Equals User Timing';
	const TRIGGER_PURCHASE									= 'Event Equals Purchase';
	const TRIGGER_IMPRESSION								= 'Event Equals Impression';
	const TRIGGER_PROMOTION_CLICK							= 'Event Equals Promotion Click';
	const TRIGGER_PROMOTION_VIEW							= 'Event Equals Promotion View Non Interactive';
	const TRIGGER_NEW_WIDGET_VIEW							= 'Event Equals NewProducts View Non Interactive';
	const TRIGGER_DETAIL									= 'Event Equals Detail';
	const TRIGGER_ADD_WISHLIST								= 'Event Equals Wishlist';
	const TRIGGER_ADD_COMPARE								= 'Event Equals Compare';
	const TRIGGER_COOKIE_CONSENT_GRANTED					= 'Event Equals Cookie Consent Granted';
	const TRIGGER_JAVASCRIPT_ERROR							= 'Event Equals Javascript Error';
	const TRIGGER_PERFORMANCE								= 'Event Equals Performance';
	const TRIGGER_VIRTUAL_VARIANT_VIEW						= 'Event Equals Virtual Variant View';
	
	/**
	 * Tag names
	 */
	const TAG_UA											= 'Universal Analytics';
	const TAG_ADD_TO_CART									= 'EE Add To Cart';
	const TAG_REMOVE_FROM_CART								= 'EE Remove From Cart';
	const TAG_CHECKOUT										= 'EE Checkout Step';
	const TAG_CHECKOUT_OPTION								= 'EE Checkout Step Option';
	const TAG_PRODUCT_CLICK									= 'EE Product Click';
	const TAG_SOCIAL_INTERACTION							= 'EE Social Interaction';
	const TAG_ADWORDS_DYNAMIC_REMARKETING					= 'EE AdWords Dynamic Remarketing';
	const TAG_USER_TIMING									= 'EE User Timing';
	const TAG_PURCHASE										= 'EE Async Purchase';
	const TAG_IMPRESSION									= 'EE Async Impression';
	const TAG_DETAIL										= 'EE Async Detail';
	const TAG_PROMOTION_CLICK								= 'EE Promotion Click';
	const TAG_PROMOTION_VIEW								= 'EE Promotion View';
	const TAG_NEW_WIDGET_VIEW								= 'EE NewProducts View';
	const TAG_ADD_TO_WISHLIST								= 'EE Add To Wishlist';
	const TAG_ADD_TO_COMPARE								= 'EE Add To Compare';
	const TAG_PERFORMANCE									= 'EE Performance';
	const TAG_VIRTUAL_VARIANT_VIEW							= 'EE Virtual Variant View';
	
	/**
	 * Variable names
	 */
	const VARIABLE_GA										= 'Google Analytics Settings';
	
	
	/**
	 * API client
	 * 
	 * @var string
	 */
	const CLIENT_ID = '602515785233-9om8aq0dga2ii9utnsmei3j24tuj8m7t.apps.googleusercontent.com';
	
	/**
	 * API client secret 
	 * 
	 * @var string
	 */
	const CLIENT_ID_SECRET = 'hcXqZnqAF8VMzJIEeTiRjwsp';
	
	/**
	 * @var Google_Service_TagManager
	 */
	private $service = null;
	
	/**
	 * OAuth2
	 *
	 * @var Google_Service_Oauth2
	 */
	private $oauth = null;
	
	/**
	 * OAuth Scopes
	 *
	 * @var array
	 */
	private $client = null;
	
	/**
	 * Access scopes 
	 * 
	 * @var []
	 */
	private $scopes = array
	(
		'https://www.googleapis.com/auth/userinfo.profile',
		'https://www.googleapis.com/auth/tagmanager.readonly',
		'https://www.googleapis.com/auth/tagmanager.edit.containers'
	);
	
	private $containers = [];
	
	/**
	 * Number of requests 
	 * 
	 * @var integer
	 */
	private $usleep = 2000000;
	
	/**
	 * Current variables
	 * 
	 * @var array
	 */
	protected $currentVariables = [];
	
	/**
	 * Current triggers
	 * 
	 * @var array
	 */
	protected $currentTriggers = [];
	
	/**
	 * Current tags
	 * 
	 * @var array
	 */
	protected $currentTags = [];
	
	/**
	 * @var \Magento\Backend\Helper\Data
	 */
	protected $helperBackend;
	
	/**
	 * @var \Magento\Framework\Session\SessionManagerInterface
	 */
	protected $session;
	
	/**
	 * @var \Anowave\Ec\Helper\Scope
	 */
	protected $scope;
	
	/**
	 * @var \Magento\Store\Model\StoreManagerInterface
	 */
	protected $storeManager;
	
	/**
	 * @var \Magento\Framework\Message\ManagerInterface
	 */
	protected $messageManager;
	
	/**
	 * @var \Anowave\Ec\Helper\Data
	 */
	protected $helper;
	
	/**
	 * Constructor 
	 * 
	 * @param \Magento\Backend\Helper\Data $helperBackend
	 * @param \Magento\Framework\Session\SessionManagerInterface $session
	 * @param \Magento\Store\Model\StoreManagerInterface $storeManager
	 * @param \Magento\Framework\Message\ManagerInterface $messageManager
	 * @param \Anowave\Ec\Helper\Scope $scope
	 * @param \Anowave\Ec\Helper\Data $helper
	 */
	public function __construct
	(
		\Magento\Backend\Helper\Data $helperBackend,
		\Magento\Framework\Session\SessionManagerInterface $session,
		\Magento\Store\Model\StoreManagerInterface $storeManager,
		\Magento\Framework\Message\ManagerInterface $messageManager,
		\Anowave\Ec\Helper\Scope $scope,
	    \Anowave\Ec\Helper\Data $helper
	)
	{
		set_time_limit(0);
		
		/**
		 * Set helper
		 * 
		 * @var \Anowave\Ec\Helper\Data $helper
		 */
		$this->helper = $helper;
		/**
		 * Set backend helper 
		 * 
		 * @var \Magento\Backend\Helper\Data $helper
		 */
		$this->helperBackend = $helperBackend;
		
		/**
		 * Set session 
		 * 
		 * @var \Magento\Framework\Session\SessionManagerInterface
		 */
		$this->session = $session;

		/**
		 * Set store manager 
		 * 
		 * @var \Magento\Store\Model\StoreManagerInterface $storeManager
		 */
		$this->storeManager = $storeManager;
		
		/**
		 * Set message manager 
		 * 
		 * @var \Magento\Framework\Message\ManagerInterface $messageManager
		 */
		$this->messageManager = $messageManager;
		
		/**
		 * Set scope 
		 * 
		 * @var \Anowave\Ec\Helper\Scope $scope
		 */
		$this->scope = $scope;
		
		$throttle = (int) $this->scope->getConfig('ec/api/throttle');
		
		if ($throttle)
		{
			$this->usleep = $throttle;
		}
	}
	
	/**
	 * Get Client
	 *
	 * @return Google_Client
	 */
	public function getClient()
	{
		if (!$this->client)
		{
			$this->client = new Google_Client();
	
			/**
			 * Set Application name
			*/
			$this->client->setApplicationName('Anowave');

			/**
			 * Set client id
			 */
			$this->client->setClientId
			(
				$this->getClientId()
			);
			
			/**
			 * Set client secret
			 */
			$this->client->setClientSecret
			(
				$this->getClientSecret()
			);			

			/**
			 * Set scopes
			*/
			$this->client->setScopes($this->scopes);
	
			/**
			 * Set state
			 */
			$this->client->setState
			(
				$this->helperBackend->getUrl("adminhtml/system_config/edit", array('section' => 'ec'))
			);
	
			/**
			 * Set redirect URI
			*/
			$this->client->setRedirectUri('https://oauth.anowave.com/');
	
			/**
			 * Check authorisation code
			*/
			if (isset($_GET['code']))
			{
				$this->getClient()->authenticate($_GET['code']);
					
				$this->session->setAccessToken
				(
					$this->client->getAccessToken()
				);
					
				header('Location: ' . $this->helperBackend->getUrl("adminhtml/system_config/edit", array('section' => 'ec')));
				exit();
			}
				
			/**
			 * Check session access token
				*/
			$token = $this->session->getAccessToken();
	
			if ($token)
			{
				$this->client->setAccessToken($token);
			}
		}
	
		return $this->client;
	}
	
	/**
	 * Create Google Tag Manager entries
	 *
	 * @param string $entry
	 * @return mixed|NULL
	 */
	public function create($entry)
	{
		if (method_exists($this, $entry))
		{
			/**
			 * Get scope code
			 * 
			 * @var string
			 */
			return call_user_func_array(array($this, $entry), array
			(
				trim($this->scope->getConfig('ec/api/google_gtm_account_id')),
				trim($this->scope->getConfig('ec/api/google_gtm_container'))
			));
		}
		
		return array();
	}

	/**
	 * Create container variables
	 */
	public function ec_api_variables($account, $container)
	{
		/**
		 * Create transport object
		 *
		 * @var \Magento\Framework\DataObject $transport
		 */
		$transport = new \Magento\Framework\DataObject
		(
		    [
		        'schema' => []
		    ]
	    );
		
		/**
		 * Notify others for schema
		 */
		$this->helper->getEventManager()->dispatch('ec_schema_variables', ['transport' => $transport]);
		
		return $this->generate_variables($transport->getSchema(), $account, $container);
	}
	
	/**
	 * Create container triggers
	 */
	public function ec_api_triggers($account, $container)
	{
		/**
		 * Create transport object
		 *
		 * @var \Magento\Framework\DataObject $transport
		 */
		$transport = new \Magento\Framework\DataObject
		(
		    [
		        'schema' => []
		    ]
	    );
		
		/**
		 * Notify others for schema
		 */
		$this->helper->getEventManager()->dispatch('ec_schema_triggers', ['transport' => $transport]);
		
		return $this->generate_triggers($transport->getSchema(), $account, $container);
	}
	
	/**
	 * Create tags
	 *
	 * @param string $account
	 * @param int $container
	 */
	public function ec_api_tags($account, $container)
	{
		/**
		 * Create transport object
		 *
		 * @var \Magento\Framework\DataObject $transport
		 */
		$transport = new \Magento\Framework\DataObject
		(
		    [
		        'schema'   => [],
		        'triggers' => $this->getTriggersMap($account, $container),
		        'tags'     => $this->getCurrentTags($account, $container)
		    ]
	    );
		
		/**
		 * Notify others for schema
		 */
		$this->helper->getEventManager()->dispatch('ec_schema_tags', ['transport' => $transport]);
		
		return $this->generate_tags($transport->getSchema(), $account, $container);;
	}
	
	/**
	 * Generate variables
	 *
	 * @param array $schema
	 * @return array
	 */
	public function generate_variables($schema, $account, $container) : array
	{
	    $set = [];
	    
	    /**
	     * Get existing variables
	     */
	    $variables = $this->getCurrentVariables($account, $container);
	    
	    /**
	     * Check which variables already exist
	     */
	    foreach ($variables as $variable)
	    {
	        $set[$variable->name] = true;
	    }
	    
	    $log = [];
	    
	    foreach ($schema as $variable => $parameters)
	    {
	        try
	        {
	            if (!isset($set[$variable]))
	            {
	                $response = $this->getService()->accounts_containers_variables->create($account, $container, new Google_Service_TagManager_Variable($parameters));
	                
	                if ($response instanceof Google_Service_TagManager_Variable && $response->variableId)
	                {
	                    $log[] = 'Created variable ' . $response->name;
	                }
	                else
	                {
	                    $log[] = 'Failed to create variable ' . $response->name;
	                }
	                
	                if ($this->usleep)
	                {
	                    usleep($this->usleep);
	                }
	            }
	        }
	        catch (\Exception $e)
	        {
	            $log[] = $e->getMessage();
	        }
	    }
	    
	    return $log;
	}
	
	/**
	 * Generate triggers
	 *
	 * @param array $schema
	 * @return array
	 */
	public function generate_triggers($schema, $account, $container) : array
	{
	    $set = [];
	    $log = [];
	    
	    /**
	     * Get existing triggers
	     * 
	     * @var [] $triggers
	     */
	    $triggers = $this->getCurrentTriggers($account, $container);
	    
	    foreach ($triggers as $trigger)
	    {
	        $set[$trigger->name] = true;
	    }
	    
	    foreach ($schema as $trigger => $parameters)
	    {
	        try
	        {
	            if (!isset($set[$trigger]))
	            {
	                $response = $this->getService()->accounts_containers_triggers->create($account, $container, new Google_Service_TagManager_Trigger($parameters));
	                
	                if ($response instanceof Google_Service_TagManager_Trigger && $response->triggerId)
	                {
	                    $log[] = 'Created trigger ' . $response->name;
	                }
	                else
	                {
	                    $log[] = 'Failed to create trigger ' . $response->name;
	                }
	                
	                if ($this->usleep)
	                {
	                    usleep($this->usleep);
	                }
	            }
	        }
	        catch (\Exception $e)
	        {
	            $log[] = $e->getMessage();
	        }
	    }
	    
	    return $log;
	}
	
	/**
	 * Generate tags
	 * 
	 * @param array $schema
	 * @return array
	 */
	public function generate_tags($schema, $account, $container) : array
	{
	    $log = [];
	    $set = [];
	    
	    $tags = $this->getCurrentTags($account, $container);
	    
	    foreach ($tags as $tag)
	    {
	        $set[$tag->name] = true;
	    }
	    
	    foreach ($schema as $tag => $parameters)
	    {
	        try
	        {
	            if (!isset($set[$tag]))
	            {
	                $response = $this->getService()->accounts_containers_tags->create($account, $container, new Google_Service_TagManager_Tag($parameters));
	                
	                if ($response instanceof Google_Service_TagManager_Tag && $response->tagId)
	                {
	                    $log[] = 'Created tag ' . $response->name;
	                }
	                else
	                {
	                    $log[] = 'Failed to create tag ' . $response->name;
	                }
	                
	                if ($this->usleep)
	                {
	                    usleep($this->usleep);
	                }
	            }
	        }
	        catch (\Exception $e)
	        {
	            $log[] = $e->getMessage();
	        }
	    }
	    
	    return $log;
	}
	
	public function ec_api_version($account, $container)
	{
		$log = [];
		$set = [];
	
		return $this->getService()->accounts_containers_versions->listAccountsContainersVersions($account, $container);
	}
	
	public function getService()
	{
		if (!$this->service)
		{
			$this->service = new Google_Service_TagManager
			(
				$this->getClient()
			);
		}
	
		return $this->service;
	}
	
	public function getOauth()
	{
		if (!$this->oauth)
		{
			$this->oauth = new Google_Service_Oauth2
			(
				$this->getClient()
			);
		}
	
		return $this->oauth;
	}
	
	/**
	 * Get account containers 
	 * 
	 * @param int $account
	 * @return array
	 */
	public function getContainers($account)
	{
		if ($this->getClient()->isAccessTokenExpired())
		{
			return array();
		}
	
		if (!$this->containers)
		{
			$this->containers = $this->getService()->accounts_containers->listAccountsContainers($account)->getContainers();
		}

		return $this->containers;
	}
	
	/**
	 * Get containers map 
	 * 
	 * @param int $account
	 * @return NULL[]
	 */
	public function getContainersMap($account)
	{
		$map = [];
		
		foreach ($this->getContainers($account) as $container) 
		{
			$map[$container->containerId] = $container->publicId;
		}
		
		return $map;
	}
	
	public function getTriggers($account, $container)
	{
		return $this->getCurrentTriggers($account, $container);
	}
	
	public function getTriggersMap($account, $container)
	{
		$map = [];
	
		foreach ($this->getTriggers($account, $container) as $trigger)
		{
			$map[$trigger->name] = $trigger->triggerId;
		}
	
		return $map;
	}

	/**
	 * Get safe conversion id
	 */
	protected function getAdwordsConversionId()
	{
		$value = $this->scope->getConfig('ec/api/google_adwords_conversion_id');
			
		if ('' == $value)
		{
			return 0;
		}
	
		return $value;
	}
	
	/**
	 * Get client id
	 * 
	 * @return string
	 */
	protected function getClientId()
	{
		if (0 === (int) $this->scope->getConfig('ec/api/use_built_in_credentials'))
		{
			$value = trim
			(
			    (string) $this->scope->getConfig('ec/api/override_client_id')
			);
			
			if ($value)
			{
				return $value;
			}
		}
		
		return static::CLIENT_ID;
	}
	
	/**
	 * Get client secret
	 * 
	 * @return string
	 */
	protected function getClientSecret()
	{
		if (0 === (int) $this->scope->getConfig('ec/api/use_built_in_credentials'))
		{
			$value = trim
			(
			    (string) $this->scope->getConfig('ec/api/override_client_secret')
			);
			
			if ($value)
			{
				return $value;
			}
		}
		
		return static::CLIENT_ID_SECRET;
	}
	
	/**
	 * Get safe conversion label
	 */
	protected function getAdwordsConversionLabel()
	{
		$value = $this->scope->getConfig('ec/api/google_adwords_conversion_label');
		
		if ('' == $value)
		{
			return 0;
		}
	
		return $value;
	}
	
	protected function getGoogleAnalyticsSettings()
	{
		return '{{' . self::VARIABLE_GA . '}}';
	}
	
	/**
	 * Get current variables 
	 * 
	 * @param string $account
	 * @param string $container
	 * @return array
	 */
	public function getCurrentVariables($account, $container)
	{
	    if (!$this->currentVariables)
	    {
	        $this->currentVariables = $this->getService()->accounts_containers_variables->listAccountsContainersVariables($account, $container)->getVariables();
	    }
	    
	    return $this->currentVariables;
	}
	
	/**
	 * Get current triggers
	 *
	 * @param string $account
	 * @param string $container
	 * @return array
	 */
	public function getCurrentTriggers($account, $container)
	{
	    if (!$this->currentTriggers)
	    {
	        $this->currentTriggers = $this->getService()->accounts_containers_triggers->listAccountsContainersTriggers($account, $container)->getTriggers();
	    }
	    
	    return $this->currentTriggers;
	}
	
	/**
	 * Get current tags
	 *
	 * @param string $account
	 * @param string $container
	 * @return array
	 */
	public function getCurrentTags($account, $container)
	{
	    if (!$this->currentTags)
	    {
	        $this->currentTags = $this->getService()->accounts_containers_tags->listAccountsContainersTags($account, $container)->getTags();
	    }
	    
	    return $this->currentTags;
	}
	
}