<?php
/**
 * Asset Loader
 *
 * Prefers Vite dist manifest in production; falls back to source assets.
 *
 * @package Kutby
 * @since   1.0.0
 */

declare(strict_types=1);

namespace Kutby\Assets;

use Kutby\Contracts\ModuleInterface;
use Kutby\Design\Tokens;

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

/**
 * Class AssetLoader
 */
final class AssetLoader implements ModuleInterface {

	/**
	 * {@inheritdoc}
	 */
	public function register(): void {
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend' ) );
		add_action( 'wp_head', array( $this, 'print_critical_css' ), 1 );
		add_action( 'wp_head', array( $this, 'vite_client' ), 1 );
		add_filter( 'script_loader_tag', array( $this, 'add_defer' ), 10, 3 );
	}

	/**
	 * {@inheritdoc}
	 */
	public function boot(): void {}

	/**
	 * Vite HMR client when KUTBY_DEV is on.
	 *
	 * @return void
	 */
	public function vite_client(): void {
		if ( ! AssetManifestManager::is_dev() ) {
			return;
		}

		echo '<script type="module" src="http://localhost:5173/@vite/client"></script>' . "\n";
		echo '<script type="module" src="http://localhost:5173/src/main.js"></script>' . "\n";
	}

	/**
	 * Enqueue frontend styles and scripts.
	 *
	 * @return void
	 */
	public function enqueue_frontend(): void {
		// Dev mode: Vite injects assets via wp_head; skip WP enqueue of built files.
		if ( AssetManifestManager::is_dev() ) {
			wp_register_script( 'kutby-theme', false, array(), KUTBY_VERSION, true );
			wp_enqueue_script( 'kutby-theme' );
			$this->localize_theme_data( 'kutby-theme' );
			$inline = Tokens::to_css();
			if ( '' !== $inline ) {
				printf( '<style id="kutby-vars">%s</style>' . "\n", $inline ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped in Tokens.
			}
			do_action( 'kutby_enqueue_assets' );
			return;
		}

		$entry = AssetManifestManager::entry( 'src/main.js' );

		if ( $entry ) {
			foreach ( $entry['css'] as $index => $css_url ) {
				wp_enqueue_style(
					0 === $index ? 'kutby-main' : 'kutby-main-' . $index,
					$css_url,
					array(),
					$entry['version']
				);
			}

			wp_enqueue_script(
				'kutby-theme',
				$entry['url'],
				array(),
				$entry['version'],
				array(
					'strategy'  => 'defer',
					'in_footer' => true,
				)
			);
		} else {
			// Fallback: legacy source files (pre-build).
			wp_enqueue_style(
				'kutby-main',
				AssetManifestManager::fallback_style( 'css/main.css' ),
				array(),
				KUTBY_VERSION
			);
			wp_enqueue_script(
				'kutby-theme',
				AssetManifestManager::fallback_script( 'js/theme.js' ),
				array(),
				KUTBY_VERSION,
				array( 'strategy' => 'defer', 'in_footer' => true )
			);
			wp_enqueue_script(
				'kutby-navigation',
				AssetManifestManager::fallback_script( 'js/navigation.js' ),
				array(),
				KUTBY_VERSION,
				array( 'strategy' => 'defer', 'in_footer' => true )
			);
			wp_enqueue_script(
				'kutby-footer',
				AssetManifestManager::fallback_script( 'js/footer.js' ),
				array(),
				KUTBY_VERSION,
				array( 'strategy' => 'defer', 'in_footer' => true )
			);
		}

		$inline = Tokens::to_css();
		if ( '' !== $inline ) {
			wp_add_inline_style( 'kutby-main', $inline );
		}

		$this->localize_theme_data( 'kutby-theme' );

		/**
		 * Fires after Kutby frontend assets are enqueued.
		 *
		 * @since 1.0.0
		 */
		do_action( 'kutby_enqueue_assets' );
	}

	/**
	 * Localize shared frontend data.
	 *
	 * @param string $handle Script handle.
	 * @return void
	 */
	private function localize_theme_data( string $handle ): void {
		wp_localize_script(
			$handle,
			'kutbyData',
			array(
				'ajaxUrl' => admin_url( 'admin-ajax.php' ),
				'homeUrl' => home_url( '/' ),
				'nonce'   => wp_create_nonce( 'kutby_frontend' ),
			)
		);
	}

	/**
	 * Build :root CSS custom properties from Design Tokens.
	 *
	 * @deprecated 2.5.0 Use Tokens::to_css().
	 * @return string
	 */
	private function build_css_variables(): string {
		return Tokens::to_css();
	}

	/**
	 * Print critical CSS placeholder in head.
	 *
	 * @return void
	 */
	public function print_critical_css(): void {
		/**
		 * Allow injecting critical CSS string.
		 *
		 * @since 1.0.0
		 *
		 * @param string $css Critical CSS.
		 */
		$critical = (string) apply_filters( 'kutby_critical_css', '' );
		if ( '' === $critical ) {
			return;
		}

		echo '<style id="kutby-critical">' . $critical . '</style>' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- filtered critical CSS.
	}

	/**
	 * Ensure theme scripts use defer when needed.
	 *
	 * @param string $tag    Script tag HTML.
	 * @param string $handle Script handle.
	 * @param string $src    Script source URL.
	 * @return string
	 */
	public function add_defer( string $tag, string $handle, string $src ): string {
		$handles = array( 'kutby-theme', 'kutby-navigation', 'kutby-search', 'kutby-slider', 'kutby-dropdown' );

		if ( ! in_array( $handle, $handles, true ) ) {
			return $tag;
		}

		if ( false !== strpos( $tag, ' defer' ) || false !== strpos( $tag, ' async' ) || false !== strpos( $tag, 'type="module"' ) ) {
			return $tag;
		}

		return str_replace( ' src', ' defer src', $tag );
	}
}
