@use 'sass:map';
////
/// @group modules.boilerplate
////

@use '../utils' as *;
@use '../site' as *;
@use 'sanitize' as *;

// ---------------------------------------------------------------------------
// HELPERS
// ---------------------------------------------------------------------------

// body and root styles setup fonts, page background, etc.

@mixin -root-styles() {
    // set the root font size (will become the basis for rem units)

    // if a font-size-scale has been defined then we create a scalable font-size
    @if (get(font-size-scale)) {
        $min: get('font-size-scale.min');
        $max: get('font-size-scale.max');
        $max-at: get('font-size-scale.max-at', null);
        font-size: scale-vw($min, $max, $max-at);
    }

    // otherwise, just a hard-coded font-size
    @else {
        font-size: get(font-size-base);
    }
}

@mixin -body-root-styles() {
    font-family: get(font-family);
    font-weight: get(font-weight);
    line-height: get(line-height);
    letter-spacing: get(letter-spacing);

    @if (get(font-smoothing)) {
        @include font-smoothing-on();
    }

    background-color: clr(page-bg);
    color: clr(page-fg);
}

// ---------------------------------------------------------------------------
// PUBLIC API
// ---------------------------------------------------------------------------

/// Generates boilerplate css for a site. Generally this only needs to be called once as part of the
/// site's global css. Many components and styles have a soft dependency on this (e.g. may expect
/// that a reset has been applied, etc.). This mixin relies on some shared settings from the site
/// module, so it should be included after that module.
///
/// @param {*} $scoped [false] If true we generate all rules directly within the provides scope rather than use the :root selector.
/// @param {string} $root-modifier [null] When set, all root-level selectors (html, body, *)
///     are scoped so they only apply when the modifier is present on the html element.
///     Example: `$root-modifier: '[data-layout="fluent"]'` outputs `html[data-layout="fluent"] { ... }`.
///     Pair with `@layer` at the call site to avoid specificity issues from the added selector.
/// @param {*} $sanitize [true] If true, include the sanitize general site reset.
/// @param {*} $reset [(link,button,lists,headings,paragraph)] The list of additional resets to include.
/// @param {*} $fonts [()] The list of fonts to be loaded.
/// @param {*} $type-styles [null] A map containing a set of type styles where the key is the name and the value is the style. Leave null to use the default config. Set to false to skip.
/// @param {*} $code-style ['code'] A type-style to apply to code and pre elements (must be contained in the $type-styles map). Set to false to skip.
/// @param {*} $link-selector ['.link'] A selector to use for generated .link style to. Set to false to skip.
/// @param {*} $container-selector ['.container'] A selector to use for a generated container style to. Set to false to skip.
/// @param {*} $button-selector ['.button'] A selector to use for a generated button style. Set to false to skip.
/// @param {*} $hide-selector ['.visually-hidden'] A selector to use for a generated style that hides things visually but allows them to stay visible for screen readers. Set to false to skip.
///
/// @example
///     // standard usage (no scoping)
///     @include boilerplate();
///
/// @example
///     // scoped to a data attribute on html, wrapped in @layer
///     @include boilerplate($root-modifier: '[data-layout="fluent"]');

