<?php
/**
 * Google Tag Manager Automation
 *
 * Handles automation for Google Tag Manager (GTM) by creating variables, triggers, and tags dynamically.
 *
 * @package StrategySuite
 */

namespace StrategySuite;

use Google\Client as Google_Client;
use Google\Service\Exception as Google_Exception;
use Google\Service\TagManager as GSTM;
use Google\Service\TagManager\Condition;
use Google\Service\TagManager\CreateContainerVersionRequestVersionOptions;
use Google\Service\TagManager\Parameter;
use Google\Service\TagManager\Tag;
use Google\Service\TagManager\Trigger;
use Google\Service\TagManager\Variable;

/**
 * Class GTM_Automation
 *
 * Provides automation functions for managing Google Tag Manager (GTM) containers,
 * including creating variables, triggers, and tags.
 */
class GTM_Automation {

	/**
	 * Default ID for firing triggers on all pages.
	 */
	private const INITIAL_ALL_PAGES_ID = '2147479573';

	/**
	 * Path to the service account JSON file.
	 *
	 * @var string
	 */
	private $service_account_file_path;

	/**
	 * Google Tag Manager Account ID.
	 *
	 * @var string
	 */
	private $account_id;

	/**
	 * Google Tag Manager Container ID.
	 *
	 * @var string
	 */
	private $container_id;

	/**
	 * Google API Client instance.
	 *
	 * @var Google_Client
	 */
	private $client;

	/**
	 * Scopes required for Google Tag Manager API access.
	 *
	 * @var array
	 */
	private $scopes = [];

	/**
	 * GTM_Automation constructor.
	 *
	 * Initializes the Google API client for managing Google Tag Manager.
	 *
	 * @param string $account_id      The GTM account ID.
	 * @param string $container_id    The GTM container ID.
	 * @param string $service_account The service account type (default: 'adwords').
	 */
	public function __construct( $account_id, $container_id, $service_account = 'adwords' ) {
		$this->account_id = $account_id;
		$this->container_id = $container_id;

		// $autoload_path = '' === trim($_SERVER['DOCUMENT_ROOT']) ? 'vendor/autoload.php' : dirname($_SERVER['DOCUMENT_ROOT']) . '/vendor/autoload.php';
		// require_once $autoload_path;
		$this->client = new Google_Client();
		$this->scopes = [
			GSTM::TAGMANAGER_MANAGE_ACCOUNTS,
			GSTM::TAGMANAGER_EDIT_CONTAINERS,
			GSTM::TAGMANAGER_EDIT_CONTAINERVERSIONS,
			GSTM::TAGMANAGER_PUBLISH,
		];

		$this->service_account_file_path = STRATEGY_SUITE_PATH . 'oauth/automation-service-account-' . $service_account . '.json';
		$this->client->setAuthConfig( $this->service_account_file_path );
		$this->client->useApplicationDefaultCredentials();
		$this->client->setScopes( $this->scopes );
	}

	/**
	 * Generates default tag templates with associated triggers.
	 *
	 * @param array $trigger_ids List of trigger IDs.
	 * @param array $args        Additional arguments.
	 *
	 * @return array|null Returns an array of default tags with triggers or null if input is invalid.
	 */
	protected function default_tags_with_triggers( $trigger_ids, $args = [] ) {
		if ( ! is_array( $trigger_ids ) ) {
			return null;
		}

		$defaults = $this->default_tag_templates( $args );

		foreach ( $trigger_ids as $trigger_name => $trigger_id ) {
			$tag_name = $this->derive_default_tag_from_trigger( $trigger_name );
			if ( false !== $trigger_id && null !== $tag_name && isset( $defaults[ $tag_name ] ) ) {
				if ( isset( $defaults[ $tag_name ]['triggers'] ) ) {
					$defaults[ $tag_name ]['triggers'] = array_merge( $defaults[ $tag_name ]['triggers'], [ $trigger_id ] );
				} else {
					$defaults[ $tag_name ]['triggers'] = [ $trigger_id ];
				}
			}
		}

		return $defaults;
	}

	/**
	 * Derives the default tag name from a trigger name.
	 *
	 * @param string $trigger The trigger name.
	 *
	 * @return string|null Returns the tag name or null if no match is found.
	 */
	protected function derive_default_tag_from_trigger( $trigger ) {
		switch ( $trigger ) {
			case 'All Email Clicks':
				return 'GA4 - Email Click';
			case 'All Phone Clicks':
				return 'GA4 - Phone Click';
			case 'All Form Submissions':
				return 'GA4 - Form Submission';
			default:
				return null;
		}
	}

