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

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

/**
 * Media Playlist element class.
 */
class X_Media_Playlist extends \Bricks\Element {

	/**
	 * Element category.
	 *
	 * @var string
	 */
	public $category = 'extras';
	/**
	 * Element name.
	 *
	 * @var string
	 */
	public $name = 'xmediaplaylist';
	/**
	 * Element icon.
	 *
	 * @var string
	 */
	public $icon = 'ti-list';
	/**
	 * CSS selector.
	 *
	 * @var string
	 */
	public $css_selector = '';
	/**
	 * Element is nestable.
	 *
	 * @var bool
	 */
	public $nestable = true;
	/**
	 * Loop index.
	 *
	 * @var int
	 */
	public $loop_index = 0;


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

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


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

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

		$this->control_groups['activeStyles'] = array(
			'title' => esc_html__( 'Item styles', 'bricksextras' ),
		);

		$this->control_groups['layout'] = array(
			'title' => esc_html__( 'Layout', 'bricks' ) . ' / ' . esc_html__( 'Spacing', 'bricks' ),
			'tab'   => 'content',
		);

		$this->control_groups['chapters'] = array(
			'title' => esc_html__( 'Chapters', 'bricksextras' ),
		);

		$this->control_groups['textTracks'] = array(
			'title' => esc_html__( 'Text Tracks', 'bricksextras' ),
		);

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

