<?php
/**
 * Asset loading class.
 *
 * @package PRECO
 */

namespace PRECO\Includes\Common;

defined( 'ABSPATH' ) || exit;

/**
 * Centralizes style/script enqueueing so handles, paths and dependency
 * resolution follow one consistent pattern across the plugin.
 */
class AssetLoader {

	/**
	 * Enqueue style
	 *
	 * @param string $handle handle.
	 * @param string $style_name style name.
	 * @param array  $deps dependencies.
	 * @return void
	 */
	public static function enqueue_style( $handle, $style_name, $deps = array() ) {
		wp_enqueue_style(
			$handle,
			self::get_style_path( $style_name ),
			$deps,
			PRECO_VER
		);
	}

	/**
	 * Load style path
	 *
	 * @param string $style_name style name.
	 * @return string
	 */
	public static function get_style_path( $style_name ) {
		return PRECO_URL . 'assets/css/' . $style_name . ( is_rtl() ? '-rtl' : '' ) . '.css';
	}

	/**
	 * Add inline CSS after a registered/enqueued style handle.
	 *
	 * @param string $handle Style handle to attach to.
	 * @param string $css    Raw CSS declarations.
	 * @return void
	 */
	public static function add_inline_style( $handle, $css ) {
		if ( empty( $css ) ) {
			return;
		}

		wp_add_inline_style( $handle, $css );
	}

	/**
	 * Enqueue script
	 *
	 * @param string $handle handle.
	 * @param string $script_name script name.
	 * @param array  $args args.
	 * @param array  $extra_deps Additional dependency handles to merge in
	 *                           alongside those read from the build's .asset.php
	 *                           (e.g. another plugin script handle).
	 * @return void
	 */
	public static function enqueue_script( $handle, $script_name, $args = true, $extra_deps = array() ) {
		$relative_js_path = 'assets/js/' . $script_name . '.js';
		$script_url       = PRECO_URL . $relative_js_path;
		$assets           = self::get_script_asset( $relative_js_path );
		// Filter out non-WordPress dependencies like 'react-jsx-runtime' and fix truncated handles.
		$filtered_deps = array_filter(
			$assets['dependencies'],
			function ( $dep ) {
				return strpos( $dep, 'react-' ) !== 0;
			}
		);
		$filtered_deps = array_map(
			function ( $dep ) {
				if ( $dep === 'wp-i18' ) {
						return 'wp-i18n';
				}
				return $dep;
			},
			$filtered_deps
		);
		$filtered_deps = array_unique( array_merge( $filtered_deps, $extra_deps ) );
		wp_enqueue_script( $handle, $script_url, $filtered_deps, $assets['version'], $args );
	}

	/**
	 * Read a wp-scripts generated asset file for a built script.
	 *
	 * WP Scripts (DependencyExtractionWebpackPlugin) generates a sibling
	 * `{entry}.asset.php` file containing `dependencies` and `version`.
	 *
	 * @param string $relative_js_path Relative JS path inside the plugin, e.g. 'assets/js/frontend-script.js'.
	 * @param array  $fallback_deps    Dependencies to use if the asset file does not exist.
	 *
	 * @return array { dependencies: string[], version: string }
	 */
	public static function get_script_asset( $relative_js_path, $fallback_deps = array() ) {
		$relative_js_path = ltrim( (string) $relative_js_path, '/\\' );
		$asset_path       = preg_replace( '/\\.js$/', '.asset.php', $relative_js_path );
		$asset_file       = trailingslashit( PRECO_PATH ) . str_replace( array( '\\', '//' ), '/', $asset_path );

		$asset = null;
		if ( $asset_file && file_exists( $asset_file ) ) {
			$asset = include $asset_file;
		}

		if ( is_array( $asset ) && isset( $asset['dependencies'], $asset['version'] ) ) {
			return array(
				'dependencies' => is_array( $asset['dependencies'] ) ? $asset['dependencies'] : array(),
				'version'      => (string) $asset['version'],
			);
		}

		return array(
			'dependencies' => is_array( $fallback_deps ) ? $fallback_deps : array(),
			'version'      => defined( 'PRECO_VER' ) ? PRECO_VER : false,
		);
	}

	/**
	 * Add inline JS after a registered/enqueued script handle.
	 *
	 * @param string $handle   Script handle to attach to.
	 * @param string $data     Raw JS.
	 * @param string $position 'before' or 'after'.
	 * @return void
	 */
	public static function add_inline_script( $handle, $data, $position = 'after' ) {
		if ( empty( $data ) ) {
			return;
		}

		wp_add_inline_script( $handle, $data, $position );
	}

	/**
	 * Localize a script with data.
	 *
	 * @param string $handle      Script handle.
	 * @param string $object_name JS global variable name.
	 * @param array  $data        Data to expose.
	 * @return void
	 */
	public static function localize_script( $handle, $object_name, $data ) {
		wp_localize_script( $handle, $object_name, $data );
	}
}
