<?php
/**
 * Media Player element.
 *
 * @package BricksExtras
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

require_once BRICKSEXTRAS_PATH . 'components/traits/media-player-trait.php';

use BricksExtras\Components\Traits\Media_Player_Trait;

/**
 * Media Player element class.
 */
class X_Media_Player extends \Bricks\Element {

	use Media_Player_Trait;

	/**
	 * Element category.
	 *
	 * @var string
	 */
	public $category = 'extras';
	/**
	 * Element name.
	 *
	 * @var string
	 */
	public $name = 'xmediaplayer';
	/**
	 * Element icon.
	 *
	 * @var string
	 */
	public $icon = 'ti-video-camera';
	/**
	 * Required scripts.
	 *
	 * @var array
	 */
	public $scripts = array(
		'xMediaPlayerTooltips',
		'xDoMediaPlayer',
	);
	/**
	 * Loop index.
	 *
	 * @var int
	 */
	public $loop_index = 0;
	/**
	 * Element is nestable.
	 *
	 * @var bool
	 */
	public $nestable = true;
	/**
	 * Control fields array.
	 *
	 * @var array
	 */
	public $control_fields = array();


	/**
	 * Get element label.
	 */
	public function get_label() {
		return esc_html__( 'Media Player', 'bricksextras' );
	}

	/**
	 * Get element keywords.
	 */
	public function get_keywords() {
		return array( 'video', 'audio', 'media', 'player', 'controls' );
	}


	/**
	 * Set control groups.
	 */
	public function set_control_groups() {

		// Main UI Type selection - should be at the top.
		$this->control_groups['controls'] = array(
			'title' => esc_html__( 'Player UI Type', 'bricksextras' ),
		);

		// Customize UI options - placed immediately after UI Type selection.
		$this->control_groups['controlsSmall'] = array(
			'title'     => esc_html__( 'Customize UI', 'bricksextras' ),
			'clearable' => false,
			'required'  => array(
				array( 'layoutType', '!=', array( 'custom', 'type_two' ) ),
			),
		);

		$this->control_groups['controlsLarge'] = array(
			'title'     => esc_html__( 'Customize UI', 'bricksextras' ),
			'clearable' => false,
			'required'  => array(
				array( 'layoutType', '=', array( 'type_two' ) ),
			),
		);

		$this->control_groups['poster'] = array(
			'title'    => esc_html__( 'Poster image', 'bricks' ),
			'required' => array( 'playlistMode', '!=', true ),
		);

		$this->control_groups['styleGeneral'] = array(
			'title' => esc_html__( 'Styles', 'bricks' ) . ' (' . esc_html__( 'General', 'bricks' ) . ')',
		);

		$this->control_groups['styleControls'] = array(
			'title' => esc_html__( 'Styles', 'bricks' ) . ' (' . esc_html__( 'Controls', 'bricks' ) . ')',
		);

		$this->control_groups['behaviour'] = array(
			'title' => esc_html__( 'Config', 'bricksextras' ) . ' / ' . esc_html__( 'Behavior', 'bricks' ),
			array( 'layoutType', '!=', 'custom' ),
		);

		// Tooltips group.
		$this->control_groups['tooltips'] = array(
			'title' => esc_html__( 'Tooltips', 'bricksextras' ),
		);

		// Notice Overlay - related to UI but less frequently used.
		$this->control_groups['noticeOverlay'] = array(
			'title'    => esc_html__( 'Overlay', 'bricks' ) . ' (' . esc_html__( 'Notice', 'bricks' ) . ')',
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
			),
		);

		// Text tracks group.
		$this->control_groups['textTracks'] = array(
			'title'    => esc_html__( 'Text Tracks', 'bricksextras' ),
			'required' => array( 'playlistMode', '!=', true ),
		);

		// Chapters group.
		$this->control_groups['chapters'] = array(
			'title'    => esc_html__( 'Chapters', 'bricksextras' ),
			'required' => array( 'playlistMode', '!=', true ),
		);

		// Keyboard Shortcuts group.
		$this->control_groups['keyboardShortcuts'] = array(
			'title' => esc_html__( 'Keyboard shortcuts', 'bricks' ),
		);

