@use 'sass:map';
@use 'sass:meta';
@use '@angular/cdk';
@use '../style/layout-common';
@use '../theming/inspection';

// Private sass variables that will be used as reference throughout component stylesheets.
$default-border-width: 3px;
$default-border-style: solid;
$default-border-color: transparent;
$default-border-radius: 4px;

// Mixin that renders the focus indicator structural styles.
@mixin structural-styling() {
  .mat-focus-indicator {
    position: relative;

    &::before {
      @include layout-common.fill();
      box-sizing: border-box;
      pointer-events: none;
      display: var(--mat-focus-indicator-display, none); // Hide the indicator by default.
      border-width: var(--mat-focus-indicator-border-width, #{$default-border-width});
      border-style: var(--mat-focus-indicator-border-style, #{$default-border-style});
      border-color: var(--mat-focus-indicator-border-color, #{$default-border-color});
      border-radius: var(--mat-focus-indicator-border-radius, #{$default-border-radius});
    }

    // By default, render the focus indicator when the focus indicator host element takes focus.
    // Defining a pseudo element's content will cause it to render.
    &:focus::before {
      content: '';
    }
  }

  // Enable the indicator in high contrast mode.
  @include cdk.high-contrast {
    @include _customize-focus-indicators((display: block));
  }
}

// Generates CSS variable declarations from a map.
@mixin _output-variables($map) {
  @each $key, $value in $map {
    @if ($value) {
      --#{$key}: #{$value};
    }
  }
}

// Mixin that dedups CSS variables for the strong-focus-indicators mixin.
@mixin _customize-focus-indicators($config) {
  $border-style: map.get($config, border-style);
  $border-width: map.get($config, border-width);
  $border-radius: map.get($config, border-radius);
  $border-color: map.get($config, border-color);
  $display: map.get($config, display);
  $map: (
    'mat-focus-indicator-border-style': $border-style,
    'mat-focus-indicator-border-width': $border-width,
    'mat-focus-indicator-border-radius': $border-radius,
    'mat-focus-indicator-border-color': $border-color,
    'mat-focus-indicator-display': $display,
  );

  @if (&) {
    @include _output-variables($map);
  }
  @else {
    // We use `html` here instead of `:root`, because the
    // latter causes some issues with internal tooling.
    html {
      @include _output-variables($map);
    }
  }
}

@mixin strong-focus-indicators($config: ()) {
  // Default focus indicator config.
  $default-config: (
    border-color: black,
    display: block,
  );

  // Merge default config with user config.
  $config: map.merge($default-config, $config);

  @include _customize-focus-indicators($config);

  // Strong focus indicators currently need chip labels to have overflow visible.
  // TODO(b/446709063) revisit the structure to find a way to remove this dependency.
  @include _chip-label-overflow-visible();
}

@mixin strong-focus-indicators-color($theme-or-color) {
  @if meta.type-of($theme-or-color) == 'color' {
    @include _customize-focus-indicators((border-color: $theme-or-color));
  }
  @else {
    $border-color: inspection.get-theme-color($theme-or-color, primary);
    @include _customize-focus-indicators((border-color: $border-color));
  }
}

@mixin strong-focus-indicators-theme($theme-or-color) {
  @if meta.type-of($theme-or-color) == 'color' {
    @include _customize-focus-indicators((border-color: $theme-or-color));
  }
  @else {
    @if inspection.theme-has($theme-or-color, color) {
      @include strong-focus-indicators-color($theme-or-color);
    }
  }
}

@mixin _chip-label-overflow-visible {
  .mat-mdc-standard-chip {
    // MDC sets `overflow: hidden` on these elements in order to truncate the text. This conflicts
    // with how we structure and style the strong focus indicators so we need to override it.
    .mdc-evolution-chip__cell--primary,
    .mdc-evolution-chip__action--primary,
    .mat-mdc-chip-action-label {
      overflow: visible;
    }
  }
}
