/**
 * Copyright IBM Corp. 2021, 2025
 * SPDX-License-Identifier: MPL-2.0
 */

//
// CODE-BLOCK
//

@use "../../mixins/focus-ring" as *;

// Note: "theme" contains just color variables and syntax highlighting styles
@use "theme";

// DIMENSIONS
$hds-code-block-line-numbers-width: 49px; // 3em ≈ 49px
$hds-code-block-code-padding: 16px;
$hds-code-block-code-footer-height: 48px;

// CODE-BLOCK PARENT/WRAPPER

.hds-code-block {
  position: relative;
  color: var(--hds-code-block-color-foreground-primary);
  background-color: var(--hds-code-block-color-surface-primary);
  border: 1px solid var(--hds-code-block-color-border-strong);

  pre,
  code {
    line-height: 1.4286;
    white-space: pre;
    text-align: left;
    text-shadow: none;
    word-wrap: normal;
    word-break: normal;
    word-spacing: normal;
    tab-size: 4;
    hyphens: none;

    @media print {
      text-shadow: none;
    }
  }
}

// VARIANTS

// isStandalone
.hds-code-block--is-standalone {
  overflow: hidden; // hide corners of scrollbar that poke out
  border-radius: var(--token-border-radius-medium);
}

// hasLineWrapping
.hds-code-block--has-line-wrapping {
  .hds-code-block__code,
  .hds-code-block__code code {
    display: block;
    white-space: pre-wrap;
    overflow-wrap: break-word;
  }
}

// CHILD COMPONENTS / ELEMENTS

// Header (contains title & description)

.hds-code-block__title {
  color: var(--hds-code-block-color-foreground-primary);
}

.hds-code-block__description {
  color: var(--hds-code-block-color-foreground-faint);
}

.hds-code-block__header {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 8px $hds-code-block-code-padding;
  background-color: var(--hds-code-block-color-surface-faint);
  border-bottom: 1px solid var(--hds-code-block-color-border-primary);
  border-top-left-radius: inherit;
  border-top-right-radius: inherit;

  &:empty {
    display: none;
  }

  // we add very basic styling for elements that may be yielded in the "title"/"description" elements

  strong {
    font-weight: var(--token-typography-font-weight-semibold);
  }

  code,
  pre {
    display: inline;
    font-size: 0.9em; // as discussed with designers, we reduce the size for optical/visual balance
    font-family: var(--token-typography-code-100-font-family);
    line-height: 1em;
  }

  // Default styling for bare HTML links not using HDS::Link components
  a:not([class*="hds-"]) {
    color: var(--hds-code-block-color-foreground-action);

    &:focus,
    &:focus-visible {
      text-decoration: none;
      outline: 2px solid var(--token-color-focus-action-internal);
      outline-offset: 1px;
    }

    &:hover {
      color: var(--token-color-foreground-action-hover);
    }

    &:active {
      color: var(--token-color-foreground-action-active);
    }
  }
}

.hds-code-block__body {
  position: relative;
  border-radius: inherit;
}

// Code
.hds-code-block__code {
  @include hds-focus-ring-basic();
  position: relative;
  display: grid;
  margin: 0;
  padding: $hds-code-block-code-padding 0 $hds-code-block-code-padding $hds-code-block-code-padding;
  overflow: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--token-color-palette-neutral-400) var(--token-color-palette-neutral-500);
  border-radius: inherit;

  ::selection {
    color: var(--hds-code-block-color-foreground-selection);
    background-color: var(--hds-code-block-color-surface-selection);
  }

  code {
    position: relative;
    display: inline-block;
    padding-right: $hds-code-block-code-padding;
    font-size: 0.8125rem;
    font-family: var(--token-typography-code-200-font-family);
  }
}

// General dark button styles
.hds-code-block__height-toggle-button,
.hds-code-block__copy-button {
  // Overriding default colors
  color: var(--hds-code-block-color-foreground-primary);
  background-color: var(--hds-code-block-color-surface-faint);
  border: 1px solid var(--hds-code-block-color-border-strong);

  &:hover,
  &.mock-hover {
    color: var(--hds-code-block-color-foreground-primary);
    background-color: var(--hds-code-block-color-surface-primary);
    border-color: var(--hds-code-block-color-border-strong);
  }

  &:active,
  &.mock-active {
    color: var(--hds-code-block-color-foreground-primary);
    background-color: var(--hds-code-block-color-surface-interactive-active);
  }

  &:focus,
  &.mock-focus,
  &:focus-visible {
    color: var(--hds-code-block-color-foreground-primary);
    background-color: var(--hds-code-block-color-surface-faint);
    border-color: var(--hds-code-block-color-focus-action-internal);

    &::before {
      border-color: var(--hds-code-block-color-focus-action-external);
    }
  }

  .hds-icon {
    color: var(--hds-code-block-color-foreground-primary);
  }
}

