@use 'sass:map';
@use 'sass:meta';
@use 'sass:color';
@use 'palette';

// For a given hue in a palette, return the contrast color from the map of contrast palettes.
// @param $palette
// @param $hue
@function get-contrast-color-from-palette($palette, $hue) {
  @return map.get(map.get($palette, contrast), $hue);
}


// Creates a map of hues to colors for a theme. This is used to define a theme palette in terms
// of the Material Design hues.
// @param $color-map
// @param $primary
// @param $lighter
@function define-palette($base-palette, $default: 500, $lighter: 100, $darker: 700, $text: $default) {
  $result: map.merge($base-palette, (
    default: map.get($base-palette, $default),
    lighter: map.get($base-palette, $lighter),
    darker: map.get($base-palette, $darker),
    text: map.get($base-palette, $text),

    default-contrast: get-contrast-color-from-palette($base-palette, $default),
    lighter-contrast: get-contrast-color-from-palette($base-palette, $lighter),
    darker-contrast: get-contrast-color-from-palette($base-palette, $darker)
  ));

  // For each hue in the palette, add a "-contrast" color to the map.
  @each $hue, $color in $base-palette {
    $result: map.merge($result, (
      '#{$hue}-contrast': get-contrast-color-from-palette($base-palette, $hue)
    ));
  }

  @return $result;
}

// Gets a color from a theme palette (the output of mat-palette).
// The hue can be one of the standard values (500, A400, etc.), one of the three preconfigured
// hues (default, lighter, darker), or any of the aforementioned prefixed with "-contrast".
//
// @param $palette The theme palette (output of mat-palette).
// @param $hue The hue from the palette to use. If this is a value between 0 and 1, it will
//     be treated as opacity.
// @param $opacity The alpha channel value for the color.
@function get-color-from-palette($palette, $hue: default, $opacity: null) {
  // If hueKey is a number between zero and one, then it actually contains an
  // opacity value, so recall this function with the default hue and that given opacity.
  @if meta.type-of($hue) == number and $hue >= 0 and $hue <= 1 {
    @return get-color-from-palette($palette, default, $hue);
  }

  $color: map.get($palette, $hue);

  @if (meta.type-of($color) != color) {
    // If the $color resolved to something different from a color (e.g. a CSS variable),
    // we can't apply the opacity anyway so we return the value as is, otherwise Sass can
    // throw an error or output something invalid.
    @return $color;
  }

  @return rgba($color, if($opacity == null, color.opacity($color), $opacity));
}

// Creates a container object for a light theme to be given to individual component theme mixins.
@function define-light-theme($primaryOrTheme, $accent: define-palette(palette.$blue-palette), $warn: define-palette(palette.$blue-palette)) {
  $primary: null;

  @if map.has-key($primaryOrTheme, primary) {
    $primary: map.get($primaryOrTheme, primary);
    $accent: map.get($primaryOrTheme, accent);
    $warn: map.get($primaryOrTheme, warn);
  } @else {
    $primary: $primaryOrTheme;
  }

  $pbl-updated-theme-background: (
  );

  $pbl-updated-theme-foreground: (
    ngrid-cell-focus-color: get-color-from-palette($primary)
  );

  $foreground: map.merge(map.get(palette.$light-theme-palette, foreground), $pbl-updated-theme-foreground);
  $background: map.merge(map.get(palette.$light-theme-palette, background), $pbl-updated-theme-background);

  @if map.has-key($primaryOrTheme, primary) {
    $foreground: map.merge($foreground, map.get($primaryOrTheme, foreground));
    $background: map.merge($background, map.get($primaryOrTheme, background));
  }

  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: false,
    foreground: $foreground,
    background: $background,
    spacing: map.get(palette.$spacing-theme-defaults, normal),
  );
}

// Creates a container object for a dark theme to be given to individual component theme mixins.
@function define-dark-theme($primaryOrTheme, $accent: define-palette(palette.$blue-palette), $warn: define-palette(palette.$blue-palette)) {
  $primary: null;

  @if map.has-key($primaryOrTheme, primary) {
    $primary: map.get($primaryOrTheme, primary);
    $accent: map.get($primaryOrTheme, accent);
    $warn: map.get($primaryOrTheme, warn);
  } @else {
    $primary: $primaryOrTheme;
  }

  $pbl-updated-theme-background: (
  );

  $pbl-updated-theme-foreground: (
    ngrid-cell-focus-color: get-color-from-palette($primary)
  );

  $foreground: map.merge(map.get(palette.$dark-theme-palette, foreground), $pbl-updated-theme-foreground);
  $background: map.merge(map.get(palette.$dark-theme-palette, background), $pbl-updated-theme-background);

  @if map.has-key($primaryOrTheme, primary) {
    $foreground: map.merge($foreground, map.get($primaryOrTheme, foreground));
    $background: map.merge($background, map.get($primaryOrTheme, background));
  }

  @return (
    primary: $primary,
    accent: $accent,
    warn: $warn,
    is-dark: true,
    foreground: $foreground,
    background: $background,
    spacing: map.get(palette.$spacing-theme-defaults, normal),
  );
}