		$this->control_groups['downloads'] = array(
			'title'    => esc_html__( 'Downloads', 'bricks' ),
			'required' => array(
				array( 'provider', '=', 'audio' ),
			),
		);
	}

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

		$this->controls['provider'] = array(
			'label'       => esc_html__( 'Media type', 'bricksextras' ),
			'type'        => 'select',
			'options'     => array(
				'video' => esc_html__( 'Video', 'bricks' ),
				'audio' => esc_html__( 'Audio', 'bricks' ),
			),
			'placeholder' => esc_html__( 'Video', 'bricks' ),
			'inline'      => true,
		);

		$this->controls['sourceType'] = array(
			'tab'         => 'content',
			'label'       => esc_html__( 'Source', 'bricks' ),
			'type'        => 'select',
			'options'     => array(
				'media' => esc_html__( 'Media library', 'bricks' ),
				'url'   => esc_html__( 'URL', 'bricks' ),
			),
			'placeholder' => esc_html__( 'URL', 'bricks' ),
			'inline'      => true,
			'clearable'   => false,
		);

		$this->controls['media'] = array(
			'tab'      => 'content',
			'label'    => esc_html__( 'Media', 'bricks' ),
			'type'     => 'video',
			'required' => array(
				array( 'provider', '!=', 'audio' ),
				array( 'sourceType', '=', 'media' ),
			),
		);

		$this->controls['audio'] = array(
			'tab'      => 'content',
			'label'    => esc_html__( 'Audio', 'bricks' ),
			'type'     => 'audio',
			'required' => array(
				array( 'provider', '=', 'audio' ),
				array( 'sourceType', '=', 'media' ),
			),
		);

		$this->controls['src'] = array(
			'label'    => esc_html__( 'Media source URL', 'bricksextras' ),
			'type'     => 'text',
			'required' => array(
				array( 'sourceType', '!=', 'media' ),
				array( 'multipleSources', '!=', true ),
			),
		);

		$this->controls['srcRepeater'] = array(
			'label'    => esc_html__( 'Media sources', 'bricksextras' ),
			'type'     => 'repeater',
			'fields'   => array(
				'source' => array(
					'label'       => esc_html__( 'Media source URL', 'bricksextras' ),
					'type'        => 'text',
					'placeholder' => 'https://example.com/video-1920x1080.mp4',
				),
				'type'   => array(
					'label'       => esc_html__( 'Media type', 'bricksextras' ),
					'type'        => 'text',
					'placeholder' => 'video/mp4',
					'inline'      => true,
				),
				'width'  => array(
					'label'       => esc_html__( 'Width', 'bricks' ),
					'type'        => 'text',
					'placeholder' => '1920',
					'inline'      => true,
				),
				'height' => array(
					'label'       => esc_html__( 'Height', 'bricks' ),
					'type'        => 'text',
					'placeholder' => '1080',
					'inline'      => true,
				),
			),
			'required' => array(
				array( 'sourceType', '!=', 'media' ),
				array( 'playlistMode', '!=', true ),
				array( 'multipleSources', '=', true ),
				array( 'provider', '!=', 'audio' ),
			),
		);

		$this->controls['srcRepeaterAudio'] = array(
			'label'    => esc_html__( 'Media sources', 'bricksextras' ),
			'info'     => esc_html__( 'Multiple file types', 'bricksextras' ),
			'type'     => 'repeater',
			'fields'   => array(
				'source' => array(
					'label'       => esc_html__( 'Media source URL', 'bricksextras' ),
					'type'        => 'text',
					'placeholder' => 'https://example.com/audio.mp3',
				),
				'type'   => array(
					'label'       => esc_html__( 'Media type', 'bricksextras' ),
					'type'        => 'text',
					'placeholder' => 'audio/mpeg',
					'inline'      => true,
				),
			),
			'required' => array(
				array( 'sourceType', '!=', 'media' ),
				array( 'playlistMode', '!=', true ),
				array( 'multipleSources', '=', true ),
				array( 'provider', '=', 'audio' ),
			),
		);

		$this->controls['title'] = array(
			'tab'    => 'content',
			'label'  => esc_html__( 'Title', 'bricks' ),
			'type'   => 'text',
			'inline' => true,
		);

		$this->controls['artist'] = array(
			'tab'      => 'content',
			'label'    => esc_html__( 'Artist', 'bricksextras' ),
			'type'     => 'text',
			'inline'   => true,
			'required' => array(
				array( 'provider', '=', 'audio' ),
			),
		);

		$this->controls['srcMediaType'] = array(
			'label'    => esc_html__( 'Mime type', 'bricks' ) . ' (' . esc_html__( 'Optional', 'bricks' ) . ' )',
			'type'     => 'text',
			'inline'   => true,
			'info'     => 'audio/mpeg, video/mp4',
			'required' => array(
				array( 'sourceType', '!=', 'media' ),
				array( 'multipleSources', '!=', true ),
			),
		);

			$this->controls['streamType'] = array(
				'label'       => esc_html__( 'Stream type', 'bricksextras' ),
				'type'        => 'text',
				'info'        => 'on-demand, live, live:dvr, ll-live, ll-live:dvr',
				'placeholder' => 'on-demand',
				'inline'      => true,
			);

			$this->controls['image'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Poster image', 'bricks' ),
				'type'  => 'image',
				'group' => 'poster',
			);

			/* active styles */

			$active_item    = '&[data-x-item-active]';
			$active_playing = $active_item . '[data-x-item-playing]';
			$active_paused  = $active_item . '[data-x-item-paused]';

			$this->controls['activeSep'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Active', 'bricks' ),
				'type'  => 'separator',
				'group' => 'activeStyles',
			);

			$this->controls['activeBackgroundColor'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'type'  => 'color',
				'label' => esc_html__( 'Background', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'background-color',
						'selector' => $active_item,
					),
				),
			);

			$this->controls['activeBorder'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'type'  => 'border',
				'label' => esc_html__( 'Border', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'border',
						'selector' => $active_item,
					),
				),
			);

			$this->controls['activeBoxShadow'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'label' => esc_html__( 'Box shadow', 'bricks' ),
				'type'  => 'box-shadow',
				'css'   => array(
					array(
						'property' => 'box-shadow',
						'selector' => $active_item,
					),
				),
			);

			$this->controls['activeTypography'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Typography', 'bricks' ),
				'type'  => 'typography',
				'group' => 'activeStyles',
				'units' => true,
				'css'   => array(
					array(
						'property' => 'font',
						'selector' => $active_item,
					),
				),
			);

			$this->controls['activePlayingSep'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Playing', 'bricksextras' ),
				'type'  => 'separator',
				'group' => 'activeStyles',
			);

			$this->controls['activePlayingBackgroundColor'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'type'  => 'color',
				'label' => esc_html__( 'Background', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'background-color',
						'selector' => $active_playing,
					),
				),
			);

			$this->controls['activePlayingBorder'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'type'  => 'border',
				'label' => esc_html__( 'Border', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'border',
						'selector' => $active_playing,
					),
				),
			);

			$this->controls['activePlayingBoxShadow'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'label' => esc_html__( 'Box shadow', 'bricks' ),
				'type'  => 'box-shadow',
				'css'   => array(
					array(
						'property' => 'box-shadow',
						'selector' => $active_playing,
					),
				),
			);

			$this->controls['activePlayingTypography'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Typography', 'bricks' ),
				'type'  => 'typography',
				'group' => 'activeStyles',
				'units' => true,
				'css'   => array(
					array(
						'property' => 'font',
						'selector' => $active_playing,
					),
				),
			);

			$this->controls['activePausedSep'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Paused', 'bricks' ),
				'type'  => 'separator',
				'group' => 'activeStyles',
			);

			$this->controls['activePausedBackgroundColor'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'type'  => 'color',
				'label' => esc_html__( 'Background', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'background-color',
						'selector' => $active_paused,
					),
				),
			);

			$this->controls['activePausedPlayingBorder'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'type'  => 'border',
				'label' => esc_html__( 'Border', 'bricks' ),
				'css'   => array(
					array(
						'property' => 'border',
						'selector' => $active_paused,
					),
				),
			);

			$this->controls['activePausedPlayingBoxShadow'] = array(
				'tab'   => 'content',
				'group' => 'activeStyles',
				'label' => esc_html__( 'Box shadow', 'bricks' ),
				'type'  => 'box-shadow',
				'css'   => array(
					array(
						'property' => 'box-shadow',
						'selector' => $active_paused,
					),
				),
			);

			$this->controls['activePausedPlayingTypography'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Typography', 'bricks' ),
				'type'  => 'typography',
				'group' => 'activeStyles',
				'units' => true,
				'css'   => array(
					array(
						'property' => 'font',
						'selector' => $active_paused,
					),
				),
			);

			$this->controls['flexWrap'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Flex wrap', 'bricks' ),
				'group'       => 'layout',
				'tooltip'     => array(
					'content'  => 'flex-wrap',
					'position' => 'top-left',
				),
				'type'        => 'select',
				'options'     => array(
					'nowrap'       => esc_html__( 'No wrap', 'bricks' ),
					'wrap'         => esc_html__( 'Wrap', 'bricks' ),
					'wrap-reverse' => esc_html__( 'Wrap reverse', 'bricks' ),
				),
				'inline'      => true,
				'css'         => array(
					array(
						'property' => 'flex-wrap',
						'selector' => '',
					),
				),
				'placeholder' => esc_html__( 'No wrap', 'bricks' ),
			);

			$this->controls['direction'] = array(
				'tab'      => 'content',
				'label'    => esc_html__( 'Direction', 'bricks' ),
				'group'    => 'layout',
				'tooltip'  => array(
					'content'  => 'flex-direction',
					'position' => 'top-left',
				),
				'type'     => 'direction',
				'css'      => array(
					array(
						'property' => 'flex-direction',
						'selector' => '',
					),
				),
				'inline'   => true,
				'rerender' => true,
			);

			$this->controls['justifyContent'] = array(
				'tab'     => 'content',
				'label'   => esc_html__( 'Align main axis', 'bricks' ),
				'group'   => 'layout',
				'tooltip' => array(
					'content'  => 'justify-content',
					'position' => 'top-left',
				),
				'type'    => 'justify-content',
				'css'     => array(
					array(
						'property' => 'justify-content',
						'selector' => '',
					),
				),
			);

			$this->controls['alignItems'] = array(
				'tab'     => 'content',
				'label'   => esc_html__( 'Align cross axis', 'bricks' ),
				'group'   => 'layout',
				'tooltip' => array(
					'content'  => 'align-items',
					'position' => 'top-left',
				),
				'type'    => 'align-items',
				'css'     => array(
					array(
						'property' => 'align-items',
						'selector' => '',
					),
				),
			);

			$this->controls['columnGap'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Column gap', 'bricks' ),
				'group' => 'layout',
				'type'  => 'number',
				'units' => true,
				'css'   => array(
					array(
						'property' => 'column-gap',
						'selector' => '',
					),
				),
			);

			$this->controls['rowGap'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Row gap', 'bricks' ),
				'group' => 'layout',
				'type'  => 'number',
				'units' => true,
				'css'   => array(
					array(
						'property' => 'row-gap',
						'selector' => '',
					),
				),
			);

			/* chapters */

			$this->controls['hasLoop'] = array(
				'tab'   => 'content',
				'label' => esc_html__( 'Add chapters with query loop', 'bricksextras' ),
				'type'  => 'checkbox',
				'group' => 'chapters',
			);

			$this->controls['query'] = array(
				'tab'      => 'content',
				'label'    => esc_html__( 'Query', 'bricks' ),
				'type'     => 'query',
				'group'    => 'chapters',
				'popup'    => true,
				'inline'   => true,
				'required' => array(
					array( 'hasLoop', '!=', '' ),
				),
			);

			$this->controls['chapters'] = array(
				'tab'         => 'content',
				'placeholder' => esc_html__( 'Chapter', 'bricksextras' ),
				'type'        => 'repeater',
				'group'       => 'chapters',
				'fields'      => array(
					'text'      => array(
						'label'          => esc_html__( 'Title', 'bricks' ),
						'type'           => 'text',
						'hasDynamicData' => false,
					),
					'startTime' => array(
						'label'          => esc_html__( 'Start time', 'bricks' ),
						'type'           => 'text',
						'hasDynamicData' => false,
						'inline'         => true,
					),
					'endTime'   => array(
						'label'          => esc_html__( 'End time', 'bricks' ),
						'type'           => 'text',
						'hasDynamicData' => false,
						'inline'         => true,
					),
				),
				'required'    => array(
					array( 'hasLoop', '!=', true ),
				),
			);

			$this->controls['chapterText'] = array(
				'tab'      => 'content',
				'label'    => esc_html__( 'Text', 'bricks' ),
				'type'     => 'text',
				'group'    => 'chapters',
				'required' => array(
					array( 'hasLoop', '=', true ),
				),
			);

			$this->controls['chapterStart'] = array(
				'tab'      => 'content',
				'label'    => esc_html__( 'Start time', 'bricks' ),
				'type'     => 'text',
				'group'    => 'chapters',
				'inline'   => true,
				'required' => array(
					array( 'hasLoop', '=', true ),
				),
			);

			$this->controls['chapterEnd'] = array(
				'tab'      => 'content',
				'label'    => esc_html__( 'End time', 'bricks' ),
				'type'     => 'text',
				'group'    => 'chapters',
				'inline'   => true,
				'required' => array(
					array( 'hasLoop', '=', true ),
				),
			);

			$this->controls['chaptersSep'] = array(
				'tab'   => 'content',
				'type'  => 'seperator',
				'group' => 'chapters',
			);

			/* textTracks */

			$this->controls['textTracksSep'] = array(
				'group'        => 'textTracks',
				'label'        => esc_html__( 'Subtitles', 'bricksextras' ) . ' / ' . esc_html__( 'Captions', 'bricksextras' ),
				'descriptions' => esc_html__( 'Here you can add subtitles/captions to the media player.', 'bricksextras' ),
				'type'         => 'separator',
			);

			$this->controls['textTracks'] = array(
				'tab'           => 'content',
				'type'          => 'repeater',
				'group'         => 'textTracks',
				'label'         => esc_html__( 'Text Tracks', 'bricksextras' ),
				'titleProperty' => 'label',
				'fields'        => array(
					'label'    => array(
						'type'   => 'text',
						'label'  => esc_html__( 'Label', 'bricks' ),
						'inline' => true,
					),
					'src'      => array(
						'type'   => 'text',
						'label'  => esc_html__( 'Source', 'bricks' ) . ' (.vtt, .srt, .json)',
						'inline' => true,
					),
					'kind'     => array(
						'type'    => 'select',
						'label'   => 'kind',
						'inline'  => true,
						'options' => array(
							'subtitles' => 'subtitles',
							'chapters'  => 'chapters',
							'captions'  => 'captions',
						),
					),
					'language' => array(
						'type'   => 'text',
						'label'  => esc_html__( 'Language', 'bricks' ) . ' (en, fr, de, es..)',
						'inline' => true,
					),
				),
			);

			$this->controls['thumbnailSep'] = array(
				'group' => 'textTracks',
				'label' => esc_html__( 'Thumbnails', 'bricksextras' ),
				'type'  => 'separator',
			);

			$this->controls['thumbnailFile'] = array(
				'group'  => 'textTracks',
				'type'   => 'text',
				'label'  => esc_html__( 'Source', 'bricks' ) . ' (.vtt)',
				'inline' => true,
			);

			$this->controls['multipleSources'] = array(
				'group'    => 'behaviour',
				'label'    => esc_html__( 'Allow multiple sources', 'bricksextras' ),
				'type'     => 'checkbox',
				'inline'   => true,
				'small'    => true,
				'rerender' => false,
				'required' =>
				array( 'sourceType', '!=', 'media' ),
			);

			$this->controls['securitySep'] = array(
				'tab'         => 'content',
				'label'       => 'Bunny Stream Authentication',
				'group'       => 'behaviour',
				'description' => esc_html__( 'Create expiring video URLs', 'bricksextras' ),
				'type'        => 'separator',
				'required'    => array( array( 'provider', '!=', 'audio' ) ),
			);

			// Add security controls.
			$this->controls['enableSecurity'] = array(
				'tab'      => 'content',
				'group'    => 'behaviour',
				'label'    => esc_html__( 'Generate Authentication Tokens', 'bricksextras' ),
				'info'     => esc_html__( 'Enable if your Bunny Stream has CDN Token Authentication enabled', 'bricksextras' ),
				'type'     => 'checkbox',
				'required' => array( array( 'provider', '!=', 'audio' ) ),
			);

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

			$this->controls['downloadSep'] = array(
				'tab'         => 'content',
				'label'       => esc_html__( 'Downloads', 'bricks' ),
				'description' => esc_html__( 'Optionally add extra download options for the media (for use with the download control)', 'bricksextras' ),
				'type'        => 'separator',
				'group'       => 'downloads',
			);

			$this->controls['downloadAttributes'] = array(
				'group'       => 'downloads',
				'type'        => 'repeater',
				'placeholder' => esc_html__( 'Download', 'bricks' ),
				'fields'      => array(
					'downloads_id' => array(
						'label'       => esc_html__( 'ID', 'bricks' ),
						'type'        => 'text',
						'placeholder' => 'mp3-version',
						'description' => esc_html__( 'Unique identifier for this download (use in download button settings)', 'bricksextras' ),
					),

					'url'          => array(
						'label'       => esc_html__( 'URL', 'bricks' ),
						'type'        => 'text',
						'placeholder' => 'https://...',
					),
					'title'        => array(
						'label'       => esc_html__( 'Name', 'bricks' ) . ' (' . esc_html__( 'optional', 'bricks' ) . ')',
						'type'        => 'text',
						'placeholder' => '',
					),
				),
			);
	}



	/**
	 * Get nestable children.
	 */
	public function get_nestable_children() {
		return array(
			array(
				'name'     => 'block',
				'settings' => array(
					'text' => esc_html__( 'Item description goes here', 'bricksextras' ),
				),
				'children' => array(
					array(
						'name'     => 'text-basic',
						'settings' => array(
							'text' => esc_html__( 'Item description goes here', 'bricksextras' ),
						),
					),
				),
			),

		);
	}


	/**
	 * Get normalized image settings.
	 *
	 * @param array $settings Element settings.
	 */
	public function get_normalized_image_settings( $settings ) {

		if ( empty( $settings['image'] ) ) {
			return array(
				'id'   => 0,
				'url'  => false,
				'size' => \BRICKS_DEFAULT_IMAGE_SIZE,
			);
		}

		$image = $settings['image'];

		// Size.
		$image['size'] = empty( $image['size'] ) ? \BRICKS_DEFAULT_IMAGE_SIZE : $settings['image']['size'];

		// Image ID or URL from dynamic data.
		if ( ! empty( $image['useDynamicData'] ) ) {

			$images = $this->render_dynamic_data_tag( $image['useDynamicData'], 'image', array( 'size' => $image['size'] ) );

			if ( ! empty( $images[0] ) ) {
				if ( is_numeric( $images[0] ) ) {
					$image['id'] = $images[0];
				} else {
					$image['url'] = $images[0];
				}
			}
		}

		$image['id'] = empty( $image['id'] ) ? 0 : $image['id'];

		// If External URL, $image['url'] is already set.
		if ( ! isset( $image['url'] ) ) {
			$image['url'] = ! empty( $image['id'] ) ? wp_get_attachment_image_url( $image['id'], $image['size'] ) : false;
		}

		return $image;
	}


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

		$settings = $this->settings;

		// Get the provider type (audio or video).
		$provider = isset( $settings['provider'] ) ? esc_attr( $settings['provider'] ) : 'video';

		// Define default sources based on provider type.
		$default_audio_src = 'https://files.vidstack.io/sprite-fight/audio.mp3';
		$default_video_src = 'https://files.vidstack.io/sprite-fight/hls/stream.m3u8';

		// Get the source type (media library or URL).
		$source_type = isset( $settings['sourceType'] ) ? $settings['sourceType'] : 'url';

		// Set a flag to track if we've found a valid source.
		$source_found = false;
		$src          = '';

		// Get the original source URL based on source type.
		if ( 'media' === $source_type ) {
			if ( 'audio' === $provider && isset( $settings['audio']['url'] ) && ! empty( $settings['audio']['url'] ) ) {
					// Get URL from audio setting when provider is audio.
				$src          = esc_url( $settings['audio']['url'] );
				$source_found = true;
			} elseif ( 'audio' !== $provider && isset( $settings['media']['url'] ) && ! empty( $settings['media']['url'] ) ) {
					// Get URL from media setting when provider is video.
				$src          = esc_url( $settings['media']['url'] );
				$source_found = true;
			}
		} elseif ( isset( $settings['src'] ) && ! empty( $settings['src'] ) ) {
			// Get URL from src field.
			$src_setting  = $settings['src'];
			$src          = strstr( $src_setting, '{' ) ? $this->render_dynamic_data_tag( $src_setting, 'text' ) : $src_setting;
			$source_found = true;
		}

		// If no source was found, use the default source based on provider type.
		if ( ! $source_found ) {
			$src = ( 'audio' === $provider ) ? $default_audio_src : $default_video_src;
		}

		// Check if we need to secure the video URL.
		if ( class_exists( '\BricksExtras\BricksExtrasVideo' ) ) {
			$src = apply_filters( 'bricksextras/video/src', $src, $settings );
		}

		if ( isset( $settings['multipleSources'] ) && 'url' === $source_type ) {

			$additional_sources = array();

			$repeater_key = ( 'video' === $provider ) ? 'srcRepeater' : 'srcRepeaterAudio';

			$type_default = ( 'video' === $provider ) ? 'video/mp4' : 'audio/mpeg';

			if ( ! empty( $settings[ $repeater_key ] ) && is_array( $settings[ $repeater_key ] ) ) {

				foreach ( $settings[ $repeater_key ] as $item ) {

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

					$source = array(
						'src'  => esc_url( bricks_render_dynamic_data( $item['source'] ) ),
						'type' => isset( $item['type'] ) ? esc_attr( bricks_render_dynamic_data( $item['type'] ) ) : $type_default,
					);

					if ( 'video' === $provider ) {
						$source['width'] = isset( $item['width'] ) && is_numeric( $item['width'] )
						? absint( bricks_render_dynamic_data( $item['width'] ) )
						: 1000;

						if ( isset( $item['height'] ) && is_numeric( $item['height'] ) ) {
							$source['height'] = absint( bricks_render_dynamic_data( $item['height'] ) );
						}
					}

					$additional_sources[] = $source;
				}
			}

				// Only set attribute if we have sources.
			if ( ! empty( $additional_sources ) ) {
				$this->set_attribute( '_root', 'data-x-srcs', wp_json_encode( $additional_sources ) );
			}
		}

			// Output download attributes if set.
		if ( isset( $settings['downloadAttributes'] ) && is_array( $settings['downloadAttributes'] ) && ! empty( $settings['downloadAttributes'] ) ) {
			$download_attributes = array();

			foreach ( $settings['downloadAttributes'] as $item ) {
				$download = array();

				if ( isset( $item['downloads_id'] ) ) {
					$rendered_id    = bricks_render_dynamic_data( $item['downloads_id'] );
					$download['id'] = sanitize_key( $rendered_id );
				}
				if ( isset( $item['title'] ) ) {
					$rendered_title    = bricks_render_dynamic_data( $item['title'] );
					$download['title'] = esc_attr( $rendered_title );
				}
				if ( isset( $item['url'] ) ) {
					$rendered_url    = bricks_render_dynamic_data( $item['url'] );
					$download['url'] = esc_url( $rendered_url, array( 'http', 'https' ) );
				}

				if ( ! empty( $download ) && ! empty( $download['id'] ) ) {
					$download_attributes[] = $download;
				}
			}

			if ( ! empty( $download_attributes ) ) {
				$download_attributes_json = htmlspecialchars(
					wp_json_encode( $download_attributes, JSON_HEX_APOS | JSON_HEX_QUOT ),
					ENT_QUOTES,
					'UTF-8'
				);

				$this->set_attribute( '_root', 'data-x-downloads', $download_attributes_json );
			}
		}

		$title  = isset( $settings['title'] ) ? bricks_render_dynamic_data( $settings['title'] ) : false;
		$artist = isset( $settings['artist'] ) ? bricks_render_dynamic_data( $settings['artist'] ) : false;

		$image      = $this->get_normalized_image_settings( $this->settings );
		$image_id   = $image['id'];
		$image_url  = $image['url'];
		$image_size = $image['size'];

		$text_tracks = ! empty( $settings['textTracks'] ) ? $settings['textTracks'] : false;

		$clip_start = isset( $settings['clipStart'] ) ? $settings['clipStart'] : false;
		$clip_end   = isset( $settings['clipEnd'] ) ? $settings['clipEnd'] : false;

		$clip_start_time = $clip_start ? \BricksExtras\Helpers::time_to_seconds( $this->render_dynamic_data( $clip_start ) ) : false;
		$clip_end_time   = $clip_end ? \BricksExtras\Helpers::time_to_seconds( $this->render_dynamic_data( $clip_end ) ) : false;

		$thumbnail_file = isset( $settings['thumbnailFile'] ) ? bricks_render_dynamic_data( $settings['thumbnailFile'] ) : false;

		$this->set_attribute( 'x-media-player-playlist_inner', 'class', 'x-media-player-playlist_inner' );

		$this->set_attribute( '_root', 'data-x-item-paused', 'true' );

		if ( ! empty( $src ) ) {
			$this->set_attribute( '_root', 'data-x-src', esc_url( $src ) );
		}

		// Add media type if specified (for URLs without file extensions).
		if ( isset( $settings['srcMediaType'] ) && ! empty( $settings['srcMediaType'] ) ) {
			$this->set_attribute( '_root', 'data-x-src-type', esc_attr( bricks_render_dynamic_data( $settings['srcMediaType'] ) ) );
		}

		$stream_type = isset( $settings['streamType'] ) ? bricks_render_dynamic_data( $settings['streamType'] ) : 'on-demand';
		$this->set_attribute( '_root', 'data-x-stream-type', esc_attr( $stream_type ) );

		if ( (bool) $title ) {
			$this->set_attribute( '_root', 'data-x-title', esc_attr( $title ) );
		}

		if ( (bool) $artist && 'audio' === $provider ) {
			$this->set_attribute( '_root', 'data-x-artist', esc_attr( $artist ) );
		}

		if ( $image_url ) {
			$this->set_attribute( '_root', 'data-x-poster', esc_url( $image_url ) );
		}

		if ( $clip_start_time ) {
			$this->set_attribute( '_root', 'data-x-clip-start', esc_attr( $clip_start_time ) );
		}

		if ( $clip_end_time ) {
			$this->set_attribute( '_root', 'data-x-clip-end', esc_attr( $clip_end_time ) );
		}

		if ( $thumbnail_file ) {
			$this->set_attribute( '_root', 'data-x-thumbnails', esc_url( $thumbnail_file ) );
		}

		/* Get cached poster for YouTube/Vimeo videos */
		if ( 'video' === $provider && ! $image_url && ! empty( $src ) ) {
			// 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 ) {
				// Use helper function to get cached poster.
				$poster_data = \BricksExtras\BricksExtrasMedia::get_video_poster( $src );

				if ( $poster_data && is_array( $poster_data ) && isset( $poster_data['url'] ) ) {
					$this->set_attribute( '_root', 'data-x-poster', esc_url( $poster_data['url'] ) );
				}
			}
		}

		$text_track_config = array();

		if ( $text_tracks ) {

			foreach ( $text_tracks as $index => $text_track ) {

				$label    = ! empty( $text_track['label'] ) ? $this->render_dynamic_data( $text_track['label'] ) : 'English';
				$src      = ! empty( $text_track['src'] ) ? $this->render_dynamic_data( $text_track['src'] ) : 'https://media-files.vidstack.io/sprite-fight/subs/english.vtt';
				$kind     = ! empty( $text_track['kind'] ) ? $text_track['kind'] : 'subtitles';
				$language = ! empty( $text_track['language'] ) ? $this->render_dynamic_data( $text_track['language'] ) : 'English';

				$default = 0 === $index ? 'default' : '';

				$text_track_config[] = array(
					'label'    => $label,
					'src'      => esc_url( $src ),
					'kind'     => $kind,
					'language' => $language,
				);

			}
		}

		if ( count( $text_track_config ) !== 0 ) {
			$this->set_attribute( '_root', 'data-x-texttracks', wp_json_encode( $text_track_config ) );
		}

		/* chapters from dynamic data */

		$chapters      = ! empty( $this->settings['chapters'] ) ? $this->settings['chapters'] : false;
		$chapter_text  = isset( $settings['chapterText'] ) ? $settings['chapterText'] : '';
		$chapter_start = isset( $settings['chapterStart'] ) ? $settings['chapterStart'] : '';
		$chapter_end   = isset( $settings['chapterEnd'] ) ? $settings['chapterEnd'] : '';

		$chapters_array = array();

		// Query Loop.
		if ( isset( $this->settings['hasLoop'] ) ) {

			$query = new \Bricks\Query(
				array(
					'id'       => $this->id,
					'settings' => $settings,
				)
			);

				$chapter_text  = isset( $this->settings['chapterText'] ) ? $this->settings['chapterText'] : '';
				$chapter_start = isset( $this->settings['chapterStart'] ) ? $this->settings['chapterStart'] : '';
				$chapter_end   = isset( $this->settings['chapterEnd'] ) ? $this->settings['chapterEnd'] : '';

				$chapters_array = $query->render( array( $this, 'chapter_repeater_item' ), array( $chapter_text, $chapter_start, $chapter_end ), true );

				$query->destroy();
				unset( $query );

		} elseif ( (bool) $chapters ) {

			foreach ( $this->settings['chapters'] as $index => $chapter ) {

				$chapter_text  = isset( $chapter['text'] ) ? $chapter['text'] : '';
				$chapter_start = isset( $chapter['startTime'] ) ? $chapter['startTime'] : '';
				$chapter_end   = isset( $chapter['endTime'] ) ? $chapter['endTime'] : '';

				$chapter_data = array(
					'text'      => $chapter_text,
					'startTime' => \BricksExtras\Helpers::time_to_seconds( $this->render_dynamic_data( $chapter_start ) ),
					'endTime'   => \BricksExtras\Helpers::time_to_seconds( $this->render_dynamic_data( $chapter_end ) ),
				);

				array_push( $chapters_array, $chapter_data );

			}
		}

			// Filter the chapters array to only keep valid chapter objects.
		$chapters_array = array_filter(
			$chapters_array,
			function ( $item ) {
				// Only keep items that are arrays (objects) with the expected chapter structure.
				return is_array( $item ) &&
				isset( $item['text'] ) &&
				isset( $item['startTime'] ) &&
				isset( $item['endTime'] );
			}
		);

			// Re-index the array to ensure sequential numeric keys.
		$chapters_array = array_values( $chapters_array );

		/* Ignore if less than 2 chapters or playlist element is not on-demand. */
		if ( 2 <= count( $chapters_array ) && 'on-demand' === $stream_type ) {
			$this->set_attribute( '_root', 'data-x-chapters', wp_json_encode( $chapters_array ) );
		}

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

		$this->set_attribute( '_root', 'aria-current', 'false' );

		$output = '';

		$output .= "<button {$this->render_attributes( '_root' )}>";

		$output .= \Bricks\Frontend::render_children( $this );

		$output .= '</button>';

		echo $output;
	}



	/**
	 * Chapter repeater item.
	 *
	 * @param string $chapter_text Chapter text content.
	 * @param string $chapter_start Chapter start time.
	 * @param string $chapter_end Chapter end time.
	 */
	public function chapter_repeater_item( $chapter_text, $chapter_start, $chapter_end ) {

		$settings = $this->settings;
		$index    = $this->loop_index;

			// Render.
		ob_start();

		$start_time = \BricksExtras\Helpers::time_to_seconds( $this->render_dynamic_data( $chapter_start ) );
		$end_time   = \BricksExtras\Helpers::time_to_seconds( $this->render_dynamic_data( $chapter_end ) );

		$chapter_data = array(
			'text'      => $this->render_dynamic_data( $chapter_text ),
			'startTime' => $start_time,
			'endTime'   => $end_time,
		);

		$html = ob_get_clean();

		++$this->loop_index;

		return $chapter_data;
	}

	/**
	 * Render builder template.
	 */
	public static function render_builder() {

		?>

			<script type="text/x-template" id="tmpl-bricks-element-xmediaplaylist">
				<button>
				<bricks-element-children
					:element="element"
				/>
				</button>
			</script>

		<?php
	}
}
