<?php
/**
 * Template Registry
 *
 * @package The Studio Player
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * Locate a player template file for a given slug (metadata only).
 *
 * @param string $template Template slug.
 * @return string Absolute path to template file or empty string when missing.
 */
function thespl_locate_player_template( $template ) {
	$template = is_string( $template ) ? $template : '';
	$template = sanitize_key( $template );
	if ( '' === $template ) {
		return '';
	}

	$uploads = wp_upload_dir();
	if ( ! empty( $uploads['basedir'] ) && is_string( $uploads['basedir'] ) ) {
		$uploads_base      = trailingslashit( $uploads['basedir'] ) . 'the-studio-player/templates/player/';
		$uploads_candidate = $uploads_base . $template . '/player.php';
		if ( file_exists( $uploads_candidate ) ) {
			return $uploads_candidate;
		}
	}

	$base      = trailingslashit( THESPL_PLUGIN_DIR . 'templates/player' );
	$candidate = $base . $template . '/player.php';
	if ( file_exists( $candidate ) ) {
		return $candidate;
	}

	return '';
}

/**
 * Locate a player template file for rendering.
 *
 * Falls back to an empty string when the template is missing.
 *
 * @param string $template Template slug.
 * @return string Absolute path to template file or empty string on failure.
 */
function thespl_locate_player_template_for_render( $template ) {
	$template = is_string( $template ) ? $template : '';
	$template = sanitize_key( $template );
	if ( '' === $template ) {
		return '';
	}

	$entries = thespl_get_player_template_entries();
	if ( ! empty( $entries ) ) {
		foreach ( $entries as $entry ) {
			if ( ! isset( $entry['slug'] ) || $entry['slug'] !== $template ) {
				continue;
			}

			if ( empty( $entry['dir'] ) || ! is_string( $entry['dir'] ) ) {
				break;
			}

			$dir  = trailingslashit( $entry['dir'] );
			$file = $dir . 'player.php';
			if ( file_exists( $file ) ) {
				return $file;
			}

			break;
		}
	}

	$uploads = wp_upload_dir();
	if ( ! empty( $uploads['basedir'] ) && is_string( $uploads['basedir'] ) ) {
		$uploads_base      = trailingslashit( $uploads['basedir'] ) . 'the-studio-player/templates/player/';
		$uploads_candidate = $uploads_base . $template . '/player.php';
		if ( file_exists( $uploads_candidate ) ) {
			return $uploads_candidate;
		}
	}

	$base      = trailingslashit( THESPL_PLUGIN_DIR . 'templates/player' );
	$candidate = $base . $template . '/player.php';
	if ( file_exists( $candidate ) ) {
		return $candidate;
	}

	return '';
}

/**
 * Sanitize template header hex color and strip optional alpha channel.
 *
 * @param string $value Raw hex string from template header.
 * @return string Sanitized hex color or empty string.
 */
function thespl_sanitize_template_hex( $value ) {
	$value = is_string( $value ) ? trim( $value ) : '';
	if ( '' === $value ) {
		return '';
	}
	if ( '#' === $value[0] && strlen( $value ) > 7 ) {
		$value = substr( $value, 0, 7 );
	}
	$sanitized = sanitize_hex_color( $value );
	return is_string( $sanitized ) ? $sanitized : '';
}

/**
 * Parse a player template directory into a normalized descriptor.
 *
 * Validates the directory, derives slug and label, and detects a "(default)" marker in the folder name.
 *
 * @param string $dir    Absolute template directory path.
 * @param string $source Source identifier ('plugin' or 'uploads').
 * @return array|null {
 *     Parsed template descriptor or null when the directory is not a valid template.
 *
 *     @type string $slug               Template slug.
 *     @type string $label              Human-readable label.
 *     @type string $dir                Directory path (with trailing slash).
 *     @type string $source             'plugin' or 'uploads'.
 *     @type bool   $has_default_marker True when folder name includes a "(default)" marker.
 * }
 */
