<?php

/**
 * Registers built blocks from wp-content/lolacore-blocks with correct asset URLs.
 *
 * @package LolaCore\BlockBuilder\Registry
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\BlockBuilder\Registry;

// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Diagnostic exception messages; escaped at REST/chat presentation layer.

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

/**
 * WordPress get_block_asset_url() falls back to plugins_url() for paths outside
 * plugins/themes. Blocks under lolacore-blocks/ need content_url() instead.
 */
final class BlockRuntimeRegistrar {

	private const REGISTRATION_BODY_TEMPLATE = <<<'PHP'
	$dir = WP_CONTENT_DIR . '/lolacore-blocks/{{SLUG}}';
	$metadata_file = $dir . '/block.json';
	if ( ! is_dir( $dir ) || ! file_exists( $metadata_file ) ) {
		return;
	}
	$metadata = wp_json_file_decode( $metadata_file, array( 'associative' => true ) );
	if ( ! is_array( $metadata ) || empty( $metadata['name'] ) ) {
		return;
	}
	$block_name = (string) $metadata['name'];
	if ( function_exists( 'unregister_block_type' ) ) {
		$registry = WP_Block_Type_Registry::get_instance();
		if ( $registry->is_registered( $block_name ) ) {
			unregister_block_type( $block_name );
		}
	}
	$content_url_for = static function ( string $absolute_path ): string {
		$path = wp_normalize_path( $absolute_path );
		$content_dir = wp_normalize_path( WP_CONTENT_DIR );
		if ( ! str_starts_with( $path, $content_dir . '/' ) ) {
			return '';
		}
		$relative = substr( $path, strlen( $content_dir ) + 1 );
		return content_url( $relative );
	};
	$prime_script = static function ( string $directory, array $metadata, string $asset_ref, string $field_name ) use ( $content_url_for ): void {
		$rel = remove_block_asset_path_prefix( $asset_ref );
		$file_path = wp_normalize_path( $directory . '/' . $rel );
		if ( ! file_exists( $file_path ) ) {
			return;
		}
		$handle = generate_block_asset_handle( $metadata['name'], $field_name, 0 );
		if ( wp_script_is( $handle, 'registered' ) ) {
			return;
		}
		$asset_file = preg_replace( '/\.js$/', '.asset.php', $file_path );
		$asset = ( is_string( $asset_file ) && file_exists( $asset_file ) ) ? require $asset_file : array();
		$deps = is_array( $asset['dependencies'] ?? null ) ? $asset['dependencies'] : array();
		$version = $asset['version'] ?? (string) filemtime( $file_path );
		$url = $content_url_for( $file_path );
		if ( $url === '' ) {
			return;
		}
		wp_register_script( $handle, $url, $deps, $version, false );
	};
	$prime_style = static function ( string $directory, array $metadata, string $asset_ref, string $field_name ) use ( $content_url_for ): void {
		$rel = remove_block_asset_path_prefix( $asset_ref );
		$file_path = wp_normalize_path( $directory . '/' . $rel );
		if ( ! file_exists( $file_path ) ) {
			return;
		}
		$handle = generate_block_asset_handle( $metadata['name'], $field_name, 0 );
		if ( wp_style_is( $handle, 'registered' ) ) {
			return;
		}
		$url = $content_url_for( $file_path );
		if ( $url === '' ) {
			return;
		}
		wp_register_style( $handle, $url, array(), (string) filemtime( $file_path ) );
	};
	if ( ! empty( $metadata['editorScript'] ) && is_string( $metadata['editorScript'] ) ) {
		$prime_script( $dir, $metadata, $metadata['editorScript'], 'editorScript' );
	}
	if ( ! empty( $metadata['style'] ) && is_string( $metadata['style'] ) ) {
		$prime_style( $dir, $metadata, $metadata['style'], 'style' );
	}
	register_block_type( $dir );

PHP;

	public static function registerDirectory( string $directory ): bool {
		$directory = wp_normalize_path(rtrim($directory, '/'));
		$metadata_file = $directory . '/block.json';
		if (! is_dir($directory) || ! file_exists($metadata_file)) {
			return false;
		}

		$metadata = wp_json_file_decode($metadata_file, array( 'associative' => true ));
		if (! is_array($metadata) || empty($metadata['name'])) {
			return false;
		}

		$block_name = (string) $metadata['name'];
		if (function_exists('unregister_block_type')) {
			$registry = \WP_Block_Type_Registry::get_instance();
			if ($registry->is_registered($block_name)) {
				unregister_block_type($block_name);
			}
		}

		self::primeAssetsFromMetadata($directory, $metadata);

		$result = register_block_type($directory);

		return $result instanceof \WP_Block_Type;
	}

	/**
	 * Inline PHP for the Playground host plugin (no LolaCore autoload in WASM).
	 */
	public static function registrationPhpBody( string $install_slug ): string {
		$install_slug = sanitize_title($install_slug);

		return str_replace('{{SLUG}}', $install_slug, self::REGISTRATION_BODY_TEMPLATE);
	}

	public static function contentUrlForFile( string $absolute_path ): string {
		$path        = wp_normalize_path($absolute_path);
		$content_dir = wp_normalize_path(WP_CONTENT_DIR);

		if (! str_starts_with($path, $content_dir . '/')) {
			return '';
		}

		$relative = substr($path, strlen($content_dir) + 1);

		return content_url($relative);
	}

	/**
	 * @param array<string, mixed> $metadata
	 */
	private static function primeAssetsFromMetadata( string $directory, array $metadata ): void {
		if (! empty($metadata['editorScript']) && is_string($metadata['editorScript'])) {
			self::primeScriptAsset($directory, $metadata, $metadata['editorScript'], 'editorScript');
		}

		if (! empty($metadata['style']) && is_string($metadata['style'])) {
			self::primeStyleAsset($directory, $metadata, $metadata['style'], 'style');
		}
	}

	/**
	 * @param array<string, mixed> $metadata
	 */
	private static function primeScriptAsset(
		string $directory,
		array $metadata,
		string $asset_ref,
		string $field_name
	): void {
		$rel       = remove_block_asset_path_prefix($asset_ref);
		$file_path = wp_normalize_path($directory . '/' . $rel);
		if (! file_exists($file_path)) {
			return;
		}

		$handle = generate_block_asset_handle((string) $metadata['name'], $field_name, 0);
		if (wp_script_is($handle, 'registered')) {
			return;
		}

		$asset_file = preg_replace('/\.js$/', '.asset.php', $file_path);
		$asset      = ( is_string($asset_file) && file_exists($asset_file) ) ? require $asset_file : array();
		$deps       = is_array($asset['dependencies'] ?? null) ? $asset['dependencies'] : array();
		$version    = $asset['version'] ?? (string) filemtime($file_path);
		$url        = self::contentUrlForFile($file_path);
		if ($url === '') {
			return;
		}

		wp_register_script($handle, $url, $deps, $version, false);
	}

	/**
	 * @param array<string, mixed> $metadata
	 */
	private static function primeStyleAsset(
		string $directory,
		array $metadata,
		string $asset_ref,
		string $field_name
	): void {
		$rel       = remove_block_asset_path_prefix($asset_ref);
		$file_path = wp_normalize_path($directory . '/' . $rel);
		if (! file_exists($file_path)) {
			return;
		}

		$handle = generate_block_asset_handle((string) $metadata['name'], $field_name, 0);
		if (wp_style_is($handle, 'registered')) {
			return;
		}

		$url = self::contentUrlForFile($file_path);
		if ($url === '') {
			return;
		}

		wp_register_style($handle, $url, array(), (string) filemtime($file_path));
	}
}

