<?php
/**
 * Asset Manifest Manager — Vite dist + env + fallbacks.
 *
 * @package Kutby
 * @since   2.5.0
 */

declare(strict_types=1);

namespace Kutby\Assets;

use Kutby\Support\Environment;

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

/**
 * Class AssetManifestManager
 */
final class AssetManifestManager {

	/**
	 * @var array<string, mixed>|null
	 */
	private static ?array $manifest = null;

	/**
	 * Whether production dist should be used.
	 *
	 * @return bool
	 */
	public static function use_dist(): bool {
		return Environment::use_dist();
	}

	/**
	 * Whether Vite HMR / dev mode is active.
	 *
	 * @return bool
	 */
	public static function is_dev(): bool {
		return Environment::is_dev();
	}

	/**
	 * Raw manifest array.
	 *
	 * @return array<string, mixed>
	 */
	public static function all(): array {
		if ( null !== self::$manifest ) {
			return self::$manifest;
		}

		// Prefer Manifest class cache path for BC.
		self::$manifest = Manifest::all();
		return self::$manifest;
	}

	/**
	 * Resolve Vite entry.
	 *
	 * @param string $entry Entry key (e.g. src/main.js).
	 * @return array{url: string, version: string, css: array<int, string>}|null
	 */
	public static function entry( string $entry ): ?array {
		return Manifest::entry( $entry );
	}

	/**
	 * Fallback style URI when dist missing.
	 *
	 * @param string $relative Relative under assets/.
	 * @return string
	 */
	public static function fallback_style( string $relative ): string {
		return trailingslashit( KUTBY_ASSETS_URI ) . ltrim( $relative, '/' );
	}

	/**
	 * Fallback script URI when dist missing.
	 *
	 * @param string $relative Relative under assets/.
	 * @return string
	 */
	public static function fallback_script( string $relative ): string {
		return trailingslashit( KUTBY_ASSETS_URI ) . ltrim( $relative, '/' );
	}

	/**
	 * Resolve a font URL that matches the Vite-built file when dist is used.
	 *
	 * Manifest keys look like: assets/fonts/tajawal/tajawal-arabic-400.woff2
	 *
	 * @param string $src Relative path under assets/ (with or without assets/ prefix).
	 * @return string|null Public URI or null when unavailable.
	 */
	public static function font_url( string $src ): ?string {
		$src = ltrim( str_replace( '\\', '/', $src ), '/' );

		if ( str_starts_with( $src, 'assets/fonts/' ) ) {
			$key = $src;
		} elseif ( str_starts_with( $src, 'fonts/' ) ) {
			$key = 'assets/' . $src;
		} else {
			// Legacy filter values: tajawal/file.woff2
			$key = 'assets/fonts/' . $src;
		}

		if ( self::use_dist() ) {
			$manifest = self::all();
			if ( ! empty( $manifest[ $key ] ) && is_array( $manifest[ $key ] ) ) {
				$file = isset( $manifest[ $key ]['file'] ) ? (string) $manifest[ $key ]['file'] : '';
				if ( '' !== $file ) {
					return trailingslashit( KUTBY_ASSETS_URI ) . 'dist/' . ltrim( $file, '/' );
				}
			}
			// Dist mode: do not preload unhashed paths (avoids double-fetch).
			return null;
		}

		$relative = preg_replace( '#^assets/#', '', $key ) ?? $key;
		$path     = KUTBY_ASSETS . '/' . ltrim( (string) $relative, '/' );
		if ( ! is_readable( $path ) ) {
			return null;
		}

		return trailingslashit( KUTBY_ASSETS_URI ) . ltrim( (string) $relative, '/' );
	}
}
