@use '../core/spacing' as sp;
@use '../mixins/responsive-utility' as *;
@use "sass:map";

// === Properties and directions ===
$properties: (
  m: margin,
  p: padding,
);

$directions: (
  t: (top),
  r: (right),
  b: (bottom),
  l: (left),
  x: (left, right),
  y: (top, bottom),
);

$insets: (
  top,
  right,
  bottom,
  left,
  inset,
);

/**
  * Emit spacing classes for a given class name and rules.
  *
  * @param {String} $class-name - The class name to emit.
  * @param {Map} $rules - The CSS rules to apply.
  * @param {Boolean} $responsive - Whether to emit responsive classes.
  */
@mixin emit-spacing-class($class-name, $rules, $responsive: false) {
  @if $responsive {
    @include utility-responsive($class-name, $rules);
  } @else {
    @include utility-base($class-name, $rules);
  }
}

/**
  * Emit spacing classes for a given class name and rules, including negative variants if allowed.
  *
  * @param {String} $class-name - The class name to emit.
  * @param {Map} $rules - The CSS rules to apply.
  * @param {Map} $negative-rules - The CSS rules to apply for negative variants.
  * @param {Boolean} $allow-negative - Whether to emit negative variants.
  * @param {Boolean} $responsive - Whether to emit responsive classes.
  */
@mixin emit-spacing-classes($class-name, $rules, $negative-rules: null, $allow-negative: false, $responsive: false) {
  @include emit-spacing-class($class-name, $rules, $responsive);

  @if $allow-negative {
    @include emit-spacing-class("-#{$class-name}", $negative-rules, $responsive);
  }
}

/**
  * Generate spacing rules for a given property and targets.
  *
  * @param {String} $property-value - The CSS property to apply.
  * @param {List} $targets - The list of targets (e.g., top, right, bottom, left).
  * @param {String} $size - The size key from the spacing map.
  * @param {Boolean} $negative - Whether to generate negative rules.
  * @return {Map} - The generated CSS rules.
  */
@function spacing-rules-for-targets($property-value, $targets, $size, $negative: false) {
  $rules: ();
  $spacing-value: var(--spacing-#{$size}) !important;

  @if $negative {
    $spacing-value: calc(-1 * var(--spacing-#{$size})) !important;
  }

  @each $target in $targets {
    $rules: map.merge($rules, (
      #{$property-value}-#{$target}: $spacing-value
    ));
  }

  @return $rules;
}

/**
  * Generate spacing utility classes.
  *
  * @param {Boolean} $responsive - Whether to generate responsive classes.
  */
@mixin generate-spacing-utilities($responsive: false) {
  // === Global classes ===
  // Ex : .av-m-sm / .av-p-md / .av--m-lg / .av-m-xs--sm / .av-p-md--lg
  @each $type, $property-value in $properties {
    @each $size, $value in sp.$spacing {
      @include emit-spacing-classes(
        "#{$type}-#{$size}",
        (
          #{$property-value}: var(--spacing-#{$size}) !important
        ),
        (
          #{$property-value}: calc(-1 * var(--spacing-#{$size})) !important
        ),
        $property-value == margin,
        $responsive
      );
    }
  }

  // === Directional classes ===
  // Ex : .av-mt-sm / .av-px-md / .av--mb-lg / .av-mt-xs--sm / .av-px-md--lg
  @each $type, $property-value in $properties {
    @each $direction-key, $direction-targets in $directions {
      @each $size, $value in sp.$spacing {
        @include emit-spacing-classes(
          "#{$type}#{$direction-key}-#{$size}",
          spacing-rules-for-targets($property-value, $direction-targets, $size),
          spacing-rules-for-targets($property-value, $direction-targets, $size, true),
          $property-value == margin,
          $responsive
        );
      }
    }
  }

  // === Auto margin classes ===
  // Ex : .av-m-auto / .av-mt-auto / .av-mb-auto / .av-ml-auto
  @include emit-spacing-class('m-auto', (margin: auto !important), $responsive);

  @each $direction-key, $direction-targets in $directions {
    $rules: ();

    @each $target in $direction-targets {
      $rules: map.merge($rules, (
        margin-#{$target}: auto !important
      ));
    }

    @include emit-spacing-class(
      "m#{$direction-key}-auto",
      $rules,
      $responsive
    );
  }

  // === Inset classes ===
  // Ex : .av-top-sm / .av--bottom-md / .av-inset-lg / .av-top-xs--sm / .av-inset-md--lg
  @each $inset in $insets {
    @each $size, $value in sp.$spacing {
      @include emit-spacing-classes(
        "#{$inset}-#{$size}",
        (
          #{$inset}: var(--spacing-#{$size}) !important
        ),
        (
          #{$inset}: calc(-1 * var(--spacing-#{$size})) !important
        ),
        true,
        $responsive
      );
    }
  }
}

// === BASE CLASSES ===
@include generate-spacing-utilities();

// === RESPONSIVE CLASSES ===
@include generate-spacing-utilities(true);