function thespl_parse_player_template_dir( $dir, $source ) {
	$source = is_string( $source ) ? $source : '';
	if ( '' === $source ) {
		return null;
	}
	$base = basename( $dir );
	if ( ! is_string( $base ) || '' === $base ) {
		return null;
	}
	if ( isset( $base[0] ) && '_' === $base[0] ) {
		return null;
	}
	if ( ! file_exists( trailingslashit( $dir ) . 'player.php' ) ) {
		return null;
	}
	$name               = $base;
	$has_default_marker = false;
	if ( preg_match( '/\(\s*default\s*\)\s*$/i', $name ) ) {
		$has_default_marker = true;
		$name               = preg_replace( '/\s*\(\s*default\s*\)\s*$/i', '', $name );
		$name               = rtrim( $name, " \t-_" );
	}
	$slug = sanitize_key( $name );
	if ( '' === $slug ) {
		return null;
	}
	$label = ucwords( str_replace( '-', ' ', $slug ) );
	return array(
		'slug'               => $slug,
		'label'              => $label,
		'dir'                => trailingslashit( $dir ),
		'source'             => $source,
		'has_default_marker' => $has_default_marker,
	);
}

/**
 * Discover and cache player template entries from plugin and uploads.
 *
 * Combines valid template directories into a list of descriptors, using a static in-memory cache.
 *
 * @return array List of template descriptor arrays as returned by thespl_parse_player_template_dir().
 */
function thespl_get_player_template_entries() {
	static $entries = null;
	if ( null !== $entries ) {
		return $entries;
	}
	$entries = array();

	$plugin_base = trailingslashit( THESPL_PLUGIN_DIR . 'templates/player' );
	$plugin_dirs = glob( $plugin_base . '*', GLOB_ONLYDIR );
	if ( is_array( $plugin_dirs ) ) {
		foreach ( $plugin_dirs as $dir ) {
			$parsed = thespl_parse_player_template_dir( $dir, 'plugin' );
			if ( is_array( $parsed ) ) {
				$entries[] = $parsed;
			}
		}
	}

	$uploads = wp_upload_dir();
	if ( ! empty( $uploads['basedir'] ) && is_string( $uploads['basedir'] ) ) {
		$uploads_base = trailingslashit( $uploads['basedir'] ) . 'the-studio-player/templates/player/';
		if ( is_dir( $uploads_base ) ) {
			$upload_dirs = glob( $uploads_base . '*', GLOB_ONLYDIR );
			if ( is_array( $upload_dirs ) ) {
				foreach ( $upload_dirs as $dir ) {
					$parsed = thespl_parse_player_template_dir( $dir, 'uploads' );
					if ( is_array( $parsed ) ) {
						$entries[] = $parsed;
					}
				}
			}
		}
	}

	return $entries;
}

/**
 * Resolve the default player template slug.
 *
 * Prefers uploads candidates with a "(default)" marker, otherwise falls back to plugin candidates,
 * or ultimately the first available slug in lexical order.
 *
 * @return string Default template slug or empty string when no templates exist.
 */
function thespl_get_default_template_slug() {
	static $default_slug = null;
	if ( null !== $default_slug ) {
		return $default_slug;
	}

	$entries = thespl_get_player_template_entries();
	if ( empty( $entries ) ) {
		$default_slug = '';
		return $default_slug;
	}

	$uploads_candidates = array();
	$plugin_candidates  = array();
	foreach ( $entries as $entry ) {
		if ( empty( $entry['has_default_marker'] ) || empty( $entry['slug'] ) ) {
			continue;
		}
		if ( isset( $entry['source'] ) && 'uploads' === $entry['source'] ) {
			$uploads_candidates[] = $entry['slug'];
		} elseif ( isset( $entry['source'] ) && 'plugin' === $entry['source'] ) {
			$plugin_candidates[] = $entry['slug'];
		}
	}

	if ( ! empty( $uploads_candidates ) ) {
		sort( $uploads_candidates );
		$default_slug = (string) $uploads_candidates[0];
		return $default_slug;
	}

	if ( ! empty( $plugin_candidates ) ) {
		sort( $plugin_candidates );
		$default_slug = (string) $plugin_candidates[0];
		return $default_slug;
	}

	$all_slugs = array();
	foreach ( $entries as $entry ) {
		if ( ! empty( $entry['slug'] ) ) {
			$all_slugs[] = $entry['slug'];
		}
	}
	if ( empty( $all_slugs ) ) {
		$default_slug = '';
		return $default_slug;
	}
	sort( $all_slugs );
	$default_slug = (string) $all_slugs[0];
	return $default_slug;
}
/**
 * Get asset base directory and URL for a player template.
 *
 * @param string $slug Template slug.
 * @return array{
 *   dir: string,
 *   url: string,
 *   slug: string,
 *   src: string
 * }
 */
