<?php
/**
 * RSM Buttons SVG sprite icons.
 *
 * @package Rsmspark_Content_Widgets
 */

defined( 'ABSPATH' ) || exit;

/**
 * Rsmspark_Buttons_Icons
 */
class Rsmspark_Buttons_Icons {

	const SPRITE_FILE    = 'assets/icons/rsm-button-icons.svg';
	const MANIFEST_FILE  = 'assets/icons/icons.manifest.json';
	const SPRITE_WRAP_ID = 'rsm-button-icons-sprite';

	/**
	 * @var bool
	 */
	private static $sprite_printed = false;

	/**
	 * @var array<string, bool>|null
	 */
	private static $valid_slugs = null;

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

	/**
	 * Legacy Dashicon slug => sprite slug.
	 *
	 * @var array<string, string>
	 */
	private static $dashicon_map = array(
		'arrow-right-alt2' => 'arrow-right',
		'email'            => 'envelope',
		'external'         => 'external-link',
		'star-filled'      => 'star',
		'yes-alt'          => 'check',
		'admin-links'      => 'link',
		'calendar-alt'     => 'calendar',
		'location'         => 'map-pin',
		'groups'           => 'users',
	);

	/**
	 * @return void
	 */
	public static function init() {
		add_action( 'wp_footer', array( __CLASS__, 'print_sprite' ), 5 );
		add_action( 'admin_footer', array( __CLASS__, 'print_sprite' ), 5 );
	}

	/**
	 * @return string
	 */
	public static function sprite_path() {
		return RSMSPARK_CONTENT_WIDGETS_PATH . self::SPRITE_FILE;
	}

	/**
	 * @return bool
	 */
	public static function sprite_exists() {
		return is_readable( self::sprite_path() );
	}

	/**
	 * @return array<string, bool>
	 */
	public static function valid_slugs() {
		if ( null !== self::$valid_slugs ) {
			return self::$valid_slugs;
		}

		self::$valid_slugs = array();
		$manifest          = self::get_manifest();
		foreach ( (array) ( $manifest['icons'] ?? array() ) as $icon ) {
			$slug = sanitize_key( (string) ( $icon['slug'] ?? '' ) );
			if ( '' !== $slug ) {
				self::$valid_slugs[ $slug ] = true;
			}
		}

		if ( empty( self::$valid_slugs ) && self::sprite_exists() ) {
			$contents = (string) file_get_contents( self::sprite_path() );
			if ( preg_match_all( '/id="rsm-icon-([a-z0-9-]+)"/', $contents, $matches ) ) {
				foreach ( $matches[1] as $slug ) {
					self::$valid_slugs[ sanitize_key( $slug ) ] = true;
				}
			}
		}

		return self::$valid_slugs;
	}

	/**
	 * @param string $slug Icon slug.
	 * @return bool
	 */
	public static function has_icon( $slug ) {
		$slug = sanitize_key( (string) $slug );
		if ( '' === $slug ) {
			return false;
		}

		$valid = self::valid_slugs();
		return ! empty( $valid[ $slug ] );
	}

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

		self::$manifest = array(
			'version'    => 1,
			'categories' => array(),
			'icons'      => array(),
		);

		$manifest_path = RSMSPARK_CONTENT_WIDGETS_PATH . self::MANIFEST_FILE;
		if ( is_readable( $manifest_path ) ) {
			$decoded = json_decode( (string) file_get_contents( $manifest_path ), true );
			if ( is_array( $decoded ) ) {
				self::$manifest = $decoded;
			}
		}

