@use 'sass:list';
@use 'sass:map';
@use 'sass:meta';
@use 'sass:string';

// ============================================
// CSS Attributes Mixin
// Transforms a map into CSS property declarations
// ============================================

// Handle vendor-prefixed pseudo-elements
@mixin pseudo-element-placeholder($pseudo-element) {
	@if list.index(
		(
			calendar-picker-indicator,
			search-cancel-button,
			color-swatch-wrapper,
			color-swatch,
			inner-spin-button,
			outer-spin-button,
			progress-bar,
			progress-value,
			progress-inner-element,
			datetime-edit,
			datetime-edit-fields-wrapper,
			datetime-edit-day-field
		),
		$pseudo-element
	) {
		&::-webkit-#{$pseudo-element} {
			@content;
		}

		&::-moz-#{$pseudo-element} {
			@content;
		}
	} @else {
		&::#{$pseudo-element} {
			@content;
		}
	}
}

// List of valid pseudo-elements
$-pseudo-elements: (
	before, after, placeholder,
	calendar-picker-indicator, search-cancel-button,
	color-swatch-wrapper, color-swatch,
	inner-spin-button, outer-spin-button,
	progress-bar, progress-value, inner-element, marker,
	datetime-edit, datetime-edit-fields-wrapper, datetime-edit-day-field,
	backdrop, file-selector-button,
	-webkit-progress-bar, -webkit-progress-value, -webkit-inner-element,
	-moz-progress-bar, -moz-progress-value, -moz-inner-element,
	-webkit-details-marker, -webkit-scrollbar,
	-webkit-scrollbar-track, -webkit-scrollbar-thumb
);

// Transform a map into a list of CSS attributes
// @param {Map} $original - Original map for reference
// @param {Map} $map - The map to transform
// @param {String} $prefix - Variable name prefix
// @param {String} $variant - Variant name for CSS variable naming
// @param {String} $postfix - Postfix for CSS variable naming
// @param {Bool} $deep - Whether to recurse into nested maps
// @param {List} $ignore - Keys to ignore
// @param {Bool} $use-custom-props - Whether to use CSS custom properties
// @param {Map} $bps - Breakpoints map
@mixin spread-map-into-attrs(
	$original: (),
	$map: (),
	$prefix: '',
	$variant: '',
	$postfix: '',
	$deep: false,
	$ignore: (),
	$use-custom-props: true,
	$bps: (xxs: 0)
) {
	@if meta.type-of($map) == 'map' and $prefix != '' {
		@each $key, $value in $map {
			@if not list.index($ignore, $key) {
				@if meta.type-of($value) == 'map' and ($deep or $key == 'pseudo') {
					$original: map.get($original, $key);

					@if not $original {
						$original: ();
					}

					@if $postfix != '' {
						$key: #{$postfix}-#{$key};
					}

					@if $key == 'pseudo' {
						@each $pseudo-element, $pseudo-map in $value {
							@if meta.type-of($pseudo-map) == 'map' {
								@if list.index($-pseudo-elements, $pseudo-element) {
									$original: map.get($original, $pseudo-element);
									$key: pseudo-#{$pseudo-element};

									@include pseudo-element-placeholder($pseudo-element) {
										@if not $original {
											@if not map.has-key($pseudo-map, 'content') {
												content: '';
											}

											$original: ();
										}

										@include spread-map-into-attrs(
											$original: $original,
											$map: $pseudo-map,
											$prefix: $prefix,
											$variant: $variant,
											$postfix: $key,
											$deep: true,
											$use-custom-props: $use-custom-props
										);
									}
								}
							}
						}
					} @else {
						@include spread-map-into-attrs(
							$original: $original,
							$map: $value,
							$prefix: $prefix,
							$variant: $variant,
							$postfix: $key,
							$deep: true,
							$use-custom-props: $use-custom-props
						);
					}
				} @else if meta.type-of($value) != 'map' and string.slice(meta.inspect($key), 1, 1) != '_' {
					@if $use-custom-props and
						$key != 'content' and
						string.slice(meta.inspect($key), 1, 2) != '--' and
						string.slice(meta.inspect($key), 1, 1) != '['
					{
						$prop-to-replace: --#{$prefix};
						$prop-to-replace-with: --#{$prefix};

						// add variant
						@if $variant != '' {
							$prop-to-replace-with: #{$prop-to-replace-with}-#{$variant};
						}

						// add postfix
						@if $postfix != '' {
							$prop-to-replace: #{$prop-to-replace}-#{$postfix};
							$prop-to-replace-with: #{$prop-to-replace-with}-#{$postfix};
						}

						// add key
						$prop-to-replace: #{$prop-to-replace}-#{$key};
						$prop-to-replace-with: #{$prop-to-replace-with}-#{$key};

						@if map.get($original, $key) {
							#{$prop-to-replace}: var(#{$prop-to-replace-with});
						} @else {
							#{$key}: var(#{$prop-to-replace-with});
						}
					} @else {
						@if string.slice(meta.inspect($key), 1, 1) == '[' {
							$key: string.slice(
								meta.inspect($key),
								2,
								string.length(meta.inspect($key)) - 1
							);
						}

						#{$key}: $value;
					}
				}
			}
		}
	}
}
