@use 'sass:map';
@use 'sass:meta';
@use 'sass:math';
@use 'sass:list';
@use 'sass:string';
@use './types';
@use '../config' as *;

////
/// @package theming
/// @group Typography
////

/// Converts pixels to relative values (em).
/// @access public
/// @param {Number | String} $pixels - The pixel value to be converted.
/// @param {Number | String} $context [$browser-context] - The base context to convert against.
/// @example scss
///   .my-component {
///     margin: em(10px) em(5px);
///   }
///
///   // Output
///   .my-component {
///     margin: 0.625em 0.3125em;
///   }
///
/// @return {number} Returns the pixels value converted to em.
@function em($pixels, $context: $base-font-size) {
    @if math.is-unitless($pixels) {
        $pixels: $pixels * 1px;
    }

    @if math.is-unitless($context) {
        $context: $context * 1px;
    }

    @return math.div($pixels, $context) * 1em;
}

/// Converts pixels to root relative values (rem).
/// @access public
/// @param {number|string} $pixels - The pixel value to be converted.
/// @param {number|string} $context [$browser-context] - The base context to convert against.
/// @example scss
///   .my-component {
///     margin: rem(10px) rem(5px);
///   }
///
///   // Output
///   .my-component {
///     margin: 0.625rem 0.3125rem;
///   }
///
/// @return {number} Returns the pixels value converted to rem.
@function rem($pixels, $context: $base-font-size) {
    @if math.is-unitless($pixels) {
        $pixels: $pixels * 1px;
    }

    @if math.is-unitless($context) {
        $context: $context * 1px;
    }

    @return math.div($pixels, $context) * 1rem;
}

/// Converts relative value (em/rem) to pixel.
/// @access public
/// @param {number|string} $num - The relative value to be converted.
/// @param {number|string} $context [$browser-context] - The base context to convert against.
/// @example scss
///   .my-component {
///     margin: px(3rem);
///   }
///
///   // Output
///   .my-component {
///     margin: 48px;
///   }
///
/// @return {number} Returns the relative value converted to pixels.
@function px($num, $context: $base-font-size) {
    @if math.is-unitless($context) {
        $context: $context * 1px;
    }

    @if meta.type-of($num) == 'number' {
        @return math.div($num, $num * 0 + 1) * $context;
    }

    @return $num;
}

/// Produces a type style map of values that adheres to the ITypeStyle map.
/// @access public
/// @param {String} $font-family [var(--ig-font-family)] - The font family of the type style.
/// @param {String} $font-size - The font size of the type style.
/// @param {Number | String} $font-weight [normal] - The font weight of the type style.
/// @param {String} $font-style [normal] - The font style of the type style.
/// @param {Number | String} $line-height [normal] - The line height of the type style.
/// @param {Number | String} $letter-spacing [normal] - The letter spacing of the type style.
/// @param {String} $text-transform [none] - The text-transform property of the type style.
/// @param {Number} $margin-top [0] - The margin-top property of the type style.
/// @param {Number} $margin-bottom [0] - The margin-bottom property of the type style.
/// @requires $ITypeStyle
/// @example scss
///   $main_navigation: type-style(
///      $font-size: rem(14px),
///      $font-weight: 600,
///      $letter-spacing: rem(.1px),
///      $line-height: rem(14px),
///      $text-transform: none,
///   );
///
///   // Use the type-style() mixin to consume the new type style produced from the type-style() function.
///   .main-nav {
///     @include type-style($main_navigation);
///   }
/// @returns {Map} A map of all defined type style properties.
@function type-style($args...) {
    $keywords: meta.keywords($args);
    $result: ();

    @each $style, $value in types.$ITypeStyle {
        $overwrite: map.get($keywords, $style);
        $value: if($overwrite, $overwrite, $value);

        @if not($value) {
            @error 'Missing argument $#{$style}.';
        }

        $result: map.merge(
            $result,
            (
                $style: $value,
            )
        );
    }

    @return $result;
}

/// Produces a type scale map containing type styles that adheres to the ITypeScale list.
/// @access public
/// @param {Map} $h1 - A map containing type style properties as produced by the type-style function.
/// @param {Map} $h2 - A map containing type style properties as produced by the type-style function.
/// @param {Map} $h3 - A map containing type style properties as produced by the type-style function.
/// @param {Map} $h4 - A map containing type style properties as produced by the type-style function.
/// @param {Map} $h5 - A map containing type style properties as produced by the type-style function.
/// @param {Map} $h6 - A map containing type style properties as produced by the type-style function.
/// @param {Map} $subtitle-1 - A map containing type style properties as produces by the type-style function.
/// @param {Map} $subtitle-2 - A map containing type style properties as produces by the type-style function.
/// @param {Map} $body-1 - A map containing type style properties as produces by the type-style function.
/// @param {Map} $body-2 - A map containing type style properties as produces by the type-style function.
/// @param {Map} $button - A map containing type style properties as produces by the type-style function.
/// @param {Map} $caption - A map containing type style properties as produces by the type-style function.
/// @param {Map} $overline - A map containing type style properties as produces by the type-style function.
/// @param {String} $_theme [null] - The theme related to this type scale. Internal use only.
/// @requires $ITypeScale
/// @example scss
///   // First define type styles to use
///   $my-body-1: type-style(
///      $font-size: rem(14px),
///   );
///
///   // Use the type style map to override one of the existing maps
///   $type-scale: type-scale(
///	    ...
///	    $body-1: $my-body-1,
///	    ...
///   );
/// @returns {Map} A map of all defined type scales.
@function type-scale($_theme: null, $args...) {
    $style_fn: meta.get-function('type-style');
    $categories: meta.keywords($args);
    $result: (
        _meta: (
            variant: $_theme,
        ),
    );

    @each $category in types.$ITypeScale {
        $value: map.get($categories, $category);

        @if not($value) {
            @error 'Missing argument $#{$category}.';
        }

        $result: map.merge(
            $result,
            (
                $category: meta.call($style_fn, $value...),
            )
        );
    }

    @return $result;
}

/// Get type scale category config.
/// @param {Map} $scale - A type scale map reference as produces by type-scale.
/// @param {String} $category - The scale category you want config for. For instance - 'h1';
/// @example scss - Get the type scale category config for the `h1` scale.
///   $h1-type-scale: type-scale-category($type-scale, 'h1');
/// @returns {Map} The config map for the selected category in the type scale.
@function type-scale-category($scale, $category) {
    @return map.get($scale, $category);
}
