<?php

use Illuminate\Container\Container;
use Illuminate\Support\HtmlString;
use Illuminate\Support\Str;

/**
 * Generate Vite tags for an entrypoint.
 *
 * @param  string|string[]  $entrypoints
 * @param  string  $buildDirectory
 * @return \Illuminate\Support\HtmlString
 *
 * @throws \Exception
 */
function initVite($entrypoints, $buildDirectory = 'http://localhost')
{
	static $manifests = [];
	$assetsPath = WP_HOME . '/app/build';

	$entrypoints = collect($entrypoints);
	$buildDirectory = Str::start($buildDirectory, '/');

	if (is_file(PUBLIC_DIR . '/hot')) {
		$url = rtrim(file_get_contents(PUBLIC_DIR . '/hot'));

		return new HtmlString(
			$entrypoints
				->map(fn ($entrypoint) => makeTag("{$url}/{$entrypoint}"))
				->prepend(makeScriptTag("{$url}/@vite/client"))
				->join('')
		);
	}

	$manifestPath = WP_CONTENT_DIR . '/build/manifest.json';

	if (! isset($manifests[$manifestPath])) {
		if (! is_file($manifestPath)) {
			throw new Exception("Vite manifest not found at: {$manifestPath}");
		}

		$manifests[$manifestPath] = json_decode(file_get_contents($manifestPath), true);
	}

	$manifest = $manifests[$manifestPath];

	$tags = collect();

	foreach ($entrypoints as $entrypoint) {
		if (! isset($manifest[$entrypoint])) {
			throw new Exception("Unable to locate file in Vite manifest: {$entrypoint}.");
		}

		$tags->push(makeTag($assetsPath . "/{$manifest[$entrypoint]['file']}"));

		if (isset($manifest[$entrypoint]['css'])) {
			foreach ($manifest[$entrypoint]['css'] as $css) {
				$tags->push(makeStylesheetTag($assetsPath . "/{$css}"));
			}
		}

		if (isset($manifest[$entrypoint]['imports'])) {
			foreach ($manifest[$entrypoint]['imports'] as $import) {
				if (isset($manifest[$import]['css'])) {
					foreach ($manifest[$import]['css'] as $css) {
						$tags->push(makeStylesheetTag($assetsPath . "/{$css}"));
					}
				}
			}
		}
	}

	[$stylesheets, $scripts] = $tags->partition(fn ($tag) => str_starts_with($tag, '<link'));

	return new HtmlString($stylesheets->join('').$scripts->join(''));
}

/**
 * Generate an appropriate tag for the given URL.
 *
 * @param  string  $url
 * @return string
 */
	function makeTag($url)
{
	if (isCssPath($url)) {
		return makeStylesheetTag($url);
	}

	return makeScriptTag($url);
}

/**
 * Generate a script tag for the given URL.
 *
 * @param  string  $url
 * @return string
 */
	function makeScriptTag($url)
{
	return sprintf('<script type="module" src="%s"></script>', $url);
}

/**
 * Generate a stylesheet tag for the given URL.
 *
 * @param  string  $url
 * @return string
 */
	function makeStylesheetTag($url)
{
	return sprintf('<link rel="stylesheet" href="%s" />', $url);
}

/**
 * Determine whether the given path is a CSS file.
 *
 * @param  string  $path
 * @return bool
 */
	function isCssPath($path)
{
	return preg_match('/\.(css|less|sass|scss|styl|stylus|pcss|postcss)$/', $path) === 1;
}