	/**
	 * Constructs a GTM API resource path.
	 *
	 * @param array $args Optional arguments for additional path segments.
	 *
	 * @return string The constructed API path.
	 */
	protected function build_path( $args = [] ) {
		$path = 'accounts/' . $this->account_id . '/containers/' . $this->container_id;
		if ( 0 < count( $args ) ) {
			foreach ( $args as $arg ) {
				if ( is_array( $arg ) && 2 === count( $arg ) ) {
					$path .= '/' . $arg[0] . '/' . $arg[1];
				}
			}
		}
		return $path;
	}

	/**
	 * Checks if all elements in an array are non-null.
	 *
	 * @param array $args The array to check.
	 *
	 * @return bool True if all values are non-null, false otherwise.
	 */
	protected function all_non_null( $args = [] ) {
		if ( ! is_array( $args ) ) {
			return false;
		}

		foreach ( $args as $arg ) {
			if ( ! $arg ) {
				return false;
			}
		}

		return true;
	}

	/**
	 * Converts a string to camel case format.
	 *
	 * @param string $string The string to convert.
	 *
	 * @return string The camel case string.
	 */
	protected function to_camel_case( $string ) {
		$string = preg_replace( '/[^a-zA-Z0-9]+/', ' ', $string );
		$string = ucwords( $string );
		$string = str_replace( ' ', '', $string );
		$string = lcfirst( $string );

		return $string;
	}

	/**
	 * Creates an event name with an optional suffix.
	 *
	 * @param string $string     The base event name.
	 * @param bool   $add_suffix Whether to add the "Submission" suffix.
	 *
	 * @return string The generated event name.
	 */
	protected function create_event_name( $string, $add_suffix = true ) {
		$suffix = 'Submission';
		$max_length = $add_suffix ? 40 - strlen( $suffix ) : 40;
		$event_name = substr( $this->to_camel_case( $string ), 0, $max_length );
		$event_name .= $add_suffix ? $suffix : '';
		return $event_name;
	}

	/**
	 * Builds a form submission tag template.
	 *
	 * @param string $form_title The title of the form.
	 * @param array  $triggers The triggers to apply the tag with.
	 *
	 * @return array The form submission trigger template.
	 */
	protected function build_form_tag_template( $form_title, $triggers = [] ) {
		$title = 'GA4 - Form Submission [' . trim( $form_title ) . ']';
		$templates = [];
		$templates[ $title ] = [
			'name'      => $title,
			'type'      => 'GA4 - Event',
			'event_name'    => $this->create_event_name( $form_title ),
			'triggers'      => $triggers,
		];

		return $templates;
	}

	/**
	 * Builds a form submission trigger template.
	 *
	 * @param string $form_title The title of the form.
	 *
	 * @return array The form submission trigger template.
	 */
	protected function build_form_trigger_template( $form_title ) {
		$title = 'Form Submission [' . trim( $form_title ) . ']';
		$templates = [];
		$templates[ $title ] = [
			'name'      => $title,
			'type'      => 'Custom Event',
			'event_name'    => 'customFormSubmission',
			'form_title'    => $form_title,
		];

		return $templates;
	}

	/**
	 * Retrieves the default tag templates for GTM.
	 *
	 * @param array $args Optional arguments to customize the template.
	 *
	 * @return array An array of default GTM tag templates.
	 */
	protected function default_tag_templates( $args = [] ) {
		$defaults = [
			'GA4 - Tracking Script' => [
				'name'      => 'GA4 - Tracking Script',
				'type'      => 'GA4 - Tracking Script',
				'triggers'  => [],
			],
			'GA4 - Email Click' => [
				'name'          => 'GA4 - Email Click',
				'type'          => 'GA4 - Event',
				'event_name'    => 'emailClick',
				'triggers'      => [],
			],
			'GA4 - Phone Click' => [
				'name'          => 'GA4 - Phone Click',
				'type'          => 'GA4 - Event',
				'event_name'    => 'phoneClick',
				'triggers'      => [],
			],
			'GA4 - Form Submission' => [
				'name'          => 'GA4 - Form Submission',
				'type'          => 'GA4 - Event',
				'event_name'    => 'customFormSubmission',
				'triggers'      => [],
			],
		];

		if ( isset( $args['exclude'] ) && is_array( $args['exclude'] ) ) {
			foreach ( $args['exclude'] as $exclusion ) {
				if ( isset( $defaults[ $exclusion ] ) ) {
					unset( $defaults[ $exclusion ] );
				}
			}
		}

		return $defaults;
	}