// CopyButton
.hds-code-block__copy-button {
  position: absolute;
  top: 11px; // 12px -1px accounting for border
  right: 12px;

  &.hds-copy-button--status-success {
    .hds-icon {
      color: var(--hds-code-block-color-foreground-success);
    }
  }

  &.hds-copy-button--status-error {
    .hds-icon {
      color: var(--hds-code-block-color-foreground-critical);
    }
  }
}

// Prism.js plugins
.hds-code-block {
  // LineNumbers plugin styles ---------------
  // Note: Prism.js is using the specific class name "line-numbers" to determine implementation of line numbers in the UI
  &.line-numbers {
    counter-reset: linenumber;

    .hds-code-block__code {
      position: relative;
      // reserve space for line numbers
      padding-left: calc(#{$hds-code-block-line-numbers-width} + #{$hds-code-block-code-padding});

      // When line numbers are enabled, line highlighing is calculated based on the pre element instead of the code element
      // To ensure the offset is correct, we need to set the position of the code element to static
      // Source: https://github.com/PrismJS/prism/blob/v2/src/plugins/line-highlight/prism-line-highlight.ts#L92
      code {
        position: static;
      }
    }

    .hds-code-block__overlay-footer {
      // match horizontal padding of the code block
      margin-left: $hds-code-block-line-numbers-width;
    }

    .line-numbers-rows {
      position: absolute;
      top: 0;
      left: 0;
      min-width: $hds-code-block-line-numbers-width;
      min-height: 100%;
      padding: $hds-code-block-code-padding 0;
      border-right: 1px solid var(--hds-code-block-color-border-primary);
      user-select: none;
      pointer-events: none;

      > span {
        display: block;
        counter-increment: linenumber;

        &::before {
          display: block;
          padding-right: $hds-code-block-code-padding;
          text-align: right;
          content: counter(linenumber);
        }
      }
    }

    .line-highlight {
      left: 0;
    }
  }

  // Highlighted Lines
  .line-highlight {
    position: absolute;
    right: 0;
    left: -$hds-code-block-code-padding;
    background-color: var(--hds-code-block-color-line-highlight);
    border: solid var(--hds-code-block-color-line-highlight-border);
    border-width: 1px 0 1px 4px;
    mix-blend-mode: screen;
    pointer-events: none;
  }

  @media print {
    .line-highlight {
      /*
       * This will prevent browsers from replacing the background color with white.
       * It's necessary because the element is layered on top of the displayed code.
       */
      -webkit-print-color-adjust: exact;
      color-adjust: exact;
    }
  }

  // commmon tokens
  .token.bold {
    font-weight: bold;
  }

  .token.italic {
    font-style: italic;
  }
}

// Footer
.hds-code-block__overlay-footer {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 10px $hds-code-block-code-padding 10px $hds-code-block-code-padding;
  pointer-events: none; // fix issue with scrolling when hovering over the footer

  // re-enable pointer events for the button (or any content inside the footer)
  > * {
    pointer-events: auto;
  }
}

// Usage of sticky positioning, negative margins, and z-index are required to prevent styling issues
// when horizontal scrolling is present.
// https://hashicorp.slack.com/archives/C025N5V4PFZ/p1746659338984369
.hds-code-block--has-overlay-footer {
  .hds-code-block__code::after {
    // gradient element
    position: sticky; // prevent gradient from scrolling together with content
    bottom: -$hds-code-block-code-padding;
    left: 0;
    display: block;
    height: $hds-code-block-code-footer-height;
    margin: 0 0 -#{$hds-code-block-code-padding} -1000px; // cover line highlights when line numbers are enabled
    background: linear-gradient(360deg, #0d0e12 37.07%, rgba(13, 14, 18, 25%) 100%);
    content: "";
    pointer-events: none;
  }

  .line-numbers .line-numbers-rows {
    padding-bottom: $hds-code-block-code-footer-height;
  }

  // place line numbers on top of footer gradient
  .line-numbers-rows {
    z-index: 1;
    isolation: isolate;
  }
}

.hds-code-block--is-expanded {
  .hds-code-block__code {
    // account for the footer at the bottom of the code block
    padding-bottom: $hds-code-block-code-footer-height;

    &::after {
      content: none;
    }
  }

  .hds-code-block__overlay-footer {
    background: none;
  }
}
