@use 'sass:map';
@use 'sass:meta';
////
/// @group modules.atoms
////

@use '../utils' as *;

// ---------------------------------------------------------------------------
// API
// ---------------------------------------------------------------------------

/// Generate atomic classes for flexbox. Full list of classes:
///
/// | Class | Equivalent Css |
/// | ----- | -------------- |
/// | .flex | display: flex; |
/// | .flex-inline | display: inline-flex; |
/// | .flex-row | flex-direction: row; |
/// | .flex-row-reverse | flex-direction: row-reverse; |
/// | .flex-column | flex-direction: column; |
/// | .flex-column-reverse | flex-direction: column-reverse; |
/// | .flex-wrap | flex-wrap: wrap; |
/// | .flex-wrap-column | flex-wrap: wrap; flex-direction: column; |
/// | .flex-wrap-reverse | flex-wrap: wrap-reverse; |
/// | .flex-nowrap | flex-wrap: nowrap; |
/// | .flex-auto | flex: 1 1 auto; |
/// | .flex-none | flex: none; |
/// | .flex-grow-[0...4] | flex-grow: [0...4] |
/// | .flex-shrink-[0...4] | flex-shrink: [0...4]; |
/// | .items-start | align-items: flex-start; |
/// | .items-end | align-items: flex-end; |
/// | .items-center | align-items: center; |
/// | .items-baseline | align-items: baseline; |
/// | .items-stretch | align-items: stretch; |
/// | .justify-start | justify-content: flex-start; |
/// | .justify-end | justify-content: flex-end; |
/// | .justify-center | justify-content: center; |
/// | .justify-between | justify-content: space-between; |
/// | .justify-around | justify-content: space-around; |
/// | .justify-stretch | justify-content: stretch; |
/// | .self-start | align-self: flex-start; |
/// | .self-end | align-self: flex-end; |
/// | .self-center | align-self: center; |
/// | .self-baseline | align-self: baseline; |
/// | .self-stretch | align-self: stretch; |
/// | .order-[0...9] | order: [0...9]; |
/// | .order-first | order: -99999; |
/// | .order-last | order: 99999; |
/// | .flex-center | display: flex; align-items: center; |
///
/// @param {*} $prefix [''] A prefix that can be applied to each of the classes
/// generated by the mixin.
///
/// @example @include atoms-flex('className') // (results limited to only first in list) =>
/// .classNameflex {
/// display: flex;
/// }

@mixin atoms-flex(
    $prefix: 'flex',
    $order-classes: false,
    $align-self-classes: false,
    $grow-shrink-classes: false
) {
    // Display

    .#{$prefix} {
        display: flex;
    }

    .#{$prefix}-inline {
        display: inline-flex;
    }

    // Direction

    .#{$prefix}-row {
        flex-direction: row;
        &:not(.#{$prefix}-inline) {
            display: flex;
        }
    }
    .#{$prefix}-row-reverse {
        flex-direction: row-reverse;
        &:not(.#{$prefix}-inline) {
            display: flex;
        }
    }
    .#{$prefix}-column {
        flex-direction: column;
        &:not(.#{$prefix}-inline) {
            display: flex;
        }
    }
    .#{$prefix}-column-reverse {
        flex-direction: column-reverse;
        &:not(.#{$prefix}-inline) {
            display: flex;
        }
    }

    // Wrapping

    .#{$prefix}-wrap {
        flex-wrap: wrap;
        flex-direction: row;
    }
    .#{$prefix}-wrap-column {
        flex-wrap: wrap;
        flex-direction: column;
    }
    .#{$prefix}-wrap-reverse {
        flex-wrap: wrap-reverse;
    }
    .#{$prefix}-nowrap {
        flex-wrap: nowrap;
    }

    .#{$prefix}-auto {
        flex: 1 1 auto;
    }

    .#{$prefix}-none {
        flex: none;
    }

    // Align items

    .#{$prefix}-items-start {
        align-items: flex-start;
    }

    .#{$prefix}-items-end {
        align-items: flex-end;
    }

    .#{$prefix}-items-center {
        align-items: center;
    }

    .#{$prefix}-items-baseline {
        align-items: baseline;
    }

    .#{$prefix}-items-stretch {
        align-items: stretch;
    }

    // Justify items

    .#{$prefix}-justify-start {
        justify-content: flex-start;
    }

    .#{$prefix}-justify-end {
        justify-content: flex-end;
    }

    .#{$prefix}-justify-center {
        justify-content: center;
    }

    .#{$prefix}-justify-between {
        justify-content: space-between;
    }

    .#{$prefix}-justify-around {
        justify-content: space-around;
    }

    .#{$prefix}-justify-stretch {
        justify-content: stretch;
    }

    // Align self

    @if ($align-self-classes) {
        .#{$prefix}-self-start {
            align-self: flex-start;
        }

        .#{$prefix}-self-end {
            align-self: flex-end;
        }

        .#{$prefix}-self-center {
            align-self: center;
        }

        .#{$prefix}-self-baseline {
            align-self: baseline;
        }

        .#{$prefix}-self-stretch {
            align-self: stretch;
        }
    }

    // Grow / Shrink

    @if ($grow-shrink-classes) {
        @for $f from 0 to 4 {
            .#{$prefix}-grow-#{$f} {
                flex-grow: $f;
            }
            .#{$prefix}-shrink-#{$f} {
                flex-shrink: $f;
            }
        }

        @for $g from 0 to 4 {
            @for $s from 0 to 4 {
                .#{$prefix}-#{$g}-#{$s} {
                    flex-grow: $g;
                    flex-shrink: $s;
                }
            }
        }
    }

    // Order

    @if ($order-classes) {
        .#{$prefix}-order-0 {
            order: 0;
        }

        .#{$prefix}-order-1 {
            order: 1;
        }

        .#{$prefix}-order-2 {
            order: 2;
        }

        .#{$prefix}-order-3 {
            order: 3;
        }

        .#{$prefix}-order-4 {
            order: 4;
        }

        .#{$prefix}-order-5 {
            order: 5;
        }

        .#{$prefix}-order-6 {
            order: 6;
        }

        .#{$prefix}-order-7 {
            order: 7;
        }

        .#{$prefix}-order-8 {
            order: 8;
        }

        .#{$prefix}-order-first {
            order: -99999;
        }

        .#{$prefix}-order-last {
            order: 99999;
        }
    }

    // Combos

    .#{$prefix}-center {
        display: flex;
        align-items: center;
    }
}

