@use 'sass:map';
@use 'sass:math';
@use 'sass:meta';
@use './typography';
@use '../../autocomplete/autocomplete-theme';
@use '../../badge/badge-theme';
@use '../../bottom-sheet/bottom-sheet-theme';
@use '../../button/button-theme';
@use '../../button/icon-button-theme';
@use '../../button/fab-theme';
@use '../../button-toggle/button-toggle-theme';
@use '../../card/card-theme';
@use '../../checkbox/checkbox-theme';
@use '../../chips/chips-theme';
@use '../../divider/divider-theme';
@use '../../table/table-theme';
@use '../../datepicker/datepicker-theme';
@use '../../dialog/dialog-theme';
@use '../../expansion/expansion-theme';
@use '../../grid-list/grid-list-theme';
@use '../../icon/icon-theme';
@use '../../input/input-theme';
@use '../../list/list-theme';
@use '../../menu/menu-theme';
@use '../../paginator/paginator-theme';
@use '../../progress-bar/progress-bar-theme';
@use '../../progress-spinner/progress-spinner-theme';
@use '../../radio/radio-theme';
@use '../../select/select-theme';
@use '../../sidenav/sidenav-theme';
@use '../../slide-toggle/slide-toggle-theme';
@use '../../slider/slider-theme';
@use '../../stepper/stepper-theme';
@use '../../sort/sort-theme';
@use '../../tabs/tabs-theme';
@use '../../toolbar/toolbar-theme';
@use '../../tooltip/tooltip-theme';
@use '../../snack-bar/snack-bar-theme';
@use '../../form-field/form-field-theme';
@use '../../tree/tree-theme';
@use '../theming/theming';
@use '../core-theme';
@use '../mdc-helpers/mdc-helpers';

// TODO(mmalerba): define-mdc-typography-config is defined here rather than in _typography.scss
//   (where define-typography-config is defined) because putting it there would cause a circular
//   dependency with mdc-helpers. We should refactor so these can live in the same place.

// Converts a map containing rem values to a map containing px values.
@function _rem-to-px($x, $px-per-rem: 16px) {
  @if meta.type-of($x) == 'map' {
    @each $key, $val in $x {
      $x: map.merge($x, ($key: _rem-to-px($val)));
    }
    @return $x;
  }
  @if meta.type-of($x) == 'number' and math.unit($x) == 'rem' {
    @return math.div($x, 1rem) * $px-per-rem;
  }
  @else {
    @return $x;
  }
}

/// Generates an Angular Material typography config based on values from the official Material
/// Design spec implementation (MDC Web). All arguments are optional, but may be passed to override
/// the default values. The `mat-typography-level` function can be used to generate a custom
/// typography level map which can be passed to this function to override one of the default levels.
/// All default typography sizing generated by this function is in `px` units.
///
/// @param {String} $font-family The font family to use for levels where it is not explicitly
///     specified.
/// @param {Map} $headline-1 The font settings for the headline-1 font level.
/// @param {Map} $headline-2 The font settings for the headline-2 font level.
/// @param {Map} $headline-3 The font settings for the headline-3 font level.
/// @param {Map} $headline-4 The font settings for the headline-4 font level.
/// @param {Map} $headline-5 The font settings for the headline-5 font level.
/// @param {Map} $headline-6 The font settings for the headline-6 font level.
/// @param {Map} $subtitle-1 The font settings for the subtitle-1 font level.
/// @param {Map} $subtitle-2 The font settings for the subtitle-2 font level.
/// @param {Map} $body-1 The font settings for the body-1 font level.
/// @param {Map} $body-2 The font settings for the body-2 font level.
/// @param {Map} $caption The font settings for the caption font level.
/// @param {Map} $button The font settings for the button font level.
/// @param {Map} $overline The font settings for the overline font level.
/// @return {Map} A map containing font settings for each of the levels in the Material Design spec.
@function define-typography-config(
  // TODO(mmalerba): rename this function to define-typography-config,
  //  and create a predefined px based config for people that need it.
  $font-family: null,
  $headline-1: null,
  $headline-2: null,
  $headline-3: null,
  $headline-4: null,
  $headline-5: null,
  $headline-6: null,
  $subtitle-1: null,
  $subtitle-2: null,
  $body-1: null,
  $body-2: null,
  $caption: null,
  $button: null,
  $overline: null,
) {
  // Declare an initial map with all of the levels.
  $overrides: if($font-family, (font-family: $font-family), ());

  @return (
    headline-1: $headline-1 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(headline1, $overrides)),
    headline-2: $headline-2 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(headline2, $overrides)),
    headline-3: $headline-3 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(headline3, $overrides)),
    headline-4: $headline-4 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(headline4, $overrides)),
    headline-5: $headline-5 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(headline5, $overrides)),
    headline-6: $headline-6 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(headline6, $overrides)),
    subtitle-1: $subtitle-1 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(subtitle1, $overrides)),
    subtitle-2: $subtitle-2 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(subtitle2, $overrides)),
    body-1: $body-1 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(body1, $overrides)),
    body-2: $body-2 or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(body2, $overrides)),
    caption: $caption or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(caption, $overrides)),
    button: $button or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(button, $overrides)),
    overline: $overline or _rem-to-px(
      mdc-helpers.typography-config-level-from-mdc(overline, $overrides)),
  );
}