function thespl_get_player_template_asset_base( $slug ) {
	$slug = is_string( $slug ) ? sanitize_key( $slug ) : '';

	$entries = thespl_get_player_template_entries();
	if ( '' !== $slug && ! empty( $entries ) ) {
		foreach ( $entries as $entry ) {
			if ( ! isset( $entry['slug'] ) || $entry['slug'] !== $slug ) {
				continue;
			}

			$dir = isset( $entry['dir'] ) && is_string( $entry['dir'] ) ? $entry['dir'] : '';
			$src = isset( $entry['source'] ) && is_string( $entry['source'] ) ? $entry['source'] : '';

			if ( '' === $dir ) {
				break;
			}

			$folder = basename( untrailingslashit( $dir ) );
			$url    = '';

			if ( 'uploads' === $src ) {
				$uploads = wp_upload_dir();
				if ( ! empty( $uploads['baseurl'] ) && is_string( $uploads['baseurl'] ) ) {
					$base_url = trailingslashit( $uploads['baseurl'] ) . 'the-studio-player/templates/player/';
					$url      = $base_url . $folder . '/';
				}
			} else {
				$url = trailingslashit( THESPL_PLUGIN_URL ) . 'templates/player/' . $folder . '/';
				$src = 'plugin';
			}

			if ( '' !== $url ) {
				return array(
					'dir'  => trailingslashit( $dir ),
					'url'  => $url,
					'slug' => $slug,
					'src'  => $src,
				);
			}

			break;
		}
	}

	$uploads = wp_upload_dir();
	if ( ! empty( $uploads['basedir'] ) && ! empty( $uploads['baseurl'] ) && is_string( $uploads['basedir'] ) && is_string( $uploads['baseurl'] ) ) {
		$uploads_dir = trailingslashit( $uploads['basedir'] ) . 'the-studio-player/templates/player/' . $slug . '/';
		$uploads_url = trailingslashit( $uploads['baseurl'] ) . 'the-studio-player/templates/player/' . $slug . '/';
		if ( file_exists( $uploads_dir . 'style.css' ) || file_exists( $uploads_dir . 'script.js' ) ) {
			return array(
				'dir'  => $uploads_dir,
				'url'  => $uploads_url,
				'slug' => $slug,
				'src'  => 'uploads',
			);
		}
	}

	$plugin_dir = trailingslashit( THESPL_PLUGIN_DIR ) . 'templates/player/' . $slug . '/';
	$plugin_url = trailingslashit( THESPL_PLUGIN_URL ) . 'templates/player/' . $slug . '/';

	return array(
		'dir'  => $plugin_dir,
		'url'  => $plugin_url,
		'slug' => $slug,
		'src'  => 'plugin',
	);
}

/**
 * Discover available player templates from plugin and uploads Verzeichnis.
 *
 * @return array Zuordnung von Template-Slug zu Label.
 */
