@use 'jass_settings';
@use 'spacing_settings';
@use "sass:math";

$c: null;
@if spacing_settings.$enable-child-selectors == yes {
  $c: jass_settings.$child-selector-extension;
}

$m: null; $p: null; $w: null; $h: null;
$wmin: null; $wmax: null; $hmin: null; $hmax: null;
$pos:'top','right','bottom','left';
$spacings: null;
$dimensions: null;
$sfx: null;
$unit: null;
$i: null;

@function str-replace($string, $search, $replace: '') {
  $index: str-index($string, $search);
  @if $index {
    @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
  }
  @return $string;
}

@if spacing_settings.$selectors == short {
     $m: '.m';             $p: '.p';             $w: '.w';              $h: '.h';
  $wmin: '.wm';         $wmax: '.wx';         $hmin: '.hm';          $hmax: '.hx';
} @else if spacing_settings.$selectors == long {
     $m: '.margin-';       $p: '.padding-';      $w: '.width-';         $h: '.height-';
  $wmin: '.min-width-'; $wmax: '.max-width-'; $hmin: '.min-height-'; $hmax: '.max-height-';
} @else {
  @error "Selectors value needs to be > long or > short.";
}

// Loading spacing steps from the presets according the primary unit type chosen.
@if spacing_settings.$primary-unit-type == em {
  $spacings: spacing_settings.$spacings-em;
  $dimensions: spacing_settings.$spacings-em;
  $unit:em;
} @else if spacing_settings.$primary-unit-type == px {
  $spacings: spacing_settings.$spacings-px;
  $dimensions: spacing_settings.$dimensions-px;
  $unit:px;
} @else {
    @error "$primary-unit-type must be one of > em or > px." ;
}

// ############### spacings ################# //
// ------------------------------------------ //

$o: null;
@if spacing_settings.$override-spacing == yes {
  $o: !important;
}