$-spacer-props: (
    p: padding,
    m: margin,
);

$-spacer-variants: (
    all: (
        top,
        bottom,
        left,
        right,
    ),
    v: (
        top,
        bottom,
    ),
    h: (
        left,
        right,
    ),
    t: (
        top,
    ),
    b: (
        bottom,
    ),
    l: (
        left,
    ),
    r: (
        right,
    ),
);

$-spacer-vals: (0, 0.25, 0.5, 1, 2, 3, 4);

/// Generate atomic classes for margin and padding. Full list of classes:
/// @example @include atoms-spacers(12px) // => lots of classes
@mixin atoms-spacers(
    $space,
    $vals: $-spacer-vals,
    $props: $-spacer-props,
    $variants: $-spacer-variants,
    $coolnames: true,
    $prefix: ''
) {
    @each $base, $prop in $props {
        @each $variant, $variant-list in $variants {
            @each $val in $vals {
                @include -atoms-spacer($space, $base, $variant, $val, $coolnames, $prefix);
            }
        }
    }

    @each $val in $vals {
        // convert value to as string for classname
        $valstr: -spacer-class-str($val, $coolnames);

        // convert numerical values to the output value using sp() function
        $val: -spacer-val($val, $space);

        .items-mbr-#{$valstr} > * {
            &:not(:last-child) {
                margin-right: $val;
                margin-bottom: $val;
            }
        }

        .items-mr-#{$valstr} > * {
            &:not(:last-child) {
                margin-right: $val;
            }
        }

        .items-mb-#{$valstr} > * {
            &:not(:last-child) {
                margin-bottom: $val;
            }
        }

        .items-mh-#{$valstr} > * {
            margin-left: $val * 0.5;
            margin-right: $val * 0.5;
            &:last-child {
                margin-right: 0;
            }
            &:first-child {
                margin-left: 0;
            }
        }

        .items-mv-#{$valstr} > * {
            margin-top: $val * 0.5;
            margin-bottom: $val * 0.5;
            &:first-child {
                margin-top: 0;
            }
            &:last-child {
                margin-bottom: 0;
            }
        }

        .items-m-#{$valstr} > * {
            margin: $val * 0.5;
        }
    }
}

@function -spacer-class-str($val, $coolnames) {
    // convert value to as string for classname
    $valstr: #{$val};
    $valstr: str-replace($valstr, '-', 'neg');
    $valstr: if(
        sass($coolnames): str-replace($valstr, '.', '\\.') ; else: str-replace($valstr, '.', '_')
    );
    @return $valstr;
}

@function -spacer-val($val, $space) {
    @return if(sass(meta.type-of($val) == 'number'): $val * $space; else: $val);
}

@mixin -atoms-spacer(
    $space,
    $base,
    $variant,
    $val,
    $coolnames,
    $prefix: '',
    $parent-sel: '',
    $child-sel: ''
) {
    // lookup the property name
    $prop-base: map.get($-spacer-props, $base);

    // lookup the variants
    $prop-variants: map.get($-spacer-variants, $variant);

    // change all to empty string now that the lookup is done
    $variant: if(sass($variant == 'all'): '' ; else: $variant);

    // convert value to as string for classname
    $valstr: -spacer-class-str($val, $coolnames);

    // convert numerical values to the output value using sp() function
    $val: -spacer-val($val, $space);

    // create the class
    #{$parent-sel} .#{$prefix}#{$base}#{$variant}-#{$valstr} #{$child-sel} {
        @each $variant in $prop-variants {
            #{$prop-base}-#{$variant}: $val;
        }
    }
}
