<?php
/**
 * Gutenberg / My Blocks identity icons (inserter + naming only).
 *
 * Storage:
 * - Dashicon slug: `screenoptions`
 * - Lucide: `lucide:{id}`
 * - Emoji: `emoji:{char}`
 *
 * Not used for in-block content icons (buttons, etc.).
 *
 * @package JOCBM
 */

namespace JOCBM\Services;

defined( 'ABSPATH' ) || exit;

/**
 * Class BlockIdentityIcon
 */
final class BlockIdentityIcon {

	/**
	 * Sanitize a stored identity icon ref.
	 *
	 * @param string $icon Raw value.
	 */
	public static function sanitize( string $icon ): string {
		$icon = trim( $icon );
		if ( '' === $icon ) {
			return 'screenoptions';
		}

		if ( preg_match( '/^lucide:([a-z0-9_-]+)$/i', $icon, $m ) ) {
			$id = strtolower( $m[1] );
			$map = IconRegistry::lucide_svg_map();
			if ( ! isset( $map[ $id ] ) ) {
				return 'screenoptions';
			}
			return 'lucide:' . $id;
		}

		if ( preg_match( '/^emoji:(.+)$/u', $icon, $m ) ) {
			$emoji = self::sanitize_emoji( $m[1] );
			return $emoji ? 'emoji:' . $emoji : 'screenoptions';
		}

		// Legacy / bare dashicon slug.
		$slug = sanitize_key( $icon );
		$slug = preg_replace( '/^dashicons-/', '', $slug ) ?? $slug;

		return $slug ?: 'screenoptions';
	}

	/**
	 * Icon safe for PHP `register_block_type` (dashicon slug only).
	 * Client JS re-registers with Lucide SVG / emoji.
	 *
	 * @param string $icon Stored ref.
	 */
	public static function php_register_icon( string $icon ): string {
		$icon = self::sanitize( $icon );
		if ( 0 === strpos( $icon, 'lucide:' ) || 0 === strpos( $icon, 'emoji:' ) ) {
			return 'screenoptions';
		}
		return $icon;
	}

	/**
	 * Editor / REST payload fields for one identity icon.
	 *
	 * @param string $icon Stored ref.
	 * @return array{icon: string, iconSvg: string, iconEmoji: string}
	 */
	public static function for_editor_meta( string $icon ): array {
		$icon = self::sanitize( $icon );
		$out  = array(
			'icon'      => $icon,
			'iconSvg'   => '',
			'iconEmoji' => '',
		);

		if ( 0 === strpos( $icon, 'lucide:' ) ) {
			$id            = substr( $icon, 7 );
			$out['iconSvg'] = IconRegistry::resolve_inline_svg( 'lucide', $id );
		} elseif ( 0 === strpos( $icon, 'emoji:' ) ) {
			$out['iconEmoji'] = substr( $icon, 6 );
		}

		return $out;
	}

	/**
	 * Allow a short emoji grapheme cluster (no HTML).
	 *
	 * @param string $raw Payload after `emoji:`.
	 */
	private static function sanitize_emoji( string $raw ): string {
		$raw = trim( $raw );
		$raw = wp_strip_all_tags( $raw );
		$raw = preg_replace( '/[\x00-\x1F\x7F]/u', '', $raw ) ?? '';
		if ( '' === $raw || false !== strpos( $raw, '<' ) || false !== strpos( $raw, '>' ) ) {
			return '';
		}
		// Cap byte length for DB + ZWJ sequences.
		if ( strlen( $raw ) > 32 ) {
			return '';
		}
		return $raw;
	}
}