function thespl_get_available_player_templates() {
	$out     = array();
	$entries = thespl_get_player_template_entries();
	if ( empty( $entries ) ) {
		return $out;
	}
	foreach ( $entries as $entry ) {
		if ( empty( $entry['slug'] ) || ! isset( $entry['label'] ) ) {
			continue;
		}
		if ( ! isset( $out[ $entry['slug'] ] ) ) {
			$out[ $entry['slug'] ] = $entry['label'];
		}
	}

	return $out;
}

/**
 * Get a human readable template title for a given slug.
 *
 * @param string $slug Template slug.
 * @return string
 */
function thespl_get_player_template_title( $slug ) {
	$slug = is_string( $slug ) ? sanitize_key( $slug ) : '';

	$templates = thespl_get_available_player_templates();
	$base      = isset( $templates[ $slug ] ) && is_string( $templates[ $slug ] ) && '' !== $templates[ $slug ]
		? $templates[ $slug ]
		: ucwords( str_replace( '-', ' ', $slug ) );

	/* translators: %s: Template title based on the template slug. */
	return sprintf( __( '%s-Template', 'the-studio-player' ), $base );
}

/**
 * Prüft, ob ein Template-Slug auf ein vorhandenes Template verweist.
 *
 * @param string $template Template-Slug.
 * @return bool True, wenn ein Template gefunden wurde.
 */
function thespl_template_slug_is_valid( $template ) {
	$template = is_string( $template ) ? sanitize_key( $template ) : '';
	if ( '' === $template ) {
		return false;
	}

	$entries = thespl_get_player_template_entries();
	if ( empty( $entries ) ) {
		return false;
	}
	foreach ( $entries as $entry ) {
		if ( isset( $entry['slug'] ) && $template === $entry['slug'] ) {
			return true;
		}
	}

	return false;
}

/**
 * Resolve player template files from plugin and uploads.
 *
 * @param string $template Template slug.
 * @return array
 */
function thespl_template_resolve_files( $template ) {
	$template = is_string( $template ) ? sanitize_key( $template ) : '';

	$plugin_file  = '';
	$uploads_file = '';

	$uploads = wp_upload_dir();
	if ( ! empty( $uploads['basedir'] ) && is_string( $uploads['basedir'] ) ) {
		$uploads_base      = trailingslashit( $uploads['basedir'] ) . 'the-studio-player/templates/player/';
		$uploads_candidate = $uploads_base . $template . '/player.php';
		if ( file_exists( $uploads_candidate ) ) {
			$uploads_file = $uploads_candidate;
		}
	}

	$plugin_base      = trailingslashit( THESPL_PLUGIN_DIR . 'templates/player' );
	$plugin_candidate = $plugin_base . $template . '/player.php';
	if ( file_exists( $plugin_candidate ) ) {
		$plugin_file = $plugin_candidate;
	}

	return array(
		'plugin'  => $plugin_file,
		'uploads' => $uploads_file,
	);
}

/**
 * Read template header fields from plugin and uploads files.
 *
 * @param string $template Template slug.
 * @param array  $fields   Header fields to read.
 * @return array
 */
function thespl_template_get_header_map( $template, $fields ) {
	$template = is_string( $template ) ? sanitize_key( $template ) : '';

	if ( ! is_array( $fields ) || empty( $fields ) ) {
		return array();
	}

	if ( ! function_exists( 'get_file_data' ) ) {
		return array();
	}

	$files = thespl_template_resolve_files( $template );

	$plugin_data  = array();
	$uploads_data = array();

	if ( isset( $files['plugin'] ) && '' !== $files['plugin'] && file_exists( $files['plugin'] ) ) {
		$plugin_data = get_file_data(
			$files['plugin'],
			$fields,
			'thespl'
		);
	}

	if ( isset( $files['uploads'] ) && '' !== $files['uploads'] && file_exists( $files['uploads'] ) ) {
		$uploads_data = get_file_data(
			$files['uploads'],
			$fields,
			'thespl'
		);
	}

	$out = array();

	foreach ( $fields as $key => $label ) {
		$value = '';
		if ( isset( $plugin_data[ $key ] ) && '' !== (string) $plugin_data[ $key ] ) {
			$value = (string) $plugin_data[ $key ];
		}
		if ( isset( $uploads_data[ $key ] ) && '' !== (string) $uploads_data[ $key ] ) {
			$value = (string) $uploads_data[ $key ];
		}
		if ( '' !== $value ) {
			$out[ $key ] = $value;
		}
	}

	return $out;
}

