<?php
/**
 * BackgroundComponentParallaxItem::component()
 *
 * @package Divi
 * @since ??
 */

namespace ET\Builder\Packages\Module\Options\Background\BackgroundComponentParallaxItemTraits;

if ( ! defined( 'ABSPATH' ) ) {
	die( 'Direct access forbidden.' );
}

use ET\Builder\Framework\Utility\HTMLUtility;
use ET\Builder\Packages\Module\Options\Background\BackgroundClassnames;
use ET\Builder\Framework\Utility\TextTransform;
use ET\Builder\Packages\GlobalData\GlobalData;

trait ComponentTrait {

	/**
	 * Get parallax background classname based on given breakpoint + state.
	 *
	 * This function is equivalent of JS function BackgroundComponentParallaxItem located in
	 * visual-builder/packages/module/src/options/background/components/parallax-item/utils/get-parallax-classname/index.ts.
	 *
	 * @since ??
	 *
	 * @param string $breakpoint Breakpoint name.
	 * @param string $state State name.
	 *
	 * @return string
	 */
	/**
	 * Get the parallax classname based on the breakpoint and state.
	 *
	 * The parallax classname is generated by combining the breakpoint and state parameters.
	 * The generated classname is used to apply parallax effects to elements on the page.
	 *
	 * @since ??
	 *
	 * @param string $breakpoint The breakpoint value. One of `desktop`, `tablet`, or `phone`.
	 * @param string $state      The state value. One of `active`, `hover`, `disabled`, or `value`.
	 *
	 * @return string The parallax classname.
	 *
	 * @example:
	 * ```php
	 * $classname = ClassName::get_parallax_classname( 'tablet', 'active' );
	 * ```
	 *
	 * @example:
	 * ```php
	 * // Generate parallax classnames for different elements within a module.
	 * $classname1 = ClassName::get_parallax_classname( 'desktop', 'hover' );
	 * $classname2 = ClassName::get_parallax_classname( 'tablet', 'active' );
	 * ```

	 * @example:
	 * ```php
	 * // Generate parallax classnames for different modules.
	 * $classname3 = ModuleClass::get_parallax_classname( 'desktop', 'value' );
	 * $classname4 = ModuleClass::get_parallax_classname( 'tablet', 'disabled' );
	 * ```
	 */
	public static function get_parallax_classname( string $breakpoint, string $state ) {
		$breakpoint_suffix = 'desktop' === $breakpoint ? '' : "_{$breakpoint}";
		$state_suffix      = 'value' === $state ? '' : "__{$state}";

		// The root classname for css parallax in D4 is `et_parallax_bg`. Since D4 scripts is still
		// enqueued and automatically implement itself on this classname on page load, using the same classname create
		// possible cause of conflict. Thus it is being renamed into `et-ph-parallax-background`.
		// See: https://elegantthemes.slack.com/archives/C01CW343ZJ9/p1667488870252499 .
		return "et-pb-parallax-background{$breakpoint_suffix}{$state_suffix}";
	}

	/**
	 * Get the classname for the parallax gradient based on the given breakpoint and state.
	 *
	 * The classname is generated by concatenating the breakpoint suffix and the state suffix.
	 * If the breakpoint is 'desktop', the breakpoint suffix is an empty string, otherwise it is "_{$breakpoint}".
	 * If the state is 'value', the state suffix is an empty string, otherwise it is "__{$state}".
	 *
	 * @since ??
	 *
	 * @param string $breakpoint The breakpoint value. One of `desktop`, `tablet`, or `phone`.
	 * @param string $state      The state value. One of `active`, `hover`, `disabled`, or `value`.
	 *
	 * @return string The generated parallax gradient classname.
	 *
	 * @example:
	 * ```php
	 * $breakpoint = 'tablet';
	 * $state = 'hover';
	 * $classname = get_parallax_gradient_classname( $breakpoint, $state );
	 *
	 * // Returns 'et_parallax_gradient_tablet__hover'
	 * ```
	 *
	 * @example:
	 * ```php
	 * $breakpoint = 'desktop';
	 * $state = 'value';
	 * $classname = get_parallax_gradient_classname( $breakpoint, $state );
	 *
	 * // Returns 'et_parallax_gradient'
	 * ```
	 */
	public static function get_parallax_gradient_classname( string $breakpoint, string $state ): string {
		$breakpoint_suffix = 'desktop' === $breakpoint ? '' : "_{$breakpoint}";
		$state_suffix      = 'value' === $state ? '' : "__{$state}";

		return "et_parallax_gradient{$breakpoint_suffix}{$state_suffix}";
	}

