<?php
/**
 * Minimal Inline Assets Printer (NO wp_head/wp_footer hooks)
 *
 * - Prints <style>/<script> immediately where you call it.
 * - Optional de-dupe by $key (so the same payload is printed only once per request).
 *
 * IMPORTANT:
 * This is NOT “Elementor-safe” by design. It outputs inline tags at the call site.
 *
 * Usage (prints immediately where called):
 *
 * WPBC_FE_Assets::add_inline_css( $css, 'wpbc_calendar_loader_inline_css' );
 * WPBC_FE_Assets::add_jq_ready_js( $js_body, 'wpbc:calendar-loader:init' );
 *
 * @file: includes/fontend/class-fe-inline-css-js.php
 * @package Booking Calendar
 * @since   11.0.x
 */

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

class WPBC_FE_Assets {

	const CSS_TAG_ID_BASE = 'wpbc-inline-css';
	const JS_TAG_ID_BASE  = 'wpbc-inline-js';

	/** @var array */
	protected static $printed_css = array();

	/** @var array */
	protected static $printed_js  = array();

	/**
	 * Print inline CSS immediately (deduped by key).
	 *
	 * @param string $css
	 * @param string $key  Unique key to prevent duplicate output. If empty, derived from content hash.
	 *
	 * @return void
	 */
	public static function add_inline_css( $css, $key = '' ) {

		$css = is_scalar( $css ) ? trim( (string) $css ) : '';
		if ( '' === $css ) {
			return;
		}

		$key = self::normalize_key( $key, $css, 'css' );
		if ( isset( self::$printed_css[ $key ] ) ) {
			return;
		}
		self::$printed_css[ $key ] = true;

		$id = self::safe_dom_id( self::CSS_TAG_ID_BASE . '-' . $key );

		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		return "\n" . '<style id="' . esc_attr( $id ) . '">' . "\n" . $css . "\n" . '</style>' . "\n";
	}

	/**
	 * Print inline JS immediately (deduped by key).
	 *
	 * @param string $js
	 * @param string $key  Unique key to prevent duplicate output. If empty, derived from content hash.
	 *
	 * @return void
	 */
	public static function add_inline_js( $js, $key = '' ) {

		$js = is_scalar( $js ) ? trim( (string) $js ) : '';
		if ( '' === $js ) {
			return;
		}

		$key = self::normalize_key( $key, $js, 'js' );
		if ( isset( self::$printed_js[ $key ] ) ) {
			return;
		}
		self::$printed_js[ $key ] = true;

		$id = self::safe_dom_id( self::JS_TAG_ID_BASE . '-' . $key );


		// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		return "\n" . '<script id="' . esc_attr( $id ) . '" type="text/javascript">' . "\n" . $js . "\n" . '</script>' . "\n";
	}

	/**
	 * Print JS wrapped into wpbc_jq_ready_start()/wpbc_jq_ready_end(), immediately.
	 *
	 * @param string $js_body
	 * @param string $key
	 *
	 * @return void
	 */
	public static function add_jq_ready_js( $js_body, $key = '' ) {

		$js_body = is_scalar( $js_body ) ? trim( (string) $js_body ) : '';
		if ( '' === $js_body ) {
			return;
		}

		if ( ';' !== substr( $js_body, -1 ) ) {
			$js_body .= ';';
		}

		$js = wpbc_jq_ready_start() . "\n" . $js_body . "\n" . wpbc_jq_ready_end();

		return self::add_inline_js( $js, $key );
	}

	// ------------------------------------------------------------------------------------------------
	// Internals
	// ------------------------------------------------------------------------------------------------

	/**
	 * Normalize de-dupe key. If empty, use deterministic hash from content.
	 *
	 * @param string $key
	 * @param string $content
	 * @param string $type  'css'|'js'
	 *
	 * @return string
	 */
	protected static function normalize_key( $key, $content, $type ) {

		$key = is_scalar( $key ) ? trim( (string) $key ) : '';
		if ( '' !== $key ) {
			return $key;
		}

		return (string) $type . '-' . md5( (string) $content );
	}

	/**
	 * Make a safe DOM id (ASCII, simple).
	 *
	 * @param string $id
	 *
	 * @return string
	 */
	protected static function safe_dom_id( $id ) {

		$id = strtolower( (string) $id );
		$id = preg_replace( '/[^a-z0-9\-\_]+/', '-', $id );
		$id = trim( $id, '-' );

		// Prevent extremely long ids.
		if ( strlen( $id ) > 80 ) {
			$id = substr( $id, 0, 80 );
		}

		if ( '' === $id ) {
			$id = 'wpbc-inline';
		}

		return $id;
	}
}