/**
 * Check whether a template allows user CSS overrides.
 *
 * This is read from the template file header:
 * "Allow User CSS Overrides: true|false".
 *
 * @param string $template Template slug.
 * @return bool
 */
function thespl_template_allows_user_css_overrides( $template ) {
	$template = is_string( $template ) ? sanitize_key( $template ) : '';

	$fields = array(
		'allow_user_css_overrides'          => 'Allow User CSS Overrides',
		'allow_user_css_overrides_alt'      => 'CSS Overwrite',
		'allow_user_css_overrides_alt_safe' => 'Allow CSS Overrides',
	);

	$data = thespl_template_get_header_map( $template, $fields );

	$raw = '';
	if ( isset( $data['allow_user_css_overrides'] ) && '' !== (string) $data['allow_user_css_overrides'] ) {
		$raw = (string) $data['allow_user_css_overrides'];
	} elseif ( isset( $data['allow_user_css_overrides_alt'] ) && '' !== (string) $data['allow_user_css_overrides_alt'] ) {
		$raw = (string) $data['allow_user_css_overrides_alt'];
	} elseif ( isset( $data['allow_user_css_overrides_alt_safe'] ) && '' !== (string) $data['allow_user_css_overrides_alt_safe'] ) {
		$raw = (string) $data['allow_user_css_overrides_alt_safe'];
	}
	$raw = strtolower( trim( $raw ) );
	if ( '' === $raw ) {
		return true;
	}

	$true_values  = array( '1', 'true', 'yes', 'on' );
	$false_values = array( '0', 'false', 'no', 'off' );
	if ( in_array( $raw, $true_values, true ) ) {
		return true;
	}
	if ( in_array( $raw, $false_values, true ) ) {
		return false;
	}

	return true;
}

/**
 * Liest einen booleschen Header-Wert aus der Template-Datei.
 *
 * @param string $template     Template-Slug.
 * @param string $header_label Header-Bezeichner im File-Header.
 * @return bool|null True/False bei gültigem Wert, sonst null.
 */
function thespl_template_get_bool_header( $template, $header_label ) {
	$template     = is_string( $template ) ? sanitize_key( $template ) : '';
	$header_label = is_string( $header_label ) ? $header_label : '';
	if ( '' === $header_label ) {
		return null;
	}

	$fields = array(
		'value' => $header_label,
	);
	$data   = thespl_template_get_header_map( $template, $fields );
	$raw    = isset( $data['value'] ) ? (string) $data['value'] : '';
	$raw    = strtolower( trim( $raw ) );
	if ( '' === $raw ) {
		return null;
	}

	$true_values  = array( '1', 'true', 'yes', 'on' );
	$false_values = array( '0', 'false', 'no', 'off' );
	if ( in_array( $raw, $true_values, true ) ) {
		return true;
	}
	if ( in_array( $raw, $false_values, true ) ) {
		return false;
	}

	return null;
}

/**
 * Build normalized template metadata and capabilities.
 *
 * @param string $template Template slug.
 * @return array
 */
