<?php
/**
 * Recursively collect Divi Icon Picker values from module attrs.
 *
 * @package DiviSupreme
 */

declare(strict_types=1);

namespace DiviSupreme\Extensions\IconLibraries;

if ( ! defined( 'ABSPATH' ) ) {
	die( 'Direct access forbidden.' );
}

/**
 * Finds stored icon picker leaves `{ unicode, type, weight?, variant? }` in attrs trees.
 */
final class IconAttrCollector {

	/**
	 * @param array<string, mixed> $attrs Module attrs.
	 * @return array<int, array<string, mixed>>
	 */
	public static function collect_dsm_icons( array $attrs ): array {
		$collected = array();

		self::walk( $attrs, $collected, false );

		return $collected;
	}

	/**
	 * Unique DSM icons (for CSS rules).
	 *
	 * @param array<string, mixed> $attrs Module attrs.
	 * @return array<int, array<string, mixed>>
	 */
	public static function collect_unique_dsm_icons( array $attrs ): array {
		$collected = array();

		self::walk( $attrs, $collected, true );

		return array_values( $collected );
	}

	/**
	 * Whether attrs contain at least one enabled DSM library icon.
	 *
	 * @param array<string, mixed> $attrs Module attrs.
	 * @return bool
	 */
	public static function has_dsm_icons( array $attrs ): bool {
		return count( self::collect_dsm_icons( $attrs ) ) > 0;
	}

	/**
	 * Stable cache key for an icon settings leaf.
	 *
	 * @param array<string, mixed> $icon Icon settings.
	 * @return string
	 */
	public static function icon_cache_key( array $icon ): string {
		$library_id = sanitize_key( (string) ( $icon['type'] ?? '' ) );
		$icon_id    = sanitize_key( (string) ( $icon['unicode'] ?? '' ) );
		$variant    = IconLibraryRegistry::resolve_variant_from_icon( $icon );

		return $library_id . ':' . $icon_id . ':' . $variant;
	}

	/**
	 * @param mixed                               $value     Node to walk.
	 * @param array<int|string, array<string, mixed>> $collected Icons list or keyed map when unique.
	 * @param bool                                $unique    Dedupe by cache key.
	 * @return void
	 */
	private static function walk( $value, array &$collected, bool $unique ): void {
		if ( ! is_array( $value ) ) {
			return;
		}

		if ( self::is_icon_picker_leaf( $value ) && IconLibraryRegistry::is_dsm_library_icon( $value ) ) {
			if ( $unique ) {
				$key = self::icon_cache_key( $value );

				if ( ! isset( $collected[ $key ] ) ) {
					$collected[ $key ] = $value;
				}
			} else {
				$collected[] = $value;
			}

			return;
		}

		foreach ( $value as $child ) {
			self::walk( $child, $collected, $unique );
		}
	}

	/**
	 * @param array<string, mixed> $value Candidate leaf.
	 * @return bool
	 */
	private static function is_icon_picker_leaf( array $value ): bool {
		return isset( $value['type'], $value['unicode'] )
			&& is_string( $value['type'] )
			&& is_string( $value['unicode'] )
			&& '' !== $value['unicode'];
	}
}