@mixin boilerplate(
    $scoped: false,
    $root-modifier: null,
    $sanitize: true,
    $reset: (
        link,
        button,
        lists,
        headings,
        paragraph,
    ),
    $fonts: null,
    $type-styles: null,
    $code-style: 'code',
    $link-selector: '.link',
    $container-selector: '.container',
    $button-selector: '.button',
    $hide-selector: '.visually-hidden'
) {
    // when root-modifier is set, prefix element selectors so rules only apply
    // when the modifier is present on html
    $root: if(sass($root-modifier): 'html#{$root-modifier} ' ; else: '');

    // ---------------------------------------------------------------------------
    // fonts (always global — @font-face can't be scoped and is harmless)
    // ---------------------------------------------------------------------------

    $fonts: if-null($fonts, get('fonts', null));

    @if ($fonts) {
        @at-root {
            // local fonts
            @each $font-name, $variants in $fonts {
                $variants-list: if(
                    sass(is-map($variants)): (
                            $variants,
                            (),
                        )
                        ;
                        else: $variants
                );
                @each $options in $variants-list {
                    @if (map.has-key($options, src)) {
                        $src: map.get($options, src);
                        $weight: map-get-default($options, 'weight', null);
                        $style: map-get-default($options, style, null);
                        $exts: map-get-default($options, exts, woff ttf);
                        @include font-face($font-name, $src, $weight, $style, $exts);
                    }
                }
            }

            // google fonts
            @each $font-name, $variants in $fonts {
                $variants-list: if(
                    sass(is-map($variants)): (
                            $variants,
                            (),
                        )
                        ;
                        else: $variants
                );
                @each $options in $variants-list {
                    @if (map.has-key($options, googleFont) and map.get($options, googleFont)) {
                        $weight: map-get-default($options, 'weight', '400');
                        $style: map-get-default($options, style, 'normal');
                        @include google-font($name: $font-name, $weights: $weight, $styles: $style);
                    }
                }
            }
        }
    }

    // ---------------------------------------------------------------------------
    // sanitize
    // ---------------------------------------------------------------------------

    @if ($sanitize) {
        @include sanitize($root-modifier: $root-modifier);
    }

    // ---------------------------------------------------------------------------
    // reset links
    // ---------------------------------------------------------------------------

    @if (list-contains($reset, 'link')) {
        #{$root}a {
            color: inherit;
        }
        #{$root}a,
        #{$root}a:hover {
            text-decoration: inherit;
        }
    }

    // ---------------------------------------------------------------------------
    // headings reset
    // ---------------------------------------------------------------------------

    @if (list-contains($reset, 'headings')) {
        #{$root}h1,
        #{$root}h2,
        #{$root}h3,
        #{$root}h4,
        #{$root}h5,
        #{$root}h6 {
            font-size: inherit;
            margin: 0;
            padding: 0;
            line-height: get('line-height');
        }
    }

    // ---------------------------------------------------------------------------
    // paragraph reset
    // ---------------------------------------------------------------------------

    @if (list-contains($reset, 'paragraph')) {
        #{$root}p {
            font-size: inherit;
            padding: 0;
            margin: 0;
        }
    }

    // ---------------------------------------------------------------------------
    // button reset
    // ---------------------------------------------------------------------------

    @if (list-contains($reset, 'button')) {
        #{$root}button {
            appearance: none;
            display: block;
            outline: none;
            border: none;
            border-radius: 0;
            background: none transparent;
            background-color: transparent;
            padding: 0;
            width: auto;
            height: auto;
            border-spacing: 0;
            text-align: left;
            text-indent: 0;
            line-height: 1;
            color: inherit;
            font-family: inherit;
            font-size: inherit;
        }
    }

    // ---------------------------------------------------------------------------
    // list reset
    // ---------------------------------------------------------------------------

    @if (list-contains($reset, 'lists')) {
        #{$root}ul,
        #{$root}ol {
            padding: 0;
            margin: 0;
            list-style: none;
            li {
                padding: 0;
                margin: 0;
            }
        }
    }

    // ---------------------------------------------------------------------------
    // root styles
    // ---------------------------------------------------------------------------

    // if $scoped, we generate font directly within the element
    @if ($scoped) {
        @include -root-styles();
        @include -body-root-styles();
    }

    // otherwise, generate within root elements
    @else {
        @at-root {
            html#{$root-modifier} {
                @include -root-styles();
            }

            html#{$root-modifier},
            html#{$root-modifier} body {
                @include -body-root-styles();
            }

            // set the body font size to be 1rem
            #{$root}body {
                font-size: 1rem;
            }
        }
    }

    // customize the text selection color
    #{$root}::selection {
        background: get('colors.selection-bg');
        color: get('colors.selection-fg');
    }

    // ---------------------------------------------------------------------------
    // code
    // ---------------------------------------------------------------------------

    @if ($code-style) {
        // code, pre
        #{$root}pre,
        #{$root}code {
            @include type-style($code-style);
        }
    }

    // ---------------------------------------------------------------------------
    // other defaults
    // ---------------------------------------------------------------------------

    // defaults for hr
    #{$root}hr {
        height: 0;
        margin: 2rem 0;
        padding: 0;
        border: none;
        border-top: 1px solid currentColor;
    }

    // prevent sup from affecting line-height
    #{$root}sup {
        line-height: 0.5;
    }

    // ---------------------------------------------------------------------------
    // type styles
    // ---------------------------------------------------------------------------

    $type-styles: if-null($type-styles, get('typography.type-styles'));
    @if ($type-styles) {
        @include type-styles($type-styles, $root: $root);
    }

    // ---------------------------------------------------------------------------
    // links
    // ---------------------------------------------------------------------------

    @if ($link-selector) {
        #{$root}#{$link-selector} {
            @include link();
        }
    }

    // ---------------------------------------------------------------------------
    // button class
    // ---------------------------------------------------------------------------
    @if ($button-selector) {
        #{$root}#{$button-selector} {
            // @warn 'TODO: need to reenable button in boilerplate.scss';
            // TODO v3
            //@include button();
        }
    }

    // ---------------------------------------------------------------------------
    // container class
    // ---------------------------------------------------------------------------
    @if ($container-selector) {
        #{$root}#{$container-selector} {
            @include container();
        }
    }

    // ---------------------------------------------------------------------------
    // hide class
    // ---------------------------------------------------------------------------

    @if ($hide-selector) {
        #{$root}#{$hide-selector} {
            position: absolute !important;
            height: 1px;
            width: 1px;
            overflow: hidden;
            clip: rect(1px, 1px, 1px, 1px);
        }
    }
}