/// Generates an Angular Material typography config based on values from the official Material
/// Design spec implementation (MDC Web). All arguments are optional, but may be passed to override
/// the default values. The `mat-typography-level` function can be used to generate a custom
/// typography level map which can be passed to this function to override one of the default levels.
/// All default typography sizing generated by this function is in `rem` units.
///
/// @param {String} $font-family The font family to use for levels where it is not explicitly
///     specified.
/// @param {Map} $headline-1 The font settings for the headline-1 font level.
/// @param {Map} $headline-2 The font settings for the headline-2 font level.
/// @param {Map} $headline-3 The font settings for the headline-3 font level.
/// @param {Map} $headline-4 The font settings for the headline-4 font level.
/// @param {Map} $headline-5 The font settings for the headline-5 font level.
/// @param {Map} $headline-6 The font settings for the headline-6 font level.
/// @param {Map} $subtitle-1 The font settings for the subtitle-1 font level.
/// @param {Map} $subtitle-2 The font settings for the subtitle-2 font level.
/// @param {Map} $body-1 The font settings for the body-1 font level.
/// @param {Map} $body-2 The font settings for the body-2 font level.
/// @param {Map} $caption The font settings for the caption font level.
/// @param {Map} $button The font settings for the button font level.
/// @param {Map} $overline The font settings for the overline font level.
/// @return {Map} A map containing font settings for each of the levels in the Material Design spec.
@function define-rem-typography-config(
  // TODO(mmalerba): rename this function to define-typography-config,
  //  and create a predefined px based config for people that need it.
  $font-family: null,
  $headline-1: null,
  $headline-2: null,
  $headline-3: null,
  $headline-4: null,
  $headline-5: null,
  $headline-6: null,
  $subtitle-1: null,
  $subtitle-2: null,
  $body-1: null,
  $body-2: null,
  $caption: null,
  $button: null,
  $overline: null,
) {
  // Declare an initial map with all of the levels.
  $overrides: if($font-family, (font-family: $font-family), ());

  @return (
    headline-1: $headline-1 or mdc-helpers.typography-config-level-from-mdc(headline1, $overrides),
    headline-2: $headline-2 or mdc-helpers.typography-config-level-from-mdc(headline2, $overrides),
    headline-3: $headline-3 or mdc-helpers.typography-config-level-from-mdc(headline3, $overrides),
    headline-4: $headline-4 or mdc-helpers.typography-config-level-from-mdc(headline4, $overrides),
    headline-5: $headline-5 or mdc-helpers.typography-config-level-from-mdc(headline5, $overrides),
    headline-6: $headline-6 or mdc-helpers.typography-config-level-from-mdc(headline6, $overrides),
    subtitle-1: $subtitle-1 or mdc-helpers.typography-config-level-from-mdc(subtitle1, $overrides),
    subtitle-2: $subtitle-2 or mdc-helpers.typography-config-level-from-mdc(subtitle2, $overrides),
    body-1: $body-1 or mdc-helpers.typography-config-level-from-mdc(body1, $overrides),
    body-2: $body-2 or mdc-helpers.typography-config-level-from-mdc(body2, $overrides),
    caption: $caption or mdc-helpers.typography-config-level-from-mdc(caption, $overrides),
    button: $button or mdc-helpers.typography-config-level-from-mdc(button, $overrides),
    overline: $overline or mdc-helpers.typography-config-level-from-mdc(overline, $overrides),
  );
}

// Includes all of the typographic styles.
@mixin all-component-typographies($config-or-theme: null) {
  $config: if(theming.private-is-theme-object($config-or-theme),
      theming.get-typography-config($config-or-theme), $config-or-theme);

  // If no actual color configuration has been specified, create a default one.
  @if not $config {
    $config: define-typography-config();
  }

  // TODO: COMP-309: Do not use individual mixins. Instead, use the all-theme mixin and only
  // specify a `typography` config while setting `color` and `density` to `null`. This is currently
  // not possible as it would introduce a circular dependency for typography because the `mat-core`
  // mixin that is transitively loaded by the `all-theme` file, imports `all-typography` which
  // would then load `all-theme` again. This ultimately results a circular dependency.
  @include badge-theme.typography($config);
  @include typography.typography-hierarchy($config);
  @include bottom-sheet-theme.typography($config);
  @include button-toggle-theme.typography($config);
  @include divider-theme.typography($config);
  @include datepicker-theme.typography($config);
  @include expansion-theme.typography($config);
  @include grid-list-theme.typography($config);
  @include icon-theme.typography($config);
  @include progress-spinner-theme.typography($config);
  @include sidenav-theme.typography($config);
  @include stepper-theme.typography($config);
  @include sort-theme.typography($config);
  @include toolbar-theme.typography($config);
  @include tree-theme.typography($config);
  @include core-theme.typography($config);
  @include card-theme.typography($config);
  @include progress-bar-theme.typography($config);
  @include tooltip-theme.typography($config);
  @include form-field-theme.typography($config);
  @include input-theme.typography($config);
  @include select-theme.typography($config);
  @include autocomplete-theme.typography($config);
  @include dialog-theme.typography($config);
  @include chips-theme.typography($config);
  @include slide-toggle-theme.typography($config);
  @include radio-theme.typography($config);
  @include slider-theme.typography($config);
  @include menu-theme.typography($config);
  @include list-theme.typography($config);
  @include paginator-theme.typography($config);
  @include tabs-theme.typography($config);
  @include checkbox-theme.typography($config);
  @include button-theme.typography($config);
  @include icon-button-theme.typography($config);
  @include fab-theme.typography($config);
  @include snack-bar-theme.typography($config);
  @include table-theme.typography($config);
}

// @deprecated Use `all-component-typographies`.
@mixin angular-material-typography($config-or-theme: null) {
  @include all-component-typographies($config-or-theme);
}