		// Playlists group.
		$this->control_groups['playLists'] = array(
			'title' => esc_html__( 'Playlists', 'bricksextras' ),
		);
	}

	/**
	 * Set element controls.
	 */
	public function set_controls() {

		$this->set_common_controls();

		// Set video-specific background and border selectors.
		if ( isset( $this->controls['_background'] ) ) {
			$this->controls['_background']['css'][1]['selector'] = '&[data-x-view-type=video]';
		}
		if ( isset( $this->controls['_border'] ) ) {
			$this->controls['_border']['css'][1]['selector'] = '&[data-x-view-type=video]';
		}

		$this->controls['_background']['css'][0]['selector'] = '&[data-x-view-type=video] media-provider';
		$this->controls['_border']['css'][0]['selector']     = '&[data-x-view-type=video] media-provider';

		$this->controls['_justifyContent']['css'][0]['selector'] = '.xmp-controls';
		$this->controls['_alignItems']['css'][0]['selector']     = '.xmp-controls';
		$this->controls['_gap']['css'][0]['selector']            = '.xmp-controls';
		$this->controls['_flexDirection']['css'][0]['selector']  = '.xmp-controls';

		/* shared media player controls */
		$shared_vars       = $this->get_media_player_shared_variables();
		$active_controls   = $shared_vars['activeControls'];
		$inactive_controls = $shared_vars['inactiveControls'];
		$placement_options = $shared_vars['placementOptions'];
		$option_controls   = $shared_vars['optionControls'];
		$control_fields    = $shared_vars['controlFields'];

		// Make sure $control_fields is defined as a class property so it's available throughout the class.
		$this->control_fields = $control_fields;

		$this->controls = array_merge( $this->controls, $this->get_media_player_controls( 'video' ) );

		$small_requirement = array(
			array( 'layoutType', '!=', 'custom' ),
			array( 'layoutType', '!=', 'type_two' ),
		);

		$large_requirement = array(
			array( 'layoutType', '!=', 'custom' ),
			array( 'layoutType', '!=', 'type_one' ),
		);

		$this->controls['aspectRatio'] = array(
			'label'          => esc_html__( 'Aspect ratio', 'bricks' ),
			'type'           => 'text',
			'placeholder'    => '16/9',
			'inline'         => true,
			'info'           => 'x/y',
			'hasDynamicData' => false,
			'small'          => true,
			'css'            => array(
				array(
					'property' => 'aspect-ratio',
					'selector' => '&[data-x-view-type=video]',
				),
				array(
					'property' => 'aspect-ratio',
					'selector' => '&[data-x-view-type=video] video',
				),
			),
		);

		$this->controls['controlsTopSep'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Top controls', 'bricksextras' ),
			'description' => esc_html__( 'Manage controls for this zone', 'bricksextras' ),
			'type'        => 'separator',
			'group'       => 'controlsLarge',
			'required'    => $large_requirement,
		);

		$this->controls['controlsTop'] = array(
			'group'         => 'controlsLarge',
			'placeholder'   => esc_html__( 'Control', 'bricksextras' ),
			'titleProperty' => 'control',
			'type'          => 'repeater',
			'required'      => $large_requirement,
			'fields'        => $this->control_fields,
			'default'       => array(
				array( 'control' => 'title' ),
				array( 'control' => 'spacer' ),
			),
		);

		$this->controls['controlsTopVisibility'] = array(
			'tab'         => 'content',
			'type'        => 'select',
			'options'     => array(
				'loaded' => esc_html__( 'Video loaded', 'bricksextras' ),
				'play'   => esc_html__( 'Video played', 'bricksextras' ),
			),
			'placeholder' => '',
			'group'       => 'controlsLarge',
			'label'       => esc_html__( 'Hide until..', 'bricksextras' ),
			'inline'      => true,
			'required'    => $large_requirement,
		);

		$this->controls['controlGapTop'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'controlsLarge',
			'label'    => esc_html__( 'Gap', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-button-gap',
					'selector' => '.xmp-controls_group_top',
				),
			),
			'required' => $large_requirement,
		);

		$this->controls['controlsCenterSep'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Center controls', 'bricksextras' ),
			'description' => esc_html__( 'Manage controls for this zone', 'bricksextras' ),
			'type'        => 'separator',
			'group'       => 'controlsLarge',
			'required'    => $large_requirement,
		);

		$this->controls['controlsCenter'] = array(
			'group'         => 'controlsLarge',
			'placeholder'   => esc_html__( 'Control', 'bricksextras' ),
			'titleProperty' => 'control',
			'type'          => 'repeater',
			'required'      => $large_requirement,
			'fields'        => $this->control_fields,
			'default'       => array(),
		);

		$this->controls['controlsCenterVisibility'] = array(
			'tab'         => 'content',
			'type'        => 'select',
			'options'     => array(
				'loaded' => esc_html__( 'Video loaded', 'bricksextras' ),
				'play'   => esc_html__( 'Video played', 'bricksextras' ),
			),
			'placeholder' => '',
			'group'       => 'controlsLarge',
			'label'       => esc_html__( 'Hide until..', 'bricksextras' ),
			'inline'      => true,
			'required'    => $large_requirement,
		);

		$this->controls['controlGapCenter'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'controlsLarge',
			'label'    => esc_html__( 'Gap', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-button-gap',
					'selector' => '.xmp-controls_group_center',
				),
			),
			'required' => $large_requirement,
		);

		$this->controls['controlsSep'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Bottom controls', 'bricksextras' ),
			'description' => esc_html__( 'Manage controls for this zone', 'bricksextras' ),
			'type'        => 'separator',
			'group'       => 'controlsLarge',
			'required'    => $large_requirement,
		);

		$this->controls['controls'] = array(
			'group'         => 'controlsLarge',
			'placeholder'   => esc_html__( 'Control', 'bricksextras' ),
			'titleProperty' => 'control',
			'type'          => 'repeater',
			'required'      => $large_requirement,
			'fields'        => $this->control_fields,
			'default'       => array(
				array( 'control' => 'play' ),
				array( 'control' => 'mute' ),
				array( 'control' => 'time' ),
				array( 'control' => 'spacer' ),
				array( 'control' => 'captions' ),
				array( 'control' => 'chapters' ),
				array( 'control' => 'fullscreen' ),
				array( 'control' => 'settings' ),
			),
		);

		$this->controls['controlsBottomVisibility'] = array(
			'tab'         => 'content',
			'type'        => 'select',
			'options'     => array(
				'loaded' => esc_html__( 'Video loaded', 'bricksextras' ),
				'play'   => esc_html__( 'Video played', 'bricksextras' ),
			),
			'placeholder' => '',
			'group'       => 'controlsLarge',
			'label'       => esc_html__( 'Hide until..', 'bricksextras' ),
			'inline'      => true,
			'required'    => $large_requirement,
		);

		$this->controls['controlGapBottom'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'controlsLarge',
			'label'    => esc_html__( 'Gap', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-button-gap',
					'selector' => '.xmp-controls_group_bottom',
				),
			),
			'required' => $large_requirement,
		);

		$this->controls['maybeTimeSlider'] = array(
			'group'       => 'controlsLarge',
			'label'       => esc_html__( 'Time slider', 'bricksextras' ) . ' (' . esc_html__( 'Full width', 'bricksextras' ) . ')',
			'type'        => 'select',
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Enable', 'bricks' ),
			'inline'      => true,
			'required'    => $large_requirement,
			'info'        => esc_html__( 'Position above bottom controls', 'bricksextras' ),
		);

		/* small ui */

		$this->controls['smallControlsSep'] = array(
			'group'       => 'controls',
			'label'       => esc_html__( 'UI type', 'bricksextras' ),
			'description' => esc_html__( 'Choose the starting layout for the player', 'bricksextras' ),
			'type'        => 'separator',
		);

		$this->controls['layoutType'] = array(
			'group'       => 'controls',
			'label'       => esc_html__( 'UI type', 'bricksextras' ),
			'inline'      => true,
			'type'        => 'select',
			'options'     => array(
				'type_one' => esc_html__( 'Type 1', 'bricksextras' ),
				'type_two' => esc_html__( 'Type 2', 'bricksextras' ),
				'custom'   => esc_html__( 'Custom', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Type 1', 'bricksextras' ),
		);

		$this->controls['controlsAdvancedSep'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Custom UI', 'bricksextras' ),
			'description' => esc_html__( 'All default UI is removed, add a block element inside the media player for the layout. Add "media controls" element inside block to build custom UI. The style settings below can still be used to style the controls globally for the player', 'bricksextras' ),
			'type'        => 'separator',
			'group'       => 'controls',
			'required'    => array( 'layoutType', '=', 'custom' ),
		);

		/* controls small */

		$this->controls['smallControlsTopSep'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Top controls', 'bricksextras' ),
			'description' => esc_html__( 'Manage controls for this zone', 'bricksextras' ),
			'type'        => 'separator',
			'group'       => 'controlsSmall',
			'required'    => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'layoutType', '!=', 'type_two' ),
			),
		);

		$this->controls['smallControlsTop'] = array(
			'group'         => 'controlsSmall',
			'label'         => esc_html__( 'Controls', 'bricks' ),
			'placeholder'   => esc_html__( 'Controls', 'bricks' ),
			'titleProperty' => 'control',
			'type'          => 'repeater',
			'required'      => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'layoutType', '!=', 'type_two' ),
			),
			'fields'        => $this->control_fields,
			'default'       => array(
				array( 'control' => 'mute' ),
				array( 'control' => 'spacer' ),
				array( 'control' => 'captions' ),
				array( 'control' => 'chapters' ),
				array( 'control' => 'fullscreen' ),
				array( 'control' => 'settings' ),
			),
		);

		$this->controls['smallcontrolsTopVisibility'] = array(
			'tab'         => 'content',
			'type'        => 'select',
			'options'     => array(
				'loaded' => esc_html__( 'Video loaded', 'bricksextras' ),
				'play'   => esc_html__( 'Video played', 'bricksextras' ),
			),
			'placeholder' => '',
			'group'       => 'controlsSmall',
			'label'       => esc_html__( 'Hide until..', 'bricksextras' ),
			'inline'      => true,
			'required'    => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'layoutType', '!=', 'type_two' ),
			),
		);

		$this->controls['smallcontrolGapTop'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'controlsSmall',
			'label'    => esc_html__( 'Gap', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-button-gap',
					'selector' => '.xmp-layout_type-one .xmp-controls_group_top',
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
			),
		);

		$this->controls['smallcontrolsCenterSep'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Center controls', 'bricksextras' ),
			'description' => esc_html__( 'Manage controls for this zone', 'bricksextras' ),
			'type'        => 'separator',
			'group'       => 'controlsSmall',
			'required'    => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'layoutType', '!=', 'type_two' ),
			),
		);

		$this->controls['smallcontrolsCenter'] = array(
			'group'         => 'controlsSmall',
			'placeholder'   => esc_html__( 'Control', 'bricksextras' ),
			'titleProperty' => 'control',
			'type'          => 'repeater',
			'required'      => $small_requirement,
			'fields'        => $this->control_fields,
			'default'       => array(
				array( 'control' => 'spacer' ),
				array( 'control' => 'play-large' ),
				array( 'control' => 'spacer' ),
			),
		);

		$this->controls['smallcontrolsCenterVisibility'] = array(
			'tab'         => 'content',
			'type'        => 'select',
			'options'     => array(
				'loaded' => esc_html__( 'Video loaded', 'bricksextras' ),
				'play'   => esc_html__( 'Video played', 'bricksextras' ),
			),
			'placeholder' => '',
			'group'       => 'controlsSmall',
			'label'       => esc_html__( 'Hide until..', 'bricksextras' ),
			'inline'      => true,
			'required'    => $small_requirement,
		);

		$this->controls['smallcontrolGapCenter'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'controlsSmall',
			'label'    => esc_html__( 'Gap', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-button-gap',
					'selector' => '.xmp-layout_type-one .xmp-controls_group_center',
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
			),
		);

		$this->controls['smallControlsBottomSep'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Bottom controls', 'bricksextras' ),
			'description' => esc_html__( 'Manage controls for this zone', 'bricksextras' ),
			'type'        => 'separator',
			'group'       => 'controlsSmall',
			'required'    => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'layoutType', '!=', 'type_two' ),
			),
		);

		$this->controls['smallControls'] = array(
			'group'         => 'controlsSmall',
			'label'         => esc_html__( 'Controls', 'bricks' ),
			'placeholder'   => esc_html__( 'Control', 'bricksextras' ),
			'titleProperty' => 'control',
			'type'          => 'repeater',
			'required'      => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'layoutType', '!=', 'type_two' ),
			),
			'fields'        => $this->control_fields,
			'default'       => array(
				array( 'control' => 'title' ),
			),
		);

		$this->controls['smallcontrolsBottomVisibility'] = array(
			'tab'         => 'content',
			'type'        => 'select',
			'options'     => array(
				'loaded' => esc_html__( 'Video loaded', 'bricksextras' ),
				'play'   => esc_html__( 'Video played', 'bricksextras' ),
			),
			'placeholder' => '',
			'group'       => 'controlsSmall',
			'label'       => esc_html__( 'Hide until..', 'bricksextras' ),
			'inline'      => true,
			'required'    => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'layoutType', '!=', 'type_two' ),
			),
		);

		$this->controls['smallcontrolGapBottom'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'controlsSmall',
			'label'    => esc_html__( 'Gap', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-button-gap',
					'selector' => '.xmp-layout_type-one .xmp-controls_group_bottom',
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
			),
		);

		$this->controls['maybeTimeSliderSmall'] = array(
			'group'       => 'controlsSmall',
			'label'       => esc_html__( 'Time slider', 'bricksextras' ) . ' (' . esc_html__( 'Full width', 'bricksextras' ) . ')',
			'type'        => 'select',
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Enable', 'bricks' ),
			'inline'      => true,
			'required'    => $small_requirement,
		);

		$this->controls['controlsVideoOpacity'] = array(
			'tab'         => 'content',
			'type'        => 'number',
			'step'        => 0.05,
			'group'       => 'styleGeneral',
			'label'       => esc_html__( 'Video opacity (when controls show)', 'bricksextras' ),
			'css'         => array(
				array(
					'property' => 'opacity',
					'selector' => '&[data-controls] media-provider',
				),
				array(
					'property' => 'opacity',
					'selector' => '&[data-buffering] media-provider',
				),
				array(
					'property' => 'opacity',
					'selector' => '&[data-paused] media-provider',
				),
			),
			'placeholder' => '.8',
		);

		/* Buffering Indicator */

		$buffering_indicator = '.xmp-buffering-indicator';

		$this->controls['bufferingIndicatorSep'] = array(
			'tab'   => 'content',
			'type'  => 'separator',
			'group' => 'styleGeneral',
			'label' => esc_html__( 'Spinner', 'bricks' ) . ' (' . esc_html__( 'Video buffering', 'bricksextras' ) . ')',
		);

		$this->controls['bufferingIndicatorDisplay'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Enable', 'bricks' ),
			'type'        => 'select',
			'group'       => 'styleGeneral',
			'options'     => array(
				'true'  => esc_html__( 'Enable', 'bricks' ),
				'false' => esc_html__( 'Disable', 'bricks' ),
			),
			'inline'      => true,
			'clearable'   => false,
			'placeholder' => esc_html__( 'Enable', 'bricks' ),
		);

		$this->controls['bufferingIndicatorDisplay'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Spinner', 'bricks' ) . ' (' . esc_html__( 'Video buffering', 'bricksextras' ) . ')',
			'type'        => 'select',
			'group'       => 'styleGeneral',
			'options'     => array(
				'true'  => esc_html__( 'Enable', 'bricks' ),
				'false' => esc_html__( 'Disable', 'bricks' ),
			),
			'inline'      => true,
			'clearable'   => false,
			'placeholder' => esc_html__( 'Enable', 'bricks' ),
		);

		$this->controls['bufferingIndicatorPreview'] = array(
			'tab'       => 'content',
			'label'     => esc_html__( 'Preview', 'bricks' ),
			'type'      => 'checkbox',
			'group'     => 'styleGeneral',
			'inline'    => true,
			'clearable' => false,
			'required'  => array( 'bufferingIndicatorDisplay', '!=', 'false' ),
		);

		$this->controls['bufferingIndicatorFillColor'] = array(
			'tab'      => 'content',
			'type'     => 'color',
			'group'    => 'styleGeneral',
			'label'    => esc_html__( 'Fill color', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-buffering-track-fill-color',
					'selector' => $buffering_indicator,
				),
			),
			'required' => array( 'bufferingIndicatorDisplay', '!=', 'false' ),
		);

		$this->controls['bufferingIndicatorTrackColor'] = array(
			'tab'      => 'content',
			'type'     => 'color',
			'group'    => 'styleGeneral',
			'label'    => esc_html__( 'Track color', 'bricks' ),
			'css'      => array(
				array(
					'property' => '--media-buffering-track-color',
					'selector' => $buffering_indicator,
				),
			),
			'required' => array( 'bufferingIndicatorDisplay', '!=', 'false' ),
		);

		$this->controls['bufferingIndicatorTrackWidth'] = array(
			'tab'         => 'content',
			'type'        => 'number',
			'units'       => true,
			'group'       => 'styleGeneral',
			'label'       => esc_html__( 'Width', 'bricks' ),
			'css'         => array(
				array(
					'property' => '--media-buffering-track-width',
					'selector' => $buffering_indicator,
				),
				array(
					'property' => '--media-buffering-track-fill-width',
					'selector' => $buffering_indicator,
				),
			),
			'required'    => array( 'bufferingIndicatorDisplay', '!=', 'false' ),
			'placeholder' => '2',
		);

		$this->controls['bufferingIndicatorSize'] = array(
			'tab'         => 'content',
			'type'        => 'number',
			'units'       => true,
			'group'       => 'styleGeneral',
			'label'       => esc_html__( 'Size', 'bricks' ),
			'css'         => array(
				array(
					'property' => '--media-buffering-size',
					'selector' => $buffering_indicator,
				),
			),
			'required'    => array( 'bufferingIndicatorDisplay', '!=', 'false' ),
			'placeholder' => '96px',
		);

		$this->controls['bufferingIndicatorTrackOpacity'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'group'    => 'styleGeneral',
			'label'    => esc_html__( 'Opacity', 'bricks' ) . ' (' . esc_html__( 'Track', 'bricks' ) . ')',
			'css'      => array(
				array(
					'property' => '--media-buffering-track-opacity',
					'selector' => $buffering_indicator,
				),
			),
			'required' => array( 'bufferingIndicatorDisplay', '!=', 'false' ),
		);

		$this->controls['bufferingIndicatorTrackFillOpacity'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'group'    => 'styleGeneral',
			'label'    => esc_html__( 'Opacity', 'bricks' ) . ' (' . esc_html__( 'Fill', 'bricks' ) . ')',
			'css'      => array(
				array(
					'property' => '--media-buffering-track-fill-opacity',
					'selector' => $buffering_indicator,
				),
			),
			'required' => array( 'bufferingIndicatorDisplay', '!=', 'false' ),
		);

		$this->controls['autoLocalPoster'] = array(
			'label'  => esc_html__( 'Save poster images locally', 'bricksextras' ),
			'type'   => 'checkbox',
			'inline' => true,
			'group'  => 'behaviour',
		);

		$this->controls['playsinline'] = array(
			'group'       => 'behaviour',
			'label'       => esc_html__( 'Playsinline', 'bricksextras' ),
			'type'        => 'select',
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Enable', 'bricks' ),
			'inline'      => true,
			'small'       => true,
			'rerender'    => false,
		);

		$this->controls['posterReshow'] = array(
			'group'    => 'behaviour',
			'label'    => esc_html__( 'Reshow poster image when paused', 'bricksextras' ),
			'type'     => 'checkbox',
			'inline'   => true,
			'small'    => true,
			'rerender' => false,
			'required' => array( 'providerControls', '!=', 'enable' ),
		);

		$this->controls['controlsDelay'] = array(
			'group'       => 'behaviour',
			'label'       => esc_html__( 'Delay', 'bricks' ) . ' (' . esc_html__( 'Hiding controls', 'bricksextras' ) . ')',
			'type'        => 'number',
			'description' => esc_html__( 'Set to -1 to never hide controls', 'bricksextras' ),
			'placeholder' => '2000',
			'inline'      => true,
			'small'       => true,
		);

		$this->controls['fullscreenFallback'] = array(
			'group'       => 'behaviour',
			'label'       => esc_html__( 'Fallback', 'bricks' ) . ' (' . esc_html__( 'Fullscreen', 'bricks' ) . ')',
			'info'        => esc_html__( 'For browsers not supporting fullscreen', 'bricksextras' ),
			'type'        => 'select',
			'options'     => array(
				'native'      => esc_html__( 'Use native fullscreen where available', 'bricksextras' ),
				'full_window' => esc_html__( 'Full window', 'bricksextras' ) . ' (Plyr)',
				'none'        => esc_html__( 'None', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Full window', 'bricksextras' ) . ' (Plyr)',
		);

		/* loading */

		$this->controls['loadingSep'] = array(
			'group'    => 'behaviour',
			'label'    => esc_html__( 'Loading media', 'bricksextras' ),
			'type'     => 'separator',
			'required' => array( 'providerControls', '!=', 'enable' ),
		);

		$this->controls['loadingType'] = array(
			'group'       => 'behaviour',
			'label'       => esc_html__( 'Media Loading', 'bricksextras' ),
			'type'        => 'select',
			'options'     => array(
				'visible' => esc_html__( 'When visible', 'bricksextras' ) . ' (' . esc_html__( 'Lazy load', 'bricksextras' ) . ')',
				'click'   => esc_html__( 'On click', 'bricksextras' ),
				'play'    => esc_html__( 'On play', 'bricksextras' ) . ' (' . esc_html__( "Fallback to 'on click' for iFrame providers", 'bricksextras' ) . ')',
				'custom'  => esc_html__( 'Custom', 'bricks' ) . ' (' . esc_html__( 'Interactions', 'bricks' ) . ')',
			),
			'placeholder' => esc_html__( 'When visible', 'bricksextras' ) . ' (' . esc_html__( 'Lazy load', 'bricksextras' ) . ')',
			'required'    => array( 'providerControls', '!=', 'enable' ),

		);

		$this->controls['loadingUISep'] = array(
			'group'    => 'behaviour',
			'label'    => esc_html__( 'Loading UI', 'bricksextras' ),
			'type'     => 'separator',
			'required' => array(
				array( 'layoutType', '!=', array( 'custom' ) ),
				array( 'providerControls', '!=', 'enable' ),
			),
		);

		$this->controls['loadingUI'] = array(
			'group'       => 'behaviour',
			'label'       => esc_html__( 'UI', 'bricksextras' ),
			'type'        => 'select',
			'options'     => array(
				'eager'   => esc_html__( 'Eager', 'bricks' ),
				'visible' => esc_html__( 'When visible (lazy)', 'bricksextras' ),
			),
			'inline'      => true,
			'placeholder' => esc_html__( 'When visible (lazy)', 'bricksextras' ),
			'required'    => array(
				array( 'layoutType', '!=', array( 'custom' ) ),
				array( 'providerControls', '!=', 'enable' ),
			),
		);

		$this->controls['securitySep'] = array(
			'tab'   => 'content',
			'label' => 'Bunny Stream',
			'group' => 'behaviour',

			'type'  => 'separator',
		);

		// Add security controls.
		$this->controls['enableSecurity'] = array(
			'tab'         => 'content',
			'group'       => 'behaviour',
			'label'       => esc_html__( 'Generate Authentication Tokens', 'bricksextras' ),
			'description' => esc_html__( 'Create expiring video URLs', 'bricksextras' ),
			'type'        => 'checkbox',
		);

		$this->controls['securityExpiry'] = array(
			'tab'         => 'content',
			'group'       => 'behaviour',
			'label'       => esc_html__( 'Token Expiry Time', 'bricksextras' ) . ' (s)',
			'type'        => 'number',
			'placeholder' => '3600 (1 hour)',
			'required'    => array(
				array( 'enableSecurity', '=', true ),
			),
		);

		$this->controls['autoCaptionsBunny'] = array(
			'tab'   => 'content',
			'group' => 'behaviour',
			/* translators: %s: Service name */
			'label' => sprintf( esc_html__( 'Populate captions from %s', 'bricksextras' ), 'Bunny Stream' ),
			'type'  => 'checkbox',
		);

		/* gestures */

		$this->controls['gestures'] = array(
			'tab'   => 'content',
			'label' => esc_html__( 'Gestures', 'bricksextras' ),
			'type'  => 'separator',
			'group' => 'behaviour',
		);

		$this->controls['clickToPlay'] = array(
			'label'       => esc_html__( 'Click to play', 'bricksextras' ),
			'type'        => 'select',
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Enable', 'bricks' ),
			'inline'      => true,
			'group'       => 'behaviour',
		);

		/* notice */

		$this->controls['maybeNotice'] = array(
			'group'       => 'noticeOverlay',
			'label'       => esc_html__( 'Enable', 'bricks' ),
			'type'        => 'select',
			'options'     => array(
				'enable'  => esc_html__( 'Enable', 'bricks' ),
				'disable' => esc_html__( 'Disable', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Disable', 'bricks' ),
			'inline'      => true,
			'required'    => array( 'layoutType', '!=', 'custom' ),
		);

		$this->controls['noticeText'] = array(
			'group'       => 'noticeOverlay',
			'label'       => esc_html__( 'Text', 'bricks' ),
			'type'        => 'text',
			'placeholder' => esc_html__( 'Notice: Your message here', 'bricksextras' ),
			'required'    => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeVisibility'] = array(
			'group'       => 'noticeOverlay',
			'label'       => esc_html__( 'Visibility', 'bricks' ),
			'type'        => 'select',
			'options'     => array(
				'first'         => esc_html__( 'Only visible before play', 'bricksextras' ),
				'play'          => esc_html__( 'Only visible after play', 'bricksextras' ),
				'loaded'        => esc_html__( 'Only visible when player ready to play', 'bricksextras' ),
				'before_loaded' => esc_html__( 'Only visible before player ready to play', 'bricksextras' ),
			),
			'placeholder' => esc_html__( 'Only visible before play', 'bricksextras' ),
			'required'    => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		/*Notice text */

		$notice_text = '.x-notice-text';

		$this->controls['noticeTextBg'] = array(
			'tab'      => 'content',
			'type'     => 'color',
			'group'    => 'noticeOverlay',
			'label'    => esc_html__( 'Background', 'bricks' ),
			'css'      => array(
				array(
					'property' => 'background-color',
					'selector' => $notice_text,
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeTextBorder'] = array(
			'tab'      => 'content',
			'type'     => 'border',
			'group'    => 'noticeOverlay',
			'label'    => esc_html__( 'Border', 'bricks' ),
			'css'      => array(
				array(
					'property' => 'border',
					'selector' => $notice_text,
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeTextTypography'] = array(
			'tab'      => 'content',
			'type'     => 'typography',
			'group'    => 'noticeOverlay',
			'label'    => esc_html__( 'Typography', 'bricks' ),
			'css'      => array(
				array(
					'property' => 'font',
					'selector' => $notice_text,
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeTextPadding'] = array(
			'tab'      => 'content',
			'type'     => 'spacing',
			'group'    => 'noticeOverlay',
			'label'    => esc_html__( 'Padding', 'bricks' ),
			'css'      => array(
				array(
					'property' => 'padding',
					'selector' => $notice_text,
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeTextWidth'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'noticeOverlay',
			'label'    => esc_html__( 'Width', 'bricks' ),
			'css'      => array(
				array(
					'property' => 'width',
					'selector' => $notice_text,
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeTextHeight'] = array(
			'tab'      => 'content',
			'type'     => 'number',
			'units'    => true,
			'group'    => 'noticeOverlay',
			'label'    => esc_html__( 'Height', 'bricks' ),
			'css'      => array(
				array(
					'property' => 'height',
					'selector' => $notice_text,
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeJustifyContent'] = array(
			'tab'      => 'content',
			'label'    => esc_html__( 'Align main axis', 'bricks' ),
			'group'    => 'noticeOverlay',
			'tooltip'  => array(
				'content'  => 'justify-content',
				'position' => 'top-left',
			),
			'type'     => 'justify-content',
			'css'      => array(
				array(
					'property' => 'justify-content',
					'selector' => '.xmp-custom-overlay',
				),
				array(
					'property' => 'justify-content',
					'selector' => $notice_text,
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);

		$this->controls['noticeAlignItems'] = array(
			'tab'      => 'content',
			'label'    => esc_html__( 'Align cross axis', 'bricks' ),
			'group'    => 'noticeOverlay',
			'tooltip'  => array(
				'content'  => 'align-items',
				'position' => 'top-left',
			),
			'type'     => 'align-items',
			'css'      => array(
				array(
					'property' => 'align-items',
					'selector' => '.xmp-custom-overlay',
				),
			),
			'required' => array(
				array( 'layoutType', '!=', 'custom' ),
				array( 'maybeNotice', '=', 'enable' ),
			),
		);
	}


	/**
	 * Render element output.
	 */
	public function render() {

		$settings = $this->settings;

		$provider = 'video';

		$is_gutenberg = \BricksExtras\Helpers::is_gutenberg_editor();

		$src = $this->get_media_source( $settings, $provider );

		$source_type = isset( $settings['sourceType'] ) ? $settings['sourceType'] : 'url';

		$color_scheme = isset( $settings['colorScheme'] ) ? esc_attr( $settings['colorScheme'] ) : 'dark';

		$positioning            = isset( $settings['positioning'] ) ? $settings['positioning'] : 'default';
		$alt_text               = isset( $settings['altText'] ) ? esc_attr( bricks_render_dynamic_data( $settings['altText'] ) ) : 'video cover image';
		$layout                 = isset( $settings['layout'] ) ? $settings['layout'] : 'default';
		$playsinline            = isset( $settings['playsinline'] ) ? 'enable' === $settings['playsinline'] : true;
		$provider_controls      = isset( $settings['providerControls'] ) ? 'enable' === $settings['providerControls'] : false;
		$controls_delay         = isset( $settings['controlsDelay'] ) ? intval( $settings['controlsDelay'] ) : 2000;
		$loop                   = isset( $settings['loop'] );
		$muted                  = isset( $settings['muted'] );
		$autoplay               = isset( $settings['autoplay'] );
		$fullscreen_orientation = isset( $settings['fullscreenOrientation'] ) ? $settings['fullscreenOrientation'] : 'landscape';
		$hide_nested            = isset( $settings['hideNested'] ) ? $settings['hideNested'] : 'firstplay';
		$loading_type           = isset( $settings['loadingType'] ) ? $settings['loadingType'] : 'visible';

		if ( $provider_controls ) {
			$loading_type = 'visible';
		}

		$title                       = isset( $settings['title'] ) ? esc_attr( bricks_render_dynamic_data( $settings['title'] ) ) : '';
		$maybe_tool_tips             = isset( $settings['maybeToolTips'] ) ? 'enable' === $settings['maybeToolTips'] : false;
		$default_tooltip_placement   = isset( $settings['defaultTooltipPlacement'] ) ? esc_attr( $settings['defaultTooltipPlacement'] ) : 'top';
		$buffering_indicator_display = isset( $settings['bufferingIndicatorDisplay'] ) ? 'true' === $settings['bufferingIndicatorDisplay'] : true;
		$portal_settings             = isset( $settings['portalSettings'] );
		$text_tracks                 = ! empty( $settings['textTracks'] ) ? $settings['textTracks'] : false;
		$image                       = \BricksExtras\Helpers::get_normalized_image_settings( $settings );
		$image_id                    = $image['id'];
		$image_url                   = bricks_render_dynamic_data( $image['url'] );
		$image_size                  = $image['size'];
		$img_loading                 = isset( $settings['imgLoading'] ) ? esc_attr( $settings['imgLoading'] ) : 'lazy';
		$poster_url                  = $image_url ? esc_url( $image_url ) : '';
		$controls                    = ! empty( $settings['controls'] ) ? $settings['controls'] : false;
		$controls_top                = ! empty( $settings['controlsTop'] ) ? $settings['controlsTop'] : false;
		$controls_center             = ! empty( $settings['controlsCenter'] ) ? $settings['controlsCenter'] : false;
		$small_controls_center       = ! empty( $settings['smallcontrolsCenter'] ) ? $settings['smallcontrolsCenter'] : false;
		$small_controls              = ! empty( $settings['smallControls'] ) ? $settings['smallControls'] : false;
		$small_controls_top          = ! empty( $settings['smallControlsTop'] ) ? $settings['smallControlsTop'] : false;
		$chapters                    = ! empty( $settings['chapters'] ) ? $settings['chapters'] : false;
		$thumbnail_attr              = isset( $settings['thumbnailFile'] ) ? 'src="' . esc_url( bricks_render_dynamic_data( $settings['thumbnailFile'] ) ) . '"' : '';
		$thumbnails                  = isset( $settings['thumbnailFile'] ) ? esc_url( bricks_render_dynamic_data( $settings['thumbnailFile'] ) ) : false;
		$layout_type                 = isset( $settings['layoutType'] ) ? esc_attr( $settings['layoutType'] ) : 'type_one';
		$small_controls_breakpoint   = isset( $settings['smallControlsBreakpoint'] ) ? intval( $settings['smallControlsBreakpoint'] ) : 478;
		$maybe_time_slider           = isset( $settings['maybeTimeSlider'] ) ? 'enable' === $settings['maybeTimeSlider'] : true;
		$maybe_time_slider_small     = isset( $settings['maybeTimeSliderSmall'] ) ? 'enable' === $settings['maybeTimeSliderSmall'] : true;
		$maybe_notice                = isset( $settings['maybeNotice'] ) ? 'enable' === $settings['maybeNotice'] : false;
		$notice_text                 = ! empty( $settings['noticeText'] ) ? bricks_render_dynamic_data( $settings['noticeText'] ) : 'Notice: Your message here';
		$notice_visibility           = isset( $settings['noticeVisibility'] ) ? $settings['noticeVisibility'] : 'first';
		$poster_reshow               = isset( $settings['posterReshow'] );
		$remember_player_settings    = isset( $settings['rememberPlayerSettings'] );
		$auto_local_poster           = isset( $settings['autoLocalPoster'] );
		$modal_autoplay              = isset( $settings['modalAutoplay'] ) ? $settings['modalAutoplay'] : 'disable';
		$click_to_play               = isset( $settings['clickToPlay'] ) ? 'enable' === $settings['clickToPlay'] : true;
		$fullscreen_fallback         = isset( $settings['fullscreenFallback'] ) ? $settings['fullscreenFallback'] : 'full_window';
		$loading_ui                  = isset( $settings['loadingUI'] ) ? $settings['loadingUI'] : 'visible';
		$which_playlist              = isset( $settings['whichPlaylist'] ) ? $settings['whichPlaylist'] : 'section';
		$playlist_selector           = isset( $settings['playlistSelector'] ) ? $settings['playlistSelector'] : '';
		$play_reset                  = isset( $settings['playReset'] );

		if ( isset( $settings['multipleSources'] ) && 'url' === $source_type && ! empty( $settings['srcRepeater'] ) && is_array( $settings['srcRepeater'] ) ) {

			$additional_sources = array();

			foreach ( $settings['srcRepeater'] as $item ) {

				if ( empty( bricks_render_dynamic_data( $item['source'] ?? '' ) ) ) {
					continue;
				}

				$source = array(
					'src'   => esc_url( bricks_render_dynamic_data( $item['source'] ) ),
					'type'  => esc_attr( bricks_render_dynamic_data( $item['type'] ?? 'video/mp4' ) ),
					'width' => absint( bricks_render_dynamic_data( $item['width'] ?? 1000 ) ),
				);

				// Only add height if it's set and valid.
				if ( isset( $item['height'] ) && is_numeric( bricks_render_dynamic_data( $item['height'] ) ) ) {
					$source['height'] = absint( bricks_render_dynamic_data( $item['height'] ) );
				}

				$additional_sources[] = $source;
			}

			if ( ! empty( $additional_sources ) ) {
				$this->set_attribute( '_root', 'data-x-srcs', htmlspecialchars( wp_json_encode( $additional_sources, JSON_HEX_APOS | JSON_HEX_QUOT ), ENT_QUOTES, 'UTF-8' ) );
			}
		}

		if ( 'custom' === $layout_type ) {
			$loading_ui = 'eager';
		}

		// Generate and set a unique identifier for this instance.
		$player_identifier = \BricksExtras\Helpers::set_identifier_attribute( $this );

		// Provider controls.
		$provider_controls = isset( $settings['providerControls'] ) ? 'enable' === $settings['providerControls'] : false;

		/* Get cached poster for YouTube/Vimeo videos BEFORE config setup */
		if ( ! \BricksExtras\Helpers::maybe_preview() && ! $image_url ) {

			// Skip poster lookup for playlist players.
			$has_playlist = isset( $settings['playlistMode'] );

			if ( $auto_local_poster && ! $has_playlist ) {

				// Only attempt caching for YouTube/Vimeo URLs.
				$is_youtube = ( strpos( $src, 'youtube' ) !== false || strpos( $src, 'youtu.be' ) !== false );
				$is_vimeo   = ( strpos( $src, 'vimeo' ) !== false );

				if ( $is_youtube || $is_vimeo ) {
					$poster_data = \BricksExtras\BricksExtrasMedia::get_video_poster( $src );

					if ( $poster_data && is_array( $poster_data ) && isset( $poster_data['url'] ) ) {
						$poster_url = esc_url( $poster_data['url'] );
					}
				}
			}
		}

		// Use the common config setup method from the trait.
		$config = $this->setup_common_config(
			$settings,
			$layout_type,
			$loading_type,
			$click_to_play,
			$auto_local_poster,
			$which_playlist,
			$playlist_selector,
			$poster_url,
			$thumbnails,
			$remember_player_settings
		);

		// Add video-specific config settings.
		$config['fullscreenFallBack'] = $fullscreen_fallback;

		// Add lazy UI config if needed.
		if ( 'visible' === $loading_ui && 'custom' !== $layout_type ) {
			$config += array(
				'lazyUI' => $loading_ui,
			);
		}

		// Add poster reshow config if needed.
		if ( $poster_reshow && ! $provider_controls ) {
			$config += array(
				'reshowPoster' => 'true',
			);
		}

		// Add container layout breakpoint if needed.
		if ( 'container' === $layout_type ) {
			$config += array(
				'breakpoint' => $small_controls_breakpoint,
			);
		}

		if ( isset( $settings['autoCaptionsBunny'] ) ) {
			$config += array(
				'autoCaptionsBunny' => true,
			);
		}

		// Process chapters using the trait method.
		$chapters_array = $this->process_chapters( $settings );

		// Set chapters attribute if valid chapters exist.
		$this->set_chapters_attribute( $chapters_array );

		// Set common attributes using the trait method.
		$this->set_common_attributes(
			$settings,
			'video',
			$config,
			$src,
			$layout_type,
			$positioning,
			$remember_player_settings ? $player_identifier : '',
			$is_gutenberg
		);

		// Play reset..
		if ( $muted && $autoplay && $play_reset && ! \BricksExtras\Helpers::maybe_preview() ) {
			$this->set_attribute( '_root', 'data-x-play-reset', 'true' );
		}

		// autoplay on modal reopen - always.
		if ( $muted && $autoplay && 'enable' === $modal_autoplay && ! \BricksExtras\Helpers::maybe_preview() ) {
			$this->set_attribute( '_root', 'data-x-modal-autoplay', 'always' );
		}

		// Autoplay on modal reopen - if playing.
		if ( $muted && $autoplay && 'if_playing' === $modal_autoplay && ! \BricksExtras\Helpers::maybe_preview() ) {
			$this->set_attribute( '_root', 'data-x-modal-autoplay', 'if-playing' );
		}

		// Set video-specific attributes.
		$this->set_attribute( '_root', 'data-lg', '' );

		// Handle controls delay - if -1, set to 2000 and add controls-remain attribute.
		if ( -1 === $controls_delay ) {
			$this->set_attribute( '_root', 'controls-delay', '2000' );
			$this->set_attribute( '_root', 'data-x-controls-remain', 'true' );
		} else {
			$this->set_attribute( '_root', 'controls-delay', esc_attr( $controls_delay ) );
		}

		if ( $playsinline ) {
			$this->set_attribute( '_root', 'playsInline', true );
		}

		$first_output = '';
		$output       = '';
		$last_output  = '';

		$first_output .= "<media-player {$this->render_attributes( '_root' )}>";
		$first_output .= '<media-provider>';

		if ( $poster_url ) {

			if ( 'custom' === $layout_type && BricksExtras\Helpers::maybe_preview() ) {
				/* In builder. */
				$first_output .= "<media-poster {$this->render_attributes( 'media-poster' )}>";
				$first_output .= "<img class='xmp-poster_initial' src='" . $poster_url . "' alt='" . esc_attr( $alt_text ) . "' >";
				$first_output .= '</media-poster>';
			} else {
				$first_output .= "<media-poster {$this->render_attributes( 'media-poster' )}>";

				if ( $image_id && $image_size ) {
					$first_output .= wp_get_attachment_image(
						$image_id,
						$image_size,
						false,
						array(
							'class'   => 'xmp-poster_initial',
							'loading' => $img_loading,
							'alt'     => esc_attr( $alt_text ),
						)
					);

				} else {
					$first_output .= "<img class='xmp-poster_initial' src='" . $poster_url . "' alt='" . esc_attr( $alt_text ) . "' loading='" . $img_loading . "'>";
				}

				$first_output .= '</media-poster>';
			}
		} else {
			$first_output .= "<media-poster alt='" . esc_attr( $alt_text ) . "' class='xmp-poster'></media-poster>";
		}

		if ( $text_tracks ) {
			$first_output .= $this->render_text_tracks( $text_tracks );
		}

		$first_output .= '</media-provider>';

		if ( $maybe_notice && 'custom' !== $layout_type ) {
			$first_output .= '<div data-x-control-visibility="' . esc_attr( $notice_visibility ) . '" class="xmp-custom-overlay"><div class="x-notice-text"><span>' . wp_kses_post( $notice_text ) . '</span></div></div>';
		}

		if ( ! $provider_controls ) {

			if ( 'custom' !== $layout_type ) {

				$output = $this->render_video_player(
					$output,
					$provider,
					$layout_type,
					$controls_top,
					$controls_center,
					$controls,
					$small_controls_top,
					$small_controls_center,
					$small_controls,
					$maybe_time_slider,
					$maybe_time_slider_small,
					$maybe_tool_tips,
					$default_tooltip_placement,
					$title,
					$thumbnail_attr,
					$color_scheme,
					$portal_settings,
					$player_identifier,
					$settings
				);
			}

			if ( 'custom' === $layout_type ) {
				$output .= "<media-layout {$this->render_attributes( 'x-media-player_inner' )}>";
			} else {
				$output .= BricksExtras\Helpers::maybe_preview() ? "<media-layout {$this->render_attributes( 'x-media-player_hidden-inner' )}>" : '';
			}

			/* nesting elements */
			if ( 'custom' === $layout_type || BricksExtras\Helpers::maybe_preview() ) {

				if ( method_exists( '\Bricks\Frontend', 'render_children' ) ) {
					$output .= "<media-controls  {$this->render_attributes( 'media-controls' )}>";
					$output .= \Bricks\Frontend::render_children( $this );
					$output .= '</media-controls>';
				}
			}

			if ( 'custom' === $layout_type ) {
				$output .= '</media-layout>';
			} else {
				$output .= BricksExtras\Helpers::maybe_preview() ? '</media-layout>' : '';
			}

			$output .= '<div class="xmp-media-features" data-x-color="' . $color_scheme . '">';

			$buffering_class = BricksExtras\Helpers::maybe_preview() && isset( $settings['bufferingIndicatorPreview'] ) ? 'xmp-buffering-indicator xmp-buffering-indicator_preview' : 'xmp-buffering-indicator';

			$output .= $buffering_indicator_display ? '<div class="' . $buffering_class . '">
        <media-spinner class="xmp-buffering-spinner"></media-spinner>
      </div>' : '';

			/* gestures */

			$output .= '<media-gesture class="xmp-gesture" event="pointerup" action="toggle:controls"></media-gesture>';

			if ( $click_to_play && ! BricksExtras\Helpers::maybe_preview() ) {
				$output .= '<media-gesture event="click" action="toggle:paused"></media-gesture><media-gesture event="keyup" action="play"></media-gesture>';
			}
		} /* end of !providerControls */

		$output .= '<media-captions class="xmp-captions"></media-captions>';

		$output .= isset( $settings['announcer'] ) && 'disable' === $settings['announcer'] ? '' : '<media-announcer></media-announcer>';

		$output .= '</div>';

		$final_output = '';

		if ( ! $is_gutenberg ) {

			$final_output .= $first_output;

			if ( 'eager' === $loading_ui || BricksExtras\Helpers::maybe_preview() ) {
				$final_output .= $output;
			} else {
				// Output template for lazy loading.
				$final_output .= '<template data-x-mediaplayer-template="' . esc_attr( $player_identifier ) . '">' . $output . '</template>';
			}

			$final_output .= '</media-player>';

		} else {

			$this->set_attribute( '_root', 'class', 'x-media-player_editor' );

			$final_output .= "<div {$this->render_attributes( '_root' )}>";
			$final_output .= "<div class='x-media-player_placeholder'>Media Player</div>";
			$final_output .= '</div>';

		}

		echo $final_output;
	}


	/**
	 * Render the video player layout
	 *
	 * @param string $output Player output HTML.
	 * @param string $provider Media provider type.
	 * @param string $layout_type Layout type setting.
	 * @param array  $controls_top Top controls array.
	 * @param array  $controls_center Center controls array.
	 * @param array  $controls Bottom controls array.
	 * @param array  $small_controls_top Small top controls array.
	 * @param array  $small_controls_center Small center controls array.
	 * @param array  $small_controls Small bottom controls array.
	 * @param bool   $maybe_time_slider Time slider enabled.
	 * @param bool   $maybe_time_slider_small Small time slider enabled.
	 * @param bool   $maybe_tool_tips Tooltips enabled.
	 * @param string $default_tooltip_placement Default tooltip placement.
	 * @param string $title Media title.
	 * @param string $thumbnail_attr Thumbnail attributes.
	 * @param string $color_scheme Color scheme setting.
	 * @param bool   $portal_settings Portal enabled.
	 * @param string $player_identifier Player identifier.
	 * @param array  $settings Element settings.
	 */
	private function render_video_player(
		$output,
		$provider,
		$layout_type,
		$controls_top,
		$controls_center,
		$controls,
		$small_controls_top,
		$small_controls_center,
		$small_controls,
		$maybe_time_slider,
		$maybe_time_slider_small,
		$maybe_tool_tips,
		$default_tooltip_placement,
		$title,
		$thumbnail_attr,
		$color_scheme,
		$portal_settings,
		$player_identifier,
		$settings
	) {

		if ( 'type_two' === $layout_type ) {
			$output .= '<media-layout class="xmp-layout_type-two">';

			if ( 'custom' !== $layout_type && 'type_two' === $layout_type ) {
				$player_controls  = '';
				$player_controls .= "<media-controls {$this->render_attributes('media-controls')}>";

				// Render top controls for large layout.
				if ( (bool) $controls_top && ( 'custom' !== $layout_type ) ) {
					$controls_top_visibility = isset( $settings['controlsTopVisibility'] ) ?
					'data-x-control-visibility="' . esc_attr( $settings['controlsTopVisibility'] ) . '"' : 'data-x-control-visibility="default"';

					$player_controls .= '<div class="xmp-controls_group xmp-controls_group_top" ' . $controls_top_visibility . '>';
					foreach ( $controls_top as $control ) {
						$player_controls .= $this->render_control(
							$control,
							$provider,
							$maybe_tool_tips,
							$default_tooltip_placement,
							'top',
							$title,
							'', /* artist */
							$thumbnail_attr,
							$color_scheme,
							$portal_settings,
							$player_identifier
						);
					}
					$player_controls .= '</div>';
				}

				// Render center controls for large layout.
				if ( (bool) $controls_center ) {
					$controls_center_visibility = isset( $settings['controlsCenterVisibility'] ) ?
					'data-x-control-visibility="' . esc_attr( $settings['controlsCenterVisibility'] ) . '"' : 'data-x-control-visibility="default"';

					$player_controls .= '<div class="xmp-controls_group xmp-controls_group_center" ' . $controls_center_visibility . '>';
					foreach ( $controls_center as $control ) {
						$player_controls .= $this->render_control(
							$control,
							$provider,
							$maybe_tool_tips,
							$default_tooltip_placement,
							'top',
							$title,
							'', /* artist */
							$thumbnail_attr,
							$color_scheme,
							$portal_settings,
							$player_identifier
						);
					}
					$player_controls .= '</div>';
				}

				// Render time slider for large layout.
				$controls_bottom_visibility = isset( $settings['controlsBottomVisibility'] ) ?
				'data-x-control-visibility="' . esc_attr( $settings['controlsBottomVisibility'] ) . '"' : 'data-x-control-visibility="default"';

				if ( $maybe_time_slider ) {
					$player_controls .= $this->render_time_slider( $controls_bottom_visibility, $thumbnail_attr );
				}

				// Render bottom controls for large layout.
				$player_controls .= '<div class="xmp-controls_group xmp-controls_group_bottom" ' . $controls_bottom_visibility . '>';

				if ( (bool) $controls && ( 'custom' !== $layout_type ) ) {
					foreach ( $controls as $control ) {
						$player_controls .= $this->render_control(
							$control,
							$provider,
							$maybe_tool_tips,
							$default_tooltip_placement,
							'bottom',
							$title,
							'', /* artist */
							$thumbnail_attr,
							$color_scheme,
							$portal_settings,
							$player_identifier
						);
					}
				}

				$player_controls .= '</div>';
				$player_controls .= '</media-controls>';

				$output .= $player_controls;
			}

			$output .= '</media-layout>';
		}

		// Now handle the small layout (when layoutType is not 'type_two').
		if ( 'type_two' !== $layout_type ) {
			$output         .= '<media-layout class="xmp-layout_type-one">';
			$player_controls = '';

			if ( 'custom' !== $layout_type ) {
				$player_controls .= "<media-controls {$this->render_attributes('media-controls')}>";

				// Render top controls for small layout.
				if ( (bool) $small_controls_top && ( 'custom' !== $layout_type ) ) {
					$smallcontrols_top_visibility = isset( $settings['smallcontrolsTopVisibility'] ) ?
					'data-x-control-visibility="' . esc_attr( $settings['smallcontrolsTopVisibility'] ) . '"' : 'data-x-control-visibility="default"';

					$player_controls .= '<div class="xmp-controls_group xmp-controls_group_top" ' . $smallcontrols_top_visibility . '>';
					foreach ( $small_controls_top as $control ) {
						$player_controls .= $this->render_control(
							$control,
							$provider,
							$maybe_tool_tips,
							$default_tooltip_placement,
							'top',
							$title,
							'', /* artist */
							$thumbnail_attr,
							$color_scheme,
							$portal_settings,
							$player_identifier
						);
					}
					$player_controls .= '</div>';
				}

				// Render center controls for small layout.
				if ( (bool) $small_controls_center ) {
					$small_controls_center_visibility = isset( $settings['smallcontrolsCenterVisibility'] ) ?
					'data-x-control-visibility="' . esc_attr( $settings['smallcontrolsCenterVisibility'] ) . '"' : 'data-x-control-visibility="default"';

					$player_controls .= '<div class="xmp-controls_group xmp-controls_group_center" ' . $small_controls_center_visibility . '>';
					foreach ( $small_controls_center as $control ) {
							$player_controls .= $this->render_control(
								$control,
								$provider,
								$maybe_tool_tips,
								$default_tooltip_placement,
								'top',
								$title,
								'', /* artist */
								$thumbnail_attr,
								$color_scheme,
								$portal_settings,
								$player_identifier
							);
					}
					$player_controls .= '</div>';
				}

				// Render bottom controls for small layout.
				$small_controls_bottom_visibility = isset( $settings['smallcontrolsBottomVisibility'] ) ?
				'data-x-control-visibility="' . esc_attr( $settings['smallcontrolsBottomVisibility'] ) . '"' : 'data-x-control-visibility="default"';

				$player_controls .= '<div class="xmp-controls_group xmp-controls_group_bottom" ' . $small_controls_bottom_visibility . '>';

				if ( (bool) $small_controls && ( 'custom' !== $layout_type ) ) {
					foreach ( $small_controls as $control ) {
						$player_controls .= $this->render_control(
							$control,
							$provider,
							$maybe_tool_tips,
							$default_tooltip_placement,
							'bottom',
							$title,
							'', /* artist */
							$thumbnail_attr,
							$color_scheme,
							$portal_settings,
							$player_identifier
						);
					}
				}

				$player_controls .= '</div>';

				// Render time slider for small layout.
				if ( $maybe_time_slider_small ) {
					$player_controls .= $this->render_time_slider( $small_controls_bottom_visibility, $thumbnail_attr );
				}

				$player_controls .= '</media-controls>';
			}

			$output .= $player_controls;
			$output .= '</media-layout>';
		}

		return $output;
	}
}