function thespl_template_get_meta( $template ) {
	$template = is_string( $template ) ? sanitize_key( $template ) : '';

	$meta = array(
		'slug'         => $template,
		'capabilities' => array(
			'has_audio_info_panel'      => true,
			'allows_user_css_overrides' => true,
		),
		'defaults'     => array(
			'show_playlist'   => null,
			'show_audio_info' => null,
			'colors'          => array(),
		),
	);

	$allows_overrides                                  = thespl_template_allows_user_css_overrides( $template );
	$meta['capabilities']['allows_user_css_overrides'] = $allows_overrides ? true : false;

	$audio_pref = thespl_template_get_bool_header( $template, 'Show Audio Info' );
	if ( null !== $audio_pref ) {
		$meta['defaults']['show_audio_info'] = (bool) $audio_pref;
	}

	$playlist_pref = thespl_template_get_bool_header( $template, 'Show Playlist' );
	if ( null !== $playlist_pref ) {
		$meta['defaults']['show_playlist'] = (bool) $playlist_pref;
	}

	$panel_support = thespl_template_get_bool_header( $template, 'Has Audio Info Panel' );
	if ( null === $panel_support ) {
		$meta['capabilities']['has_audio_info_panel'] = true;
	} else {
		$meta['capabilities']['has_audio_info_panel'] = (bool) $panel_support;
	}

	$color_fields = array(
		'accent_color'             => 'Default Accent Color',
		'accent_2_color'           => 'Default Accent 2 Color',
		'base_color'               => 'Default Base Color',
		'text_color'               => 'Default Text Color',
		'waveform_color'           => 'Default Waveform Color',
		'ring_base_color'          => 'Default Ring Base Color',
		'button_bg_color'          => 'Default Button Background Color',
		'button_text_color'        => 'Default Button Text Color',
		'button_active_bg_color'   => 'Default Button Active Background Color',
		'button_active_text_color' => 'Default Button Active Text Color',
		'chip_bg_color'            => 'Default Chip Background Color',
		'chip_br_color'            => 'Default Chip Border Color',
	);

	$buffer_fields = array(
		'buffer_ring_alpha' => 'Default Buffer Ring Alpha',
	);

	$color_data  = thespl_template_get_header_map( $template, $color_fields );
	$buffer_data = thespl_template_get_header_map( $template, $buffer_fields );

	$colors = array();

	foreach ( $color_fields as $key => $label ) {
		if ( isset( $color_data[ $key ] ) && is_string( $color_data[ $key ] ) && '' !== $color_data[ $key ] ) {
			$colors[ $key ] = thespl_sanitize_template_hex( $color_data[ $key ] );
		}
	}

	if ( isset( $buffer_data['buffer_ring_alpha'] ) && '' !== (string) $buffer_data['buffer_ring_alpha'] && is_numeric( $buffer_data['buffer_ring_alpha'] ) ) {
		$meta['defaults']['buffer_ring_alpha'] = (float) $buffer_data['buffer_ring_alpha'];
	}

	$meta['defaults']['colors'] = $colors;

	return $meta;
}

/**
 * Liefert die Template-Voreinstellung für "Show Audio Info".
 *
 * @param string $template Template-Slug.
 * @return bool|null Voreinstellung oder null, falls nicht gesetzt.
 */
function thespl_template_get_show_audio_info_pref( $template ) {
	$meta = thespl_template_get_meta( $template );
	if ( isset( $meta['defaults']['show_audio_info'] ) ) {
		return null === $meta['defaults']['show_audio_info'] ? null : (bool) $meta['defaults']['show_audio_info'];
	}

	return null;
}

/**
 * Liefert die Template-Voreinstellung für "Show Playlist".
 *
 * @param string $template Template-Slug.
 * @return bool|null Voreinstellung oder null, falls nicht gesetzt.
 */
function thespl_template_get_show_playlist_pref( $template ) {
	$meta = thespl_template_get_meta( $template );
	if ( isset( $meta['defaults']['show_playlist'] ) ) {
		return null === $meta['defaults']['show_playlist'] ? null : (bool) $meta['defaults']['show_playlist'];
	}

	return null;
}

/**
 * Check whether a template exposes an audio info panel.
 *
 * @param string $template Template slug.
 * @return bool
 */
function thespl_template_has_audio_info_panel( $template ) {
	$meta = thespl_template_get_meta( $template );
	if ( isset( $meta['capabilities']['has_audio_info_panel'] ) ) {
		return (bool) $meta['capabilities']['has_audio_info_panel'];
	}

	return true;
}