		return self::$manifest;
	}

	/**
	 * @return array<int, array{id: string, label: string}>
	 */
	public static function get_categories() {
		$categories = array();
		foreach ( (array) ( self::get_manifest()['categories'] ?? array() ) as $category ) {
			$id = sanitize_key( (string) ( $category['id'] ?? '' ) );
			if ( '' === $id ) {
				continue;
			}
			$categories[] = array(
				'id'    => $id,
				'label' => (string) ( $category['label'] ?? ucfirst( $id ) ),
			);
		}

		return $categories;
	}

	/**
	 * @return array<int, array{slug: string, label: string, category: string}>
	 */
	public static function get_picker_choices() {
		$choices = array(
			array(
				'slug'     => '',
				'label'    => __( 'None', 'rsm-content-widgets' ),
				'category' => 'general',
			),
		);

		foreach ( (array) ( self::get_manifest()['icons'] ?? array() ) as $icon ) {
			$slug = sanitize_key( (string) ( $icon['slug'] ?? '' ) );
			if ( '' === $slug || ! self::has_icon( $slug ) ) {
				continue;
			}

			$choices[] = array(
				'slug'     => $slug,
				'label'    => (string) ( $icon['label'] ?? ucwords( str_replace( '-', ' ', $slug ) ) ),
				'category' => sanitize_key( (string) ( $icon['category'] ?? 'general' ) ),
			);
		}

		return apply_filters( 'rsmspark_buttons_sprite_choices', $choices );
	}

	/**
	 * @param string $dashicon_slug Dashicon slug without prefix.
	 * @return string Sprite slug or empty string.
	 */
	public static function map_dashicon_slug( $dashicon_slug ) {
		$slug = sanitize_key( (string) $dashicon_slug );
		if ( '' === $slug ) {
			return '';
		}

		if ( isset( self::$dashicon_map[ $slug ] ) ) {
			return (string) self::$dashicon_map[ $slug ];
		}

		return $slug;
	}

	/**
	 * Normalize legacy dashicon config to sprite slugs.
	 *
	 * @param array<string, mixed> $config Button config.
	 * @return array<string, mixed>
	 */
	public static function normalize_config( array $config ) {
		if ( 'image' === ( $config['icon_type'] ?? '' ) ) {
			return $config;
		}

		$icon_type = (string) ( $config['icon_type'] ?? 'sprite' );
		$icon      = Rsmspark_Buttons_Config::sanitize_icon( (string) ( $config['icon'] ?? '' ) );

		if ( 'dashicon' === $icon_type || 'sprite' === $icon_type || '' === $icon_type ) {
			$mapped = self::map_dashicon_slug( $icon );
			if ( self::has_icon( $mapped ) ) {
				$config['icon']      = $mapped;
				$config['icon_type'] = 'sprite';
			} elseif ( self::has_icon( $icon ) ) {
				$config['icon']      = $icon;
				$config['icon_type'] = 'sprite';
			} elseif ( 'dashicon' === $icon_type && '' !== $icon ) {
				$config['icon']      = $icon;
				$config['icon_type'] = 'dashicon';
			} else {
				$config['icon']      = $icon;
				$config['icon_type'] = 'sprite';
			}
		}

		if ( 'sprite' === ( $config['icon_type'] ?? '' ) && '' !== (string) ( $config['icon'] ?? '' ) && ! self::has_icon( (string) $config['icon'] ) ) {
			$config['icon'] = '';
		}

		return $config;
	}

	/**
	 * @param string $slug Sprite slug.
	 * @return string
	 */
	public static function render_use_markup( $slug ) {
		$slug = sanitize_key( (string) $slug );
		if ( '' === $slug || ! self::has_icon( $slug ) ) {
			return '';
		}

		return sprintf(
			'<svg class="rsmspark-btn__icon rsmspark-btn__icon--svg" aria-hidden="true" focusable="false"><use href="#rsm-icon-%s"></use></svg>',
			esc_attr( $slug )
		);
	}

	/**
	 * Build inline sprite markup (once per request).
	 *
	 * @return string
	 */
	public static function get_sprite_markup() {
		if ( self::$sprite_printed || ! self::sprite_exists() ) {
			return '';
		}

		$contents = (string) file_get_contents( self::sprite_path() );
		if ( '' === $contents ) {
			return '';
		}

		$contents = preg_replace( '/<\?xml[^>]*\?>\s*/', '', $contents );
		$contents = trim( $contents );
		if ( '' === $contents || ! preg_match( '/^<svg\b/i', $contents ) ) {
			return '';
		}

		$contents = preg_replace(
			'/^<svg\b/i',
			sprintf(
				'<svg id="%s" style="position:absolute;width:0;height:0;overflow:hidden" aria-hidden="true" focusable="false"',
				esc_attr( self::SPRITE_WRAP_ID )
			),
			$contents,
			1
		);

		self::$sprite_printed = true;

		return $contents;
	}

	/**
	 * Print inline sprite once per request.
	 *
	 * @return void
	 */
	public static function print_sprite( $force = false ) {
		if ( self::$sprite_printed ) {
			return;
		}

		if (
			! $force
			&& ! doing_action( 'wp_footer' )
			&& ! doing_action( 'admin_footer' )
		) {
			if ( ! has_action( 'wp_footer', array( __CLASS__, 'print_sprite' ) ) ) {
				add_action( 'wp_footer', array( __CLASS__, 'print_sprite' ), 5 );
			}
			if ( ! has_action( 'admin_footer', array( __CLASS__, 'print_sprite' ) ) ) {
				add_action( 'admin_footer', array( __CLASS__, 'print_sprite' ), 5 );
			}

			return;
		}

		$contents = self::get_sprite_markup();
		if ( '' === $contents ) {
			return;
		}

		echo wp_kses( Rsmspark_Content_Widgets_Kses::svg_sprite( $contents ), Rsmspark_Content_Widgets_Kses::allowed_html() );
	}
}