	/**
	 * Retrieves the default trigger templates for GTM.
	 *
	 * @param array $args Optional arguments to exclude certain triggers.
	 *
	 * @return array An array of default GTM trigger templates.
	 */
	protected function default_trigger_templates( $args = [] ) {
		$defaults = [
			'All Email Clicks'  => [
				'name'              => 'All Email Clicks',
				'type'              => 'Link Click',
				'condition_type'    => 'contains',
				'on'                => '{{Click URL}}',
				'where'             => 'mailto:',
			],
			'All Phone Clicks'  => [
				'name'              => 'All Phone Clicks',
				'type'              => 'Link Click',
				'condition_type'    => 'contains',
				'on'                => '{{Click URL}}',
				'where'             => 'tel:',
			],
			'All Form Submissions'   => [
				'name'          => 'All Form Submissions',
				'type'          => 'Custom Event',
				'event_name'    => 'customFormSubmission',
			],
		];

		if ( isset( $args['exclude'] ) && is_array( $args['exclude'] ) ) {
			foreach ( $args['exclude'] as $exclusion ) {
				if ( isset( $defaults[ $exclusion ] ) ) {
					unset( $defaults[ $exclusion ] );
				}
			}
		}

		return $defaults;
	}

	/**
	 * Retrieves the default variable templates for GTM.
	 *
	 * @param array $args Optional arguments to exclude certain variables.
	 *
	 * @return array An array of default GTM variable templates.
	 */
	protected function default_variable_templates( $args = [] ) {
		$defaults = [
			'GA4 - Measurement ID'  => [
				'name'  => 'GA4 - Measurement ID',
				'type'  => 'Constant',
				'value' => isset( $args['measurement_id'] ) ? $args['measurement_id'] : 'REPLACE_ME',
			],
			'Form Title'    => [
				'name'              => 'Form Title',
				'type'              => 'Data Layer',
				'target_variable'   => 'formTitle',
			],
		];

		if ( isset( $args['exclude'] ) && is_array( $args['exclude'] ) ) {
			foreach ( $args['exclude'] as $exclusion ) {
				if ( isset( $defaults[ $exclusion ] ) ) {
					unset( $defaults[ $exclusion ] );
				}
			}
		}

		return $defaults;
	}

	/**
	 * Generates a GTM tag schema based on provided arguments.
	 *
	 * @param array $args Configuration options for the tag.
	 *
	 * @return Tag|null Returns a Tag object or null if input is invalid.
	 */
	protected function tag_schema( $args = [] ) {
		if ( ! isset( $args['type'] ) ) {
			return null;
		}

		$tag = new Tag();
		switch ( $args['type'] ) {
			case 'GA4 - Tracking Script':
				if ( $this->all_non_null( [ $args['name'] ] ) ) {
					$triggers = [ self::INITIAL_ALL_PAGES_ID ];
					if ( isset( $args['triggers'] ) ) {
						$triggers = array_merge( $triggers, $args['triggers'] );
					}
					$tag->setName( $args['name'] );
					$tag->setFiringTriggerId( $triggers );
					$tag->setTagFiringOption( 'oncePerEvent' );
					$tag->setType( 'googtag' );
					$tag->setParameter(
						[
							new Parameter(
								[
									'key'   => 'tagId',
									'type'  => 'template',
									'value' => '{{GA4 - Measurement ID}}',
								]
							),
						]
					);
				}
				break;
			case 'GA4 - Event':
				if ( $this->all_non_null( [ $args['name'], $args['event_name'] ] ) ) {
					$triggers = [];
					if ( isset( $args['triggers'] ) ) {
						$triggers = array_merge( $triggers, $args['triggers'] );
					}
					$tag->setName( $args['name'] );
					$tag->setFiringTriggerId( $triggers );
					$tag->setTagFiringOption( 'oncePerEvent' );
					$tag->setType( 'gaawe' );
					$tag->setParameter(
						[
							new Parameter(
								[
									'key'   => 'sendEcommerceData',
									'type'  => 'boolean',
									'value' => 'false',
								]
							),
							new Parameter(
								[
									'key'   => 'enhancedUserId',
									'type'  => 'boolean',
									'value' => 'false',
								]
							),
							new Parameter(
								[
									'key'   => 'eventName',
									'type'  => 'template',
									'value' => $args['event_name'],
								]
							),
							new Parameter(
								[
									'key'   => 'measurementIdOverride',
									'type'  => 'template',
									'value' => '{{GA4 - Measurement ID}}',
								]
							),
						]
					);
				}
				break;
			default:
				break;
		}

		return $tag;
	}