/**
 * Liefert Template-spezifische Design-Defaults für den Admin-Builder.
 *
 * Die Werte werden aus dem Header der Template-Datei gelesen.
 *
 * @param string $template Template-Slug.
 * @return array Assoziatives Array mit Keys wie 'accent_color', 'accent_2_color', 'base_color', 'text_color', 'waveform_color', 'ring_base_color'.
 */
function thespl_template_get_design_defaults( $template ) {
	$meta = thespl_template_get_meta( $template );
	$out  = array();

	if ( isset( $meta['defaults']['colors'] ) && is_array( $meta['defaults']['colors'] ) ) {
		foreach ( $meta['defaults']['colors'] as $key => $value ) {
			if ( is_string( $value ) && '' !== $value ) {
				$out[ $key ] = $value;
			}
		}
	}

	if ( isset( $meta['defaults']['buffer_ring_alpha'] ) && is_numeric( $meta['defaults']['buffer_ring_alpha'] ) ) {
		$out['buffer_ring_alpha'] = (float) $meta['defaults']['buffer_ring_alpha'];
	}

	return $out;
}

/**
 * Render a generic player notice card.
 *
 * @param string $title Notice title.
 * @param string $body  Notice body text.
 * @return string Rendered HTML.
 */
function thespl_render_player_notice_card( $title, $body ) {
	$title = is_string( $title ) ? $title : '';
	$body  = is_string( $body ) ? $body : '';
	$name  = esc_html__( 'The Studio Player', 'the-studio-player' );
	$copy  = esc_html__( '© Peter Rahe', 'the-studio-player' );
	$ver   = defined( 'THESPL_VERSION' ) ? (string) THESPL_VERSION : '';

	$html  = '<div class="thespl-player thespl-player--error">';
	$html .= '<div class="thespl-player__notice" role="status">';
	$html .= '<strong>' . esc_html( $title ) . '</strong>';
	if ( '' !== $body ) {
		$html .= '<br />';
		$html .= esc_html( $body );
	}
	$html .= '</div>';
	$html .= '<div class="thespl-player__metafoot">';
	$html .= '<span class="thespl-player__metafoot-prefix">' . $name . '</span>';
	if ( '' !== $ver ) {
		$html .= '<span class="thespl-player__metafoot-sep"> | </span>';
		$html .= '<span class="thespl-player__metafoot-version">' . esc_html( $ver ) . '</span>';
	}
	$html .= '<span class="thespl-player__metafoot-sep"> | </span>';
	$html .= '<span class="thespl-player__metafoot-copy">' . $copy . '</span>';
	$html .= '</div>';
	$html .= '</div>';

	return $html;
}

/**
 * Render the unavailable player notice.
 *
 * @param string $message Unavailable message.
 * @return string Rendered HTML.
 */
function thespl_render_player_unavailable_notice( $message ) {
	$title   = esc_html__( 'The Studio Player', 'the-studio-player' );
	$message = is_string( $message ) ? $message : '';

	return thespl_render_player_notice_card( $title, $message );
}

/**
 * Render a player template with provided context variables.
 *
 * @param string $template Template slug.
 * @param array  $context  Context variables for the template.
 * @return string Rendered HTML.
 */
function thespl_render_player_template( $template, array $context ) {
	$title = esc_html__( 'The Studio Player could not render the selected player template.', 'the-studio-player' );
	$body  = esc_html__( 'The player template is missing, was renamed, or contains a fatal error. Please restore the template folder or reinstall the plugin templates.', 'the-studio-player' );

	$file = thespl_locate_player_template_for_render( $template );
	if ( '' === $file || ! file_exists( $file ) ) {
		return thespl_render_player_notice_card( $title, $body );
	}

	ob_start();
	$thespl_context = $context;
	try {
		include $file;
	} catch ( \Throwable $e ) {
		ob_end_clean();
		return thespl_render_player_notice_card( $title, $body );
	}

	return (string) ob_get_clean();
}
