@use 'sass:map';
@use 'xui.theme' as theme;
@use '../core/typography';

@function _get-color-from-palette($palette, $hue) {
  @if map.has-key($palette, $hue) {
    @return map.get($palette, $hue);
  }

  @error 'Hue "' + $hue + '" does not exist in palette. Available hues are: ' + map.keys($palette);
}

@function _get-contrast-color-from-palette($palette, $hue) {
  @return map.get(map.get($palette, contrast), $hue);
}

@function define-palette($base-palette, $default: 500, $lighter: 100, $darker: 700, $text: $default) {
  $result: map.merge(
    $base-palette,
    (
      default: _get-color-from-palette($base-palette, $default),
      lighter: _get-color-from-palette($base-palette, $lighter),
      darker: _get-color-from-palette($base-palette, $darker),
      text: _get-color-from-palette($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)
    )
  );

  @each $hue, $color in $base-palette {
    @if $hue != contrast {
      $result: map.merge(
        $result,
        (
          '#{$hue}-contrast': _get-contrast-color-from-palette($base-palette, $hue)
        )
      );
    }
  }

  @return $result;
}

@function define-background-palette($base-palette) {
  $result: $base-palette;

  @each $hue, $color in $base-palette {
    @if $hue != contrast {
      $result: map.merge(
        $result,
        (
          '#{$hue}-contrast': _get-contrast-color-from-palette($base-palette, $hue)
        )
      );
    }
  }

  @return $result;
}

@function define-dark-theme($theme) {
  @return _define-theme($theme, theme.$background-dark-palette);
}

@function define-light-theme($theme) {
  @return _define-theme($theme, theme.$background-light-palette);
}

@function _define-theme($theme, $default-background) {
  $color: map.get($theme, color);
  $typography: map.get($theme, typography);
  $elevation: map.get($theme, elevation);

  $primary: map.get($color, primary);

  $color: map.merge(
    $color,
    (
      primary-alt: map.get($color, primary-alt) or map.get($primary, 700),
      info: map.get($color, info) or define-palette(theme.$blue-palette),
      success: map.get($color, success) or define-palette(theme.$green-palette),
      warning: map.get($color, warning) or define-palette(theme.$orange-palette),
      error: map.get($color, error) or define-palette(theme.$red-palette),
      bg: map.get($color, bg) or define-background-palette($default-background)
    )
  );

  @return (
    color: $color,
    typography: $typography or typography.define-typography-config(),
    elevation: $elevation or theme.$default-elevation
  );
}

@mixin create-color-variables($theme) {
  $colors: map.get($theme, color);

  @each $name, $palette in $colors {
    @each $weight, $value in $palette {
      @if type-of($value) != map {
        --color-#{$name}-#{$weight}: #{$value};
        --color-#{$name}-#{$weight}-rgb: #{red($value), green($value), blue($value)};
      }
    }
  }

  --hover-opacity: 0.4;
  --active-opacity: 0.48;
  --selected-opacity: 0.6;
  --accent-opacity: 0.48;
  --text-muted-opacity: 0.5;

  --text-link-color: var(--color-info-default);
  --focus-color: var(--color-info-400);
}

@mixin create-elevation-variables($theme) {
  $elevation: map.get($theme, elevation);

  @each $name, $value in $elevation {
    --elevation-#{$name}: #{$value};
  }
}

@mixin fill($name, $palette: bg) {
  color: var(--color-#{$palette}-#{$name}-contrast);
  background-color: var(--color-#{$palette}-#{$name});
}

@mixin elevate($elevation) {
  box-shadow: var(--elevation-#{$elevation});
}

@mixin focusable() {
  &:focus-visible {
    outline: 5px solid var(--focus-color);
    z-index: 1;
  }
}

@function modifier-hover($color: accent, $palette: bg) {
  @return rgba(var(--color-#{$palette}-#{$color}-rgb), var(--hover-opacity));
}

@function modifier-active($color: accent, $palette: bg) {
  @return rgba(var(--color-#{$palette}-#{$color}-rgb), var(--active-opacity));
}

@function modifier-selected($color: accent, $palette: bg) {
  @return rgba(var(--color-#{$palette}-#{$color}-rgb), var(--selected-opacity));
}

@function modifier-accent($color: accent, $palette: bg) {
  @return rgba(var(--color-#{$palette}-#{$color}-rgb), var(--accent-opacity));
}

@function text-muted($color: accent, $palette: bg) {
  @return rgba(var(--color-#{$palette}-#{$color}-contrast-rgb), var(--text-muted-opacity));
}
