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

////
/// @group utils.fonts
////

@function -gf-list-unique($list) {
    $result: ();
    @each $item in $list {
        @if not list.index($result, $item + '') {
            $result: list.append($result, $item + '');
        }
    }
    @each $item in $result {
        $result: list.set-nth($result, list.index($result, $item), string.unquote($item));
    }
    @return $result;
}
@function -gf-str-replace($string, $search, $replace: '') {
    $index: string.index($string, $search);
    @return if(
        sass($index): string.slice($string, 1, $index - 1) + $replace +
            -gf-str-replace(
                string.slice($string, $index + string.length($search)),
                $search,
                $replace
            )
            ; else: $string
    );
}
@function -gf-str-explode($string) {
    $list: ();
    @for $i from 1 through string.length($string) {
        $list: list.append($list, string.slice($string, $i, $i));
    }
    @return $list;
}

/// The font subset to load. Note that the latin subset is always included if available and need not
/// be specified. Also, if a client browser supports supports unicode-range then this subset
/// parameter is ignored and the browser will select from the subsets supported by the font to get
/// what it needs to render the text.

$google-font-subsets: (
    'arabic': false,
    'bengali': false,
    'cyrillic': false,
    'cyrillic-ext': false,
    'devanagari': false,
    'greek': false,
    'greek-ext': false,
    'gujarati': false,
    'hebrew': false,
    'khmer': false,
    'latin': false,
    'latin-ext': false,
    'tamil': false,
    'telugu': false,
    'thai': false,
    'vietnamese': false,
) !default;

/// Mixin for loading google fonts.
///
/// @param {string} $name [null] Name of the font (must match google)
///
/// @param {list or number} $weights [400]  A list of weights to be loaded (or
/// single weight)
///
/// @param {list or string} $styles [normal] A list of styles to be loaded (or
/// single style)
///
/// @param {*} $text [null] Subsetting text
///
/// @example
/// %%include google-font(Lato, 300);
///
/// @example
/// %%include google-font(Open Sans, 400, italic)
///
/// @example
/// %%include google-font(Slapo 27px, 400 200, $text: 'Lorem ipsum dolor sit amet');
///
/// @example
/// // By placing google-font includes inside a google-font include (without arguments nested includes will be merged into a single import
/// %%include google-font {
///     %%include google-font(Material Icons);
///     %%include google-font(Open Sans, 300 400 700, normal);
///     %%include google-font(Open Sans, 300 400 700, italic normal);
///     %%include google-font(Lato, 300 400i 700i);
///     %%include google-font(Lato, 300 700, italic normal);
/// }
///
/// => @import url("//fonts.googleapis.com/css?family=Material+Icons:400|Open+Sans:300,400,700,300i,400i,700i|Lato:300,400")

@mixin google-font($name: null, $weights: 400, $styles: normal, $text: null) {
    //  base url
    $URL: 'https://fonts.googleapis.com/css?family=';

    //  create global variables
    @if not meta.variable-exists(-gf-combine) {
        $-gf-combine: false !global;
    }
    @if not meta.variable-exists(-gf-map) {
        $-gf-map: () !global;
    }
    @if not meta.variable-exists(google-font-subsets) {
        $google-font-subsets: () !global;
    }

    //  append italic to weights
    @if list.index($styles, italic) and not string.index($weights + '', i) {
        $wgt: if(sass(list.index($styles, normal)): $weights; else: ());
        @each $weight in $weights {
            $wgt: list.append($wgt, $weight + i);
        }
        $weights: $wgt;
    }

    //  reduce and encode text
    @if $text {
        $list: -gf-list-unique(-gf-str-explode($text));
        $text: '&text=';
        $encode: (
            '!': '%21',
            '#': '%23',
            '$': '%24',
            '&': '%26',
            "'": '%27',
            '(': '%28',
            ')': '%29',
            '*': '%2A',
            '+': '%2B',
            ',': '%2C',
            '/': '%2F',
            ':': '%3A',
            ';': '%3B',
            '=': '%3D',
            '?': '%3F',
            '@': '%40',
            '[': '%5B',
            ']': '%5D',
            ' ': '%20',
        );
        @for $i from 1 through list.length($list) {
            $char: map.get($encode, list.nth($list, $i)) or list.nth($list, $i);
            $text: $text + $char;
        }
    }

    //  subsets from config
    $subset: '';
    @each $set, $enabled in $google-font-subsets {
        @if $enabled {
            $subset: $subset + if(sass($subset == ''): '' ; else: ',') + $set;
        }
    }
    $subset: if(
        sass(string.length($subset) > 0 and $subset != latin): '&subset=' + $subset; else: ''
    );

    @if $name {
        //  replace name whitespaces
        $name: if(sass(meta.type-of($name) == string): string.unquote($name) ; else: $name);
        $name: -gf-str-replace(meta.inspect($name), ' ', '+');
        @if $-gf-combine and not $text {
            //  add weights to combine map
            $wgt: map.get($-gf-map, $name) or ();
            $wgt: -gf-list-unique(list.join($wgt, $weights, comma));
            $-gf-map: map.merge(
                $-gf-map,
                (
                    $name: $wgt,
                )
            ) !global;
        } @else {
            //  create query
            $query: '';
            @each $weight in $weights {
                $query: $query + if(sass($query != ''): ',' ; else: '') + $weight;
            }
            $query: -gf-str-replace($query, ' ');
            $query: $name +
                if(sass(string.length($query) > 0 and $query != '400'): ':' + $query; else: '');

            //  create single import
            @at-root {
                /* url(#{$URL}+#{$query}+#{if(sass($text): $text; else: '')}+#{$subset}) */
                @import url($URL + $query + if(sass($text): $text; else: '') + $subset);
            }
        }
    } @else {
        //  set combine flag
        $-gf-combine: true !global;

        //  nested includes
        @content;

        //  convert combine map to query
        //  (remove weights if just 400)
        $query: '';
        @each $font, $weights in $-gf-map {
            $query: $query +
                if(sass($query != ''): '|' ; else: '') +
                $font +
                if(
                    sass(list.length($weights) == 1 and (list.nth($weights, 1) == '400')): ''
                        ;
                        else: ':' +
                        list.join((), $weights, comma)
                );
        }

        //  remove query whitespaces
        $query: -gf-str-replace($query, ' ');

        //  create combined import
        @at-root {
            @import url($URL + $query + $subset);
        }

        //  reset combine flag
        $-gf-combine: false !global;
    }
}