	/**
	 * Generates a GTM trigger schema based on provided arguments.
	 *
	 * @param array $args Configuration options for the trigger.
	 *
	 * @return Trigger|null Returns a Trigger object or null if input is invalid.
	 */
	protected function trigger_schema( $args = [] ) {
		if ( ! isset( $args['type'] ) ) {
			return null;
		}

		$trigger = new Trigger();
		switch ( $args['type'] ) {
			case 'Link Click':
				if ( $this->all_non_null( [ $args['name'], $args['condition_type'], $args['on'], $args['where'] ] ) ) {
					$trigger->setName( $args['name'] );
					$trigger->setType( 'linkClick' );
					$trigger->setFilter(
						[
							new Condition(
								[
									'type'  => $args['condition_type'],
									'parameter' => [
										new Parameter(
											[
												'key'   => 'arg0',
												'type'  => 'template',
												'value' => $args['on'],
											]
										),
										new Parameter(
											[
												'key'   => 'arg1',
												'type'  => 'template',
												'value' => $args['where'],
											]
										),
									],
								]
							),
						]
					);
					$trigger->setWaitForTags(
						new Parameter(
							[
								'type'  => 'boolean',
								'value' => 'false',
							]
						)
					);
					$trigger->setCheckValidation(
						new Parameter(
							[
								'type'  => 'boolean',
								'value' => 'false',
							]
						)
					);
				}
				break;
			case 'Custom Event':
				if ( $this->all_non_null( [ $args['name'], $args['event_name'] ] ) ) {
					$trigger->setName( $args['name'] );
					$trigger->setType( 'customEvent' );
					$trigger->setCustomEventFilter(
						[
							new Condition(
								[
									'type'      => 'equals',
									'parameter' => [
										new Parameter(
											[
												'key'   => 'arg0',
												'type'  => 'template',
												'value' => '{{_event}}',
											]
										),
										new Parameter(
											[
												'key'   => 'arg1',
												'type'  => 'template',
												'value' => $args['event_name'],
											]
										),
									],
								]
							),
						]
					);
					if ( isset( $args['form_title'] ) ) {
						$trigger->setFilter(
							[
								new Condition(
									[
										'type'      => 'equals',
										'parameter' => [
											new Parameter(
												[
													'key'   => 'arg0',
													'type'  => 'template',
													'value' => '{{Form Title}}',
												]
											),
											new Parameter(
												[
													'key'   => 'arg1',
													'type'  => 'template',
													'value' => $args['form_title'],
												]
											),
										],
									]
								),
							]
						);
					}
				}
				break;
			default:
				break;
		}

		return $trigger;
	}

	/**
	 * Generates a GTM variable schema based on provided arguments.
	 *
	 * @param array $args Configuration options for the variable.
	 *
	 * @return Variable|null Returns a Variable object or null if input is invalid.
	 */
	protected function variable_schema( $args = [] ) {
		if ( ! isset( $args['type'] ) ) {
			return null;
		}

		$variable = new Variable();
		switch ( $args['type'] ) {
			case 'Constant':
				if ( $this->all_non_null( [ $args['name'], $args['value'] ] ) ) {
					$variable->setName( $args['name'] );
					$variable->setType( 'c' );
					$variable->setParameter(
						[
							new Parameter(
								[
									'key'   => 'value',
									'type'  => 'template',
									'value' => $args['value'],
								]
							),
						]
					);
				}
				break;
			case 'Data Layer':
				if ( $this->all_non_null( [ $args['name'], $args['target_variable'] ] ) ) {
					$variable->setName( $args['name'] );
					$variable->setType( 'v' );
					$variable->setParameter(
						[
							new Parameter(
								[
									'key'   => 'dataLayerVersion',
									'type'  => 'integer',
									'value' => 2,
								]
							),
							new Parameter(
								[
									'key'   => 'setDefaultValue',
									'type'  => 'boolean',
									'value' => 'false',
								]
							),
							new Parameter(
								[
									'key'   => 'name',
									'type'  => 'template',
									'value' => $args['target_variable'],
								]
							),
						]
					);
				}
				break;
			default:
				break;
		}

		return $variable;
	}