// shortens position suffixes top, left. bottom, right in CSS properties
@function s($xy) {
  @if spacing_settings.$selectors == short {
    $xy: str-slice(#{$xy},1,1);
  } @else {$xy: $xy;}

  @return $xy;
}

@function get_unit_suffix($v) {
  $sfx: null;
  @if spacing_settings.$primary-unit-type == em { $sfx: str-replace(#{$v},'.','_'); }
  @else if spacing_settings.$primary-unit-type == px { $sfx: #{$v}; }
  @else { @error "$primary-unit-type must be one of > em or > px." ; }

  @return $sfx;
}

// Prepare mixins for later usage in the generation loops.
@mixin spacings ($sfx, $v, $i, $o) {
  @if spacing_settings.$spacing-index-classes == yes { $sfx: #{$i}; }
  #{$p}#{$sfx} { @each $xy in $pos          { padding-#{$xy}: $v$o; &#{$c} { @extend #{$p}#{$sfx}; } } }
  @each $xy in $pos { #{$p}#{s($xy)}#{$sfx} { padding-#{$xy}: $v$o; &#{$c} { @extend #{$p}#{s($xy)}#{$sfx}; } } }
  #{$m}#{$sfx} { @each $xy in $pos           { margin-#{$xy}: $v$o; &#{$c} { @extend #{$m}#{$sfx}; } } }
  @each $xy in $pos { #{$m}#{s($xy)}#{$sfx}  { margin-#{$xy}: $v$o; &#{$c} { @extend #{$m}#{s($xy)}#{$sfx}; } } }
}
@mixin negative-spacings ($sfx, $v, $i, $o) {
  @if spacing_settings.$spacing-index-classes == yes { $sfx: #{$i}; }
  @each $xy in $pos { #{$m}#{s($xy)}-#{$sfx} { margin-#{$xy}: -$v$o; &#{$c} { @extend #{$m}#{s($xy)}-#{$sfx}; } } }
}

// Render spacings based on generator steps in case spacing generator is enabled.
@if spacing_settings.$enable-spacing-generator == yes {
  @include spacings (0, 0, 0, $o);
  $i: null;
  $sfx: null;
  @for $i from 1 through spacing_settings.$generator-spacing-steps {
    $v: spacing_settings.$generator-spacing-rhythm * $i;
    $v: #{$v}#{spacing_settings.$primary-unit-type};
    $sfx: get_unit_suffix($v);
    @include spacings ($sfx,$v ,$i, $o);
    @include negative-spacings ($sfx, $v, $i, $o);
  }
// Render spacings based on preset in case spacing preset is enabled.
} @else if spacing_settings.$spacing-preset == yes {
  @include spacings (0, 0, 0, $o);
  $i: 1;
  $sfx: null;
  @each $v in $spacings {
    $v: #{$v}#{spacing_settings.$primary-unit-type};
    $sfx: get_unit_suffix($v);
    @include spacings ($sfx, $v, $i, $o);
    @include negative-spacings ($sfx, $v, $i, $o);
    $i: $i + 1;
  }
}

// ############### dimensions ############### //
// ------------------------------------------ //

$o: null;
@if spacing_settings.$override-dimensions == yes {
  $o: !important;
}

@mixin dimensions ($sfx, $v, $i, $o) {
  @if spacing_settings.$dimension-index-classes == yes { $sfx: #{$i}; }
     #{$h}#{$sfx} {     height: $v$o; &#{$c} { @extend    #{$h}#{$sfx}; } }
     #{$w}#{$sfx} {      width: $v$o; &#{$c} { @extend    #{$w}#{$sfx}; } }
  #{$hmin}#{$sfx} { min-height: $v$o; &#{$c} { @extend #{$hmin}#{$sfx}; } }
  #{$wmin}#{$sfx} {  min-width: $v$o; &#{$c} { @extend #{$wmin}#{$sfx}; } }
  #{$hmax}#{$sfx} { max-height: $v$o; &#{$c} { @extend #{$hmax}#{$sfx}; } }
  #{$wmax}#{$sfx} {  max-width: $v$o; &#{$c} { @extend #{$wmax}#{$sfx}; } }
}

@if spacing_settings.$enable-dimension-generator == yes {
  @include dimensions (0, 0, 0, $o);
  $i: null;
  $sfx: null;
  @for $i from 1 through spacing_settings.$generator-dimension-steps {
    $v: spacing_settings.$generator-dimension-rhythm * $i;
    $v: #{$v}#{spacing_settings.$primary-unit-type};
    $sfx: get_unit_suffix($v);
    @include dimensions ($sfx, $v, $i, $o);
  }
} @else if spacing_settings.$dimension-preset == yes {
  @include dimensions (0, 0, 0, $o);
  $i: 1;
  $sfx: null;
  @each $v in $dimensions {
    $v: #{$v}#{spacing_settings.$primary-unit-type};
    $sfx: get_unit_suffix($v);
    @include dimensions ($sfx, $v, $i, $o);
    $i: $i + 1;
  }
}

@if spacing_settings.$secondary-unit-type == percent {
  @if spacing_settings.$spacings-percent {
    $i: 1;
    $sfx: null;
    $base: math.div(100, spacing_settings.$spacings-percent);
    @for $d from 1 through spacing_settings.$spacings-percent {
       @if $d < spacing_settings.$dimensions-percent {
         $result: $base * $d;
         $v: $result * 1%;
         $sfx: #{$d}of#{spacing_settings.$dimensions-percent};
         @include spacings ($sfx, $v, $sfx, $o);
      } @else {
         @include spacings (full, 100%, null, $o);
      }
      $i: $i + 1;
    }
  }
  @if spacing_settings.$dimensions-percent {
    $i: 1;
    $sfx: null;
    $base: math.div(100, spacing_settings.$dimensions-percent);
    @for $d from 1 through spacing_settings.$dimensions-percent {
      @if $d < spacing_settings.$dimensions-percent {
        $result: $base * $d;
        $v: $result * 1%;
        $sfx: #{$d}of#{spacing_settings.$dimensions-percent};
        @include dimensions ($sfx, $v, $sfx, $o);
      } @else {
        @include dimensions (full, 100%, null, $o);
      }
      $i: $i + 1;
    }
  }
}