	/**
	 * ParallaxItem background element.
	 *
	 * This function takes an array of arguments and returns a HTML `span` tag with specified class
	 * and attributes for creating a parallax effect on a background.
	 *
	 * The function generates a parallax name by concatenating the module name and a transformed version of the module ID.
	 * It also generates parallax class names and a unique class name based on the breakpoint and state values.
	 * The function then uses the HTMLUtility class to render the HTML markup for the parallax background element.
	 *
	 * @since ??
	 *
	 * @param array $args {
	 *     An array of arguments.
	 *
	 *     @type string   $breakpoint            Optional. Current breakpoint. Default `null`.
	 *     @type bool     $cssParallax           Optional. Whether parallax is enabled. Default `null`.
	 *     @type array    $existClassNames       Optional. Classnames that are already present. Default `null`.
	 *     @type string   $name                  Optional. Name used for parallax class. Default `module`.
	 *     @type string   $moduleId              Optional. Module ID used for parallax class. Default `null`.
	 *     @type string   $state                 Optional. Current state. Default `null`.
	 *     @type string   $url                   Optional. Background image URL. Default `null`.
	 *     @type string   $blend                 Optional. Blend mix mode. Default `null`.
	 *     @type array    $gradientClassNames    Optional. List of gradient classnames. Default `null`.
	 *     @type bool     $gradientOverlaysImage Optional. Whether the gradient should overlay the image. Default `null`.
	 *     @type string   $gradientCSS           Optional. CSS rules for gradient. Default `null`.
	 * }
	 *
	 * @return string The HTML markup for the parallax background element.
	 */
	public static function component( array $args ): string {
		$args = wp_parse_args(
			$args,
			[
				'breakpoint'                  => null,
				'cssParallax'                 => null,
				'existClassNames'             => null,
				'name'                        => 'module',
				'moduleId'                    => null,
				'state'                       => null,
				'url'                         => null,
				'blend'                       => null,
				'color'                       => null,
				'gradientClassNames'          => null,
				'gradientOverlaysImage'       => null,
				'gradientCSS'                 => null,
				'responsiveVisibilityClasses' => [],
			]
		);

		$name                          = $args['name'];
		$module_id                     = $args['moduleId'];
		$breakpoint                    = $args['breakpoint'];
		$css_parallax                  = $args['cssParallax'];
		$exist_class_names             = ! empty( $args['existClassNames'] ) ? $args['existClassNames'] : [];
		$state                         = $args['state'];
		$url                           = $args['url'];
		$blend                         = $args['blend'];
		$color                         = $args['color'];
		$gradient_class_names          = $args['gradientClassNames'];
		$gradient_overlays_image       = $args['gradientOverlaysImage'];
		$gradient_css                  = $args['gradientCSS'];
		$responsive_visibility_classes = $args['responsiveVisibilityClasses'];

		// Resolve global color variable to CSS-compatible value for inline styles.
		if ( isset( $color ) && '' !== $color ) {
			$color = GlobalData::resolve_global_color_variable(
				$color,
				GlobalData::get_global_colors()
			);
		}

		// Generate parallax name. Traditionally, parallax is part of background options and only being used
		// as module's background only. This parallax name anticipates the case of parallax being
		// used on various elements inside a module.
		$parallax_name = "{$name}--" . TextTransform::param_case( $module_id );

		// Generate parallax classnames.
		$parallax_class_name          = self::get_parallax_classname( $breakpoint, $state );
		$parallax_gradient_class_name = self::get_parallax_gradient_classname( $breakpoint, $state );

		// Generate parallax unique classname that will be used as selector.
		// Combination of breakpoint and state aware parallax classname + parallax name, ensure unique
		// Selector name for this selector.
		$parallax_unique_class_name = "{$parallax_class_name}-{$parallax_name}";

		$children = HTMLUtility::render(
			[
				'tag'        => 'span',
				'attributes' => [
					'class' => HTMLUtility::classnames(
						array_merge(
							[
								'et-pb-parallax-background' => true,
								'et-pb-parallax-background--css' => $css_parallax,
								$parallax_class_name => true,
								$parallax_unique_class_name => true,
							],
							$exist_class_names,
							[ BackgroundClassnames::get_background_parallax_exist_classnames( $breakpoint, $state ) => false ]
						)
					),
					'style' => array_merge(
						[
							'background-image' => ( isset( $gradient_css ) && '' !== $gradient_css && isset( $blend ) && '' !== $blend && 'normal' !== $blend )
								? ( $gradient_overlays_image
									? sprintf( '%1$s, url(%2$s)', esc_attr( $gradient_css ), esc_url( $url ) )
									: sprintf( 'url(%1$s), %2$s', esc_url( $url ), esc_attr( $gradient_css ) ) )
								: sprintf( 'url(%1$s)', esc_url( $url ) ),
						],
						( isset( $color ) && '' !== $color && isset( $blend ) && '' !== $blend && 'normal' !== $blend ) ? [
							'background-color' => esc_attr( ( isset( $gradient_css ) && '' !== $gradient_css ) ? 'initial' : $color ),
						] : [],
						( isset( $blend ) && '' !== $blend && 'normal' !== $blend ) ? [
							'background-blend-mode' => esc_attr( $blend ),
						] : []
					),
				],
			]
		);

		// Skip overlay span when blend is active; gradient already lives in the base background-image.
		// This follows the same logic when parallax is not enabled, gradient and image are blended even when gradient is placed above image.
		if ( $gradient_overlays_image && ( ! isset( $blend ) || 'normal' === $blend ) ) {
			$children .= HTMLUtility::render(
				[
					'tag'        => 'span',
					'attributes' => [
						'class' => HTMLUtility::classnames(
							array_merge(
								[
									'et_parallax_gradient' => true,
									$parallax_gradient_class_name => true,
									'et_pb_parallax_css'   => $css_parallax,
								],
								$gradient_class_names,
								[ BackgroundClassnames::get_background_parallax_exist_classnames( $breakpoint, $state, $gradient_overlays_image ) => false ]
							)
						),
						'style' => [
							'background-image' => esc_attr( $gradient_css ),
						],
					],
				]
			);
		}

		$wrapper_classes = array_merge(
			[ 'et-pb-parallax-wrapper' ],
			$responsive_visibility_classes
		);

		return HTMLUtility::render(
			[
				'tag'               => 'span',
				'attributes'        => [
					'class' => HTMLUtility::classnames( $wrapper_classes ),
				],
				'children'          => $children,
				'childrenSanitizer' => 'et_core_esc_previously',
			]
		);
	}
}