	/**
	 * Creates a new workspace version schema.
	 *
	 * @param array $args Optional arguments to override default settings.
	 *
	 * @return CreateContainerVersionRequestVersionOptions The workspace version schema object.
	 */
	protected function workspace_version_schema( $args = [] ) {
		$defaults = [
			'name'  => 'Automated Update',
			'notes' => 'This update was created by the LeadFuel Analytics Automation',
		];
		$req_args = array_merge( $defaults, $args );

		$version = new CreateContainerVersionRequestVersionOptions( $req_args );
		return $version;
	}

	/**
	 * Enables built-in GTM variables in a given workspace.
	 *
	 * @param string $workspace_id The workspace ID.
	 * @param array  $args         List of built-in variables to enable.
	 *
	 * @return bool True if successful, false otherwise.
	 */
	private function enable_built_in_variables( $workspace_id, $args = [] ) {
		if ( ! $this->all_non_null( [ $this->account_id, $this->container_id, $workspace_id ] ) || ! is_array( $args ) || ! isset( $args['variables'] ) || 1 > count( $args['variables'] ) ) {
			return false;
		}

		$success = true;
		$path = $this->build_path( [ [ 'workspaces', $workspace_id ] ] );
		$service = new GSTM( $this->client );

		try {
			foreach ( $args['variables'] as $variable ) {
				$built_in = $service->accounts_containers_workspaces_built_in_variables->create( $path, [ 'type' => $variable ] );
			}
		} catch ( Google_Exception $e ) {
			$success = false;
		}

		return $success;
	}

	/**
	 * Retrieves the GTM container information.
	 *
	 * @param array $args Optional arguments.
	 *
	 * @return mixed The GTM container object or false on failure.
	 */
	private function get_container( $args = [] ) {
		if ( ! $this->all_non_null( [ $this->account_id, $this->container_id ] ) ) {
			return false;
		}

		$path = $this->build_path();
		$service = new GSTM( $this->client );
		$container = $service->accounts_containers->get( $path );
		return $container;
	}

	/**
	 * Retrieves a GTM workspace by ID or name.
	 *
	 * @param array $args Optional arguments to specify workspace ID or name.
	 *
	 * @return mixed The GTM workspace object or false on failure.
	 */
	private function get_workspace( $args = [] ) {
		if ( ! $this->all_non_null( [ $this->account_id, $this->container_id ] ) || ! is_array( $args ) ) {
			return false;
		}

		$id = isset( $args['id'] ) ? $args['id'] : null;
		$name = isset( $args['name'] ) ? $args['name'] : 'Default Workspace';
		$path = $this->build_path( $id ? [ [ 'workspaces', $id ] ] : [] );
		$service = new GSTM( $this->client );
		if ( ! $id ) {
			$workspaces = $service->accounts_containers_workspaces->listAccountsContainersWorkspaces( $path );
			foreach ( $workspaces as $workspace ) {
				if ( $name === $workspace->getName() ) {
					return $workspace;
				}
			}
		} else {
			$workspace = $service->accounts_containers_workspaces->get( $path );
			return $workspace;
		}

		return false;
	}

	/**
	 * Creates and publishes a new GTM workspace version.
	 *
	 * @param string $workspace_id The workspace ID.
	 * @param array  $args         Optional arguments for version settings.
	 *
	 * @return bool True if the version was created and published successfully, false otherwise.
	 */
	private function create_new_workspace_version( $workspace_id, $args = [] ) {
		if ( ! $this->all_non_null( [ $this->account_id, $this->container_id, $workspace_id ] ) ) {
			return false;
		}

		$success = true;
		$path = $this->build_path( [ [ 'workspaces', $workspace_id ] ] );
		$service = new GSTM( $this->client );

		try {
			$new_workspace_version = $this->workspace_version_schema( $args );
			$version = $service->accounts_containers_workspaces->create_version( $path, $new_workspace_version );
			$container_version = $version?->getContainerVersion();
			if ( isset( $container_version['containerVersionId'] ) ) {
				$version_path = $this->build_path( [ [ 'versions', $container_version['containerVersionId'] ] ] );
				$publish = $service->accounts_containers_versions->publish( $version_path );
			}
		} catch ( Google_Exception $e ) {
			$success = false;
		}

		return $success;
	}

