@use 'sass:list';
@use 'sass:map';
@use 'sass:math';
@use 'sass:meta';
@use 'config/colors';
@use 'config/fonts';
@use 'functions/color';
@use 'mixins/flex';
@use 'mixins/font';
@use 'mixins/position';
@use 'mixins/spacing';
@use 'mixins/transition';

$types: (
  // these are the default colors, not for a specific type (typically used for the label color)
  // (in case a specific type's styling hasn't been applied for whatever reason)
  default-color: (
    light: colors.$black,
    dark: colors.$white,
  ),

  colors: (
    unknown: #424242, // aka. the ??? type
    normal: #90905D,
    fighting: #81201B,
    flying: #8563EA,
    poison: #7C317C,
    ground: #D1A42B,
    rock: #917E2C,
    bug: #808D18,
    ghost: #584578,
    steel: #9999BC,
    fire: #DD6510,
    water: #3A6EEB,
    grass: #549B31,
    electric: color.shade(#FDD835, 5%),
    psychic: color.shade(#F62765, 10%),
    ice: color.shade(#73CACA, 10%),
    dragon: #4D09F4,
    dark: #41332A,
    fairy: #E76D88,

    // note: this one's special uwu
    // (colors extracted from in-game Stellar type icon; will be used to populate gradient stops)
    // (also... should've just made PokeType into an SVG in hindsight lmao)
    stellar: (
      #E4B637,
      #FD7A33,
      (#FA3E3A, topRight),
      #E53B7D,
      (#B762B1, middleRight),
      #713CBE,
      (#5E3B9D, bottomRight),
      #374477,
      #567D97,
      #3599D5,
      #21A5E0,
      (#246FD4, bottomLeft),
      #294FBC,
      (#2C97C2, middleLeft),
      (#16B345, topLeft),
      #C7D86E,
      #99A977,
      // #B9864E,
      #E0C08C,
    ),
  ),

  adjustment: (
    light: 8%, // shade (both highlight/non-highlight)
    dark: 32%, // tint (for non-highlight only)

    stellar: (
      linear-angle: -30deg, // slanted right

      // +% for tint, -% for shade
      // (+/-% feature for stellar only)
      color: (
        light: -4%,
        dark: 16%,
      ),
      background-color: (
        light: 4%,
        dark: -8%,
      ),
    ),
  ),
);

$container: (
  width: (
    default: 36px,
    sm: 28px,
    xs: 22px,
  ),

  height: 13px,
);

$label: (
  font-size: 8px,
  border-radius: 5px,

  text-shadow: (
    default: 1px 1px 0 color.alpha(colors.$black, 0.1),
    highlight: 1px 1px 0 color.alpha(colors.$black, 0.3),
  ),

  label-opacity: (
    default: (
      light: 0.75,
      dark: 0.85,
    ),

    highlight: (
      light: 1,
      dark: 1,
    ),
  ),

  // for the unknown/??? type
  // (these colors were obtained with the commented out default background-opacity's below)
  default-background-color: (
    light: #DCDFE1,
    dark: #2D2B2A,
  ),

  background-opacity: (
    // for the unknown/??? type
    default: (
      light: 0.88,
      dark: 0.88,
    ),

    highlight: (
      light: 1,
      dark: 1,
    ),
  ),
);

$tera-edge: (
  size: (
    edge: 6px,
    middle: 7px,
  ),

  rotation: (
    edge: 18deg, // must be positive (0deg is ok)
    middle: 45deg,
  ),

  offset: (
    edge: 1px, // must be positive (0 is ok)
    middle: (
      x: -2px,
      y: 3px,
    ),
  ),

  background-opacity: (
    default: (
      light: 0.9,
      dark: 0.9,
    ),

    highlight: (
      light: 1,
      dark: 1,
    ),
  ),
);

.container {
  position: relative;
  display: inline-block;
  width: map.get($container, width, default);
  height: map.get($container, height);
  @include transition.apply(width);

  &.sm {
    width: map.get($container, width, sm);
  }

  &.xs {
    width: map.get($container, width, xs);
  }
}

.label {
  @include position.absolute-fill;
  @include flex.row-center($inline: true);
  @include font.apply(fonts.$mono);
  font-size: map.get($label, font-size);
  text-align: center;
  text-transform: uppercase;
  text-shadow: map.get($label, text-shadow, default);
  border-radius: map.get($label, border-radius);
  @include transition.apply(color, text-shadow, background-color);
  user-select: none;
  z-index: 1;

  .light & {
    color: color.alpha(map.get($types, default-color, light), map.get($label, label-opacity, default, light));
    background-color: color.alpha(map.get($label, default-background-color, light), map.get($label, background-opacity, default, light));
  }

  .dark & {
    color: color.alpha(map.get($types, default-color, dark), map.get($label, label-opacity, default, dark));
    background-color: color.alpha(map.get($label, default-background-color, dark), map.get($label, background-opacity, default, dark));
  }

  // see `.highlight.light &` and `.highlight.dark &` in `.teraEdge` below
  // for why we can't do `.highlight & { .light & { ... } ... }`
  .highlight & {
    text-shadow: map.get($label, text-shadow, highlight);
  }

  .highlight.light & {
    color: color.alpha(colors.$white, map.get($label, label-opacity, highlight, light));
    background-color: color.alpha(map.get($types, colors, unknown), map.get($label, background-opacity, default, light));
  }

  .highlight.dark & {
    color: color.alpha(colors.$white, map.get($label, label-opacity, highlight, dark));
    background-color: color.alpha(map.get($types, colors, unknown), map.get($label, background-opacity, default, dark));
  }
}

.teraEdge {
  display: inline-block;
  width: map.get($tera-edge, size, edge);
  height: map.get($tera-edge, size, edge);
  @include transition.apply(background-color);
  user-select: none;
  pointer-events: none;

  .light & {
    background-color: color.alpha(map.get($label, default-background-color, light), map.get($tera-edge, background-opacity, default, light));
  }

  .dark & {
    background-color: color.alpha(map.get($label, default-background-color, dark), map.get($tera-edge, background-opacity, default, dark));
  }

  // must be done this way btw (due to how I've nested the DOM elements lol)
  // (one does not simply `.highlight & { .light & { ... } ... }` -> `.highlight .light .teraEdge`; should be `.highlight.light .teraEdge`)
  .highlight.light & {
    background-color: color.alpha(map.get($types, colors, unknown), map.get($label, background-opacity, default, light));
  }

  .highlight.dark & {
    background-color: color.alpha(map.get($types, colors, unknown), map.get($label, background-opacity, default, dark));
  }

  &.topLeft {
    @include position.absolute($top: map.get($tera-edge, offset, edge) * -1, $left: map.get($tera-edge, offset, edge));
    transform: rotateZ(map.get($tera-edge, rotation, edge));
  }

  &.topRight {
    @include position.absolute($top: map.get($tera-edge, offset, edge) * -1, $right: map.get($tera-edge, offset, edge));
    transform: rotateZ(map.get($tera-edge, rotation, edge) * -1);
  }

  &.middleRight {
    @include position.absolute($top: map.get($tera-edge, offset, middle, y), $right: map.get($tera-edge, offset, middle, x));
    width: map.get($tera-edge, size, middle);
    height: map.get($tera-edge, size, middle);
    transform: rotateZ(map.get($tera-edge, rotation, middle));
  }

  &.bottomRight {
    @include position.absolute($right: map.get($tera-edge, offset, edge), $bottom: map.get($tera-edge, offset, edge) * -1);
    transform: rotateZ(map.get($tera-edge, rotation, edge));
  }

  &.bottomLeft {
    @include position.absolute($bottom: map.get($tera-edge, offset, edge) * -1, $left: map.get($tera-edge, offset, edge));
    transform: rotateZ(map.get($tera-edge, rotation, edge) * -1);
  }

  &.middleLeft {
    @include position.absolute($top: map.get($tera-edge, offset, middle, y), $left: map.get($tera-edge, offset, middle, x));
    width: map.get($tera-edge, size, middle);
    height: map.get($tera-edge, size, middle);
    transform: rotateZ(map.get($tera-edge, rotation, middle));
  }
}

@each $type, $color in map.get($types, colors) {
  @if $type != unknown {
    $light-shade: map.get($types, adjustment, light);
    $dark-tint: map.get($types, adjustment, dark);

    .type-#{$type} {
      @if $type == stellar {
        $light-color-adj: map.get($types, adjustment, stellar, color, light);
        $light-background-color-adj: map.get($types, adjustment, stellar, background-color, light);
        $dark-color-adj: map.get($types, adjustment, stellar, color, dark);
        $dark-background-color-adj: map.get($types, adjustment, stellar, background-color, dark);

        // note: unless manipulated by any sass:map functions, meta.type-of() will return 'list' for `()`
        // (not that it really matters here, but knowledge is power)
        $light-colors: (); // list
        $light-background-colors: (); // list
        $light-tera-edges: (); // map
        $dark-colors: (); // list
        $dark-background-colors: (); // list
        $dark-tera-edges: (); // map

        @each $stop-tuple in $color {
          $stop-color: if(meta.type-of($stop-tuple) == list, list.nth($stop-tuple, 1), $stop-tuple);
          $tera-edge-name: if(meta.type-of($stop-tuple) == list, list.nth($stop-tuple, 2), null);

          $light-stop-color: if($light-color-adj > 0, color.tint($stop-color, $light-color-adj), color.shade($stop-color, math.abs($light-color-adj)));
          $light-stop-background-color: if($light-color-adj > 0, color.tint($stop-color, $light-background-color-adj), color.shade($stop-color, math.abs($light-background-color-adj)));
          $dark-stop-color: if($dark-color-adj > 0, color.tint($stop-color, $dark-color-adj), color.shade($stop-color, math.abs($dark-color-adj)));
          $dark-stop-background-color: if($dark-color-adj > 0, color.tint($stop-color, $dark-background-color-adj), color.shade($stop-color, math.abs($dark-background-color-adj)));

          $light-colors: list.append($light-colors, $light-stop-color, $separator: comma);
          $light-background-colors: list.append($light-background-colors, $light-stop-background-color, $separator: comma);
          $dark-colors: list.append($dark-colors, $dark-stop-color, $separator: comma);
          $dark-background-colors: list.append($dark-background-colors, $dark-stop-background-color, $separator: comma);

          @if $tera-edge-name {
            $light-tera-edges: map.set($light-tera-edges, $tera-edge-name, $light-stop-background-color);
            $dark-tera-edges: map.set($dark-tera-edges, $tera-edge-name, $dark-stop-background-color);
          }
        }

        &:not(.highlight) {
          .label span {
            color: colors.$transparent;
            background-clip: text;
          }

          $linear-angle: map.get($types, adjustment, stellar, linear-angle);

          &.light .label span {
            background-image: linear-gradient($linear-angle, $light-colors);
          }

          &.dark .label span {
            background-image: linear-gradient($linear-angle, $dark-colors);
          }
        }

        &.highlight {
          .label > span {
            background-image: none;
          }

          &.light {
            .label {
              background-image: conic-gradient($light-background-colors);
            }

            @each $edge, $edge-color in $light-tera-edges {
              .teraEdge.#{$edge} {
                background-color: $edge-color;
              }
            }
          }

          &.dark {
            .label {
              background-image: conic-gradient($dark-background-colors);
            }

            @each $edge, $edge-color in $dark-tera-edges {
              .teraEdge.#{$edge} {
                background-color: $edge-color;
              }
            }
          }
        }
      } @else {
        $light-default-color: color.shade($color, $light-shade);
        $dark-default-color: color.tint($color, $dark-tint);

        &:not(.highlight) {
          &.light .label {
            color: color.alpha($light-default-color, map.get($label, label-opacity, default, light));
          }

          &.dark .label {
            color: color.alpha($dark-default-color, map.get($label, label-opacity, default, dark));
          }
        }

        $light-highlight-color: $light-default-color;
        $dark-highlight-color: $color;

        &.highlight {
          &.light {
            .label {
              background-color: color.alpha($light-highlight-color, map.get($label, background-opacity, highlight, light));
            }

            .teraEdge {
              background-color: color.alpha($light-highlight-color, map.get($tera-edge, background-opacity, highlight, light));
            }
          }

          &.dark {
            .label {
              background-color: color.alpha($dark-highlight-color, map.get($label, background-opacity, highlight, dark));
            }

            .teraEdge {
              background-color: color.alpha($dark-highlight-color, map.get($tera-edge, background-opacity, highlight, dark));
            }
          }
        } // end &:not(.highlight), &.highlight
      } // end @else
    } // end .type-#{$type}
  } // end @if
}