	/**
	 * Creates GTM tags within a workspace.
	 *
	 * @param string $workspace_id The workspace ID.
	 * @param array  $args         List of tags to create.
	 *
	 * @return array An array of created tag IDs.
	 */
	private function create_tags( $workspace_id, $args = [] ) {
		if ( ! $this->all_non_null( [ $this->account_id, $this->container_id, $workspace_id ] ) || ! is_array( $args ) || ! isset( $args['tags'] ) ) {
			return false;
		}

		$tag_ids = [];
		foreach ( $args['tags'] as $tag ) {
			if ( is_array( $tag ) && isset( $tag['name'] ) ) {
				$tag_ids[ $tag['name'] ] = false;
			}
		}

		$path = $this->build_path( [ [ 'workspaces', $workspace_id ] ] );
		$service = new GSTM( $this->client );

		$tags = $service->accounts_containers_workspaces_tags->listAccountsContainersWorkspacesTags( $path );
		if ( 0 < count( $tags ) ) {
			foreach ( $tags as $tag ) {
				$name = $tag?->getName();
				if ( isset( $tag_ids[ $name ] ) ) {
					$tag_ids[ $name ] = $tag?->getTagId();
				}
			}
		}

		foreach ( $args['tags'] as $tag_data ) {
			if ( isset( $tag_ids[ $tag_data['name'] ] ) && false === $tag_ids[ $tag_data['name'] ] ) {
				$new_tag = $this->tag_schema( $tag_data );
				$tag = $service->accounts_containers_workspaces_tags->create( $path, $new_tag );
				$tag_ids[ $tag_data['name'] ] = $tag?->getTagId();
			}
		}

		return $tag_ids;
	}

	/**
	 * Creates GTM triggers within a workspace.
	 *
	 * @param string $workspace_id The workspace ID.
	 * @param array  $args         List of triggers to create.
	 *
	 * @return array An array of created trigger IDs.
	 */
	private function create_triggers( $workspace_id, $args = [] ) {
		if ( ! $this->all_non_null( [ $this->account_id, $this->container_id, $workspace_id ] ) || ! is_array( $args ) || ! isset( $args['triggers'] ) ) {
			return false;
		}

		$trigger_ids = [];
		foreach ( $args['triggers'] as $trigger ) {
			if ( is_array( $trigger ) && isset( $trigger['name'] ) ) {
				$trigger_ids[ $trigger['name'] ] = false;
			}
		}

		$path = $this->build_path( [ [ 'workspaces', $workspace_id ] ] );
		$service = new GSTM( $this->client );

		$triggers = $service->accounts_containers_workspaces_triggers->listAccountsContainersWorkspacesTriggers( $path );
		if ( 0 < count( $triggers ) ) {
			foreach ( $triggers as $trigger ) {
				$name = $trigger?->getName();
				if ( isset( $trigger_ids[ $name ] ) ) {
					$trigger_ids[ $name ] = $trigger?->getTriggerId();
				}
			}
		}

		foreach ( $args['triggers'] as $trigger_data ) {
			if ( isset( $trigger_ids[ $trigger_data['name'] ] ) && false === $trigger_ids[ $trigger_data['name'] ] ) {
				$new_trigger = $this->trigger_schema( $trigger_data );
				$trigger = $service->accounts_containers_workspaces_triggers->create( $path, $new_trigger );
				$trigger_ids[ $trigger_data['name'] ] = $trigger?->getTriggerId();
			}
		}

		return $trigger_ids;
	}

	/**
	 * Creates GTM variables within a workspace.
	 *
	 * @param string $workspace_id The workspace ID.
	 * @param array  $args         List of variables to create.
	 *
	 * @return array An array of created variable IDs.
	 */
	private function create_variables( $workspace_id, $args = [] ) {
		if ( ! $this->all_non_null( [ $this->account_id, $this->container_id, $workspace_id ] ) || ! is_array( $args ) || ! isset( $args['variables'] ) ) {
			return false;
		}

		$variable_ids = [];
		foreach ( $args['variables'] as $variable ) {
			if ( is_array( $variable ) && isset( $variable['name'] ) ) {
				$variable_ids[ $variable['name'] ] = false;
			}
		}

		$path = $this->build_path( [ [ 'workspaces', $workspace_id ] ] );
		$service = new GSTM( $this->client );

		$variables = $service->accounts_containers_workspaces_variables->listAccountsContainersWorkspacesVariables( $path );
		if ( 0 < count( $variables ) ) {
			foreach ( $variables as $variable ) {
				$name = $variable?->getName();
				if ( isset( $variable_ids[ $name ] ) ) {
					$variable_ids[ $name ] = $variable?->getVariableId();
				}
			}
		}

		foreach ( $args['variables'] as $variable_data ) {
			if ( isset( $variable_ids[ $variable_data['name'] ] ) && false === $variable_ids[ $variable_data['name'] ] ) {
				$new_variable = $this->variable_schema( $variable_data );
				$variable = $service->accounts_containers_workspaces_variables->create( $path, $new_variable );
				$variable_ids[ $variable_data['name'] ] = $variable?->getVariableId();
			}
		}

		return $variable_ids;
	}

	/**
	 * Runs the GTM automation for a single form submission.
	 *
	 * @param string $form_title The title of the form.
	 * @param array  $args       Optional arguments.
	 *
	 * @return array Report containing created triggers, tags, and version updates.
	 */
	public function run_single_form( $form_title, $args = [] ) {
		$report = [
			'triggers'  => null,
			'tags'      => null,
			'version'   => null,
		];

		$workspace = $this->get_workspace();
		$workspace_id = $workspace?->getWorkspaceId();
		if ( $workspace_id ) {
			$form_trigger = $this->build_form_trigger_template( $form_title );
			$trigger_ids = $this->create_triggers(
				$workspace_id,
				[
					'triggers'  => $form_trigger,
				]
			);
			$report['triggers'] = $trigger_ids;

			$triggers = [];
			foreach ( $trigger_ids as $trigger ) {
				$triggers[] = $trigger;
			}

			$form_tag = $this->build_form_tag_template( $form_title, $triggers );
			$tag_ids = $this->create_tags(
				$workspace_id,
				[
					'tags'  => $form_tag,
				]
			);
			$report['tags'] = $tag_ids;

			$version_updated = $this->create_new_workspace_version( $workspace_id );
			$report['version'] = $version_updated;
		}

		return $report;
	}

	/**
	 * Runs the default GTM automation setup.
	 *
	 * @param array $args Optional arguments to configure automation.
	 *
	 * @return array Report containing built-in variables, created variables, triggers, tags, and version updates.
	 */
	public function run_default( $args = [] ) {
		$report = [
			'built_ins' => null,
			'variables' => null,
			'triggers'  => null,
			'tags'      => null,
			'version'   => null,
		];
		if ( isset( $args['get_public_id'] ) && true === $args['get_public_id'] ) {
			$container = $this->get_container();
			$report['public_id'] = $container?->getPublicId();
		}

		$workspace = $this->get_workspace();
		$workspace_id = $workspace?->getWorkspaceId();
		if ( $workspace_id ) {
			$built_ins = $this->enable_built_in_variables(
				$workspace_id,
				[
					'variables' => [ 'clickUrl' ],
				]
			);
			$report['built_ins'] = $built_ins;

			$variable_ids = $this->create_variables(
				$workspace_id,
				[
					'variables' => $this->default_variable_templates( $args ),
				]
			);
			$report['variables'] = $variable_ids;

			$trigger_ids = $this->create_triggers(
				$workspace_id,
				[
					'triggers'  => $this->default_trigger_templates( $args ),
				]
			);
			$report['triggers'] = $trigger_ids;

			$tags_with_triggers = $this->default_tags_with_triggers( $trigger_ids, $args );
			$tag_ids = $this->create_tags(
				$workspace_id,
				[
					'tags'  => $tags_with_triggers,
				]
			);
			$report['tags'] = $tag_ids;

			$version_updated = $this->create_new_workspace_version( $workspace_id );
			$report['version'] = $version_updated;
		}

		return $report;
	}
}
