<template>
  <component
    :is="tag"
    :aria-label="$slots.default ? $slots.default[0].text : text"
    :disabled="disabled"
    :type="nativeType"
    :href="href"
    :target="target"
    :class="[
      `is-${size}`,
      // `is-${type}`, uncomment when we remove the deprecated types
      {
        'has-icon': icon,
        'prepend-icon': icon && prepend,
        'is-block': isBlock,
        'is-disabled': disabled,
        'no-branding': noBranding,
        // remove type checks when we remove the deprecated types
        'is-success': ['affirm', 'success'].includes(type),
        'is-danger': ['decline', 'danger'].includes(type),
        'is-primary': type === 'primary',
        'is-secondary': type === 'secondary',
      },
    ]"
    class="app-button"
    @click="$emit('click', $event);"
  >
    <span
      v-if="!isIcon && ($slots.default || text)"
      class="button-text"
    >{{ text || $slots.default[0].text }}</span>
    <template v-if="icon || isIcon">
      <AppIcon
        :icon="isLoading ? 'fa-solid fa-spinner fa-spin' : icon"
        :size="iconSize"
        class="app-button-icon"
        data-test="app button icon"
      />
      <span
        v-if="isIcon"
        class="sr-only"
        v-text="text"
      />
    </template>
  </component>
</template>
<script>
  /**
   * A standalone customizable themeable global button.
   *
   * @vuedoc
   * @exports AppAlert
   * @category Components
   */
  export default {
    name: 'AppButton',
    props: {
      /**
       * Prop used to pass the {@href https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-href} attribute used for an anchor tag.
       */
      href: {
        type: String,
        default: null,
      },
      /**
       * Prop used to select the name of the icon to be used in the template. See the {@docs https://fontawesome.com/docs/web/use-with/vue/add-icons} for more information.
       */
      icon: {
        type: String,
        default: '',
      },
      /**
       * Prop used to set the width to 100% and center the text.
       */
      isBlock: {
        type: Boolean,
        default: false,
      },
      /**
       * Prop used to disable the element in the template.
       */
      isDisabled: {
        type: Boolean,
        default: false,
      },
      /**
       * Prop used to disable the element in the template and render a spinning icon if an icon is present.
       */
      isLoading: {
        type: Boolean,
        default: false,
      },
      /**
       * Prop used to pass the {@type https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-type} attribute used for an anchor tag.
       */
      nativeType: {
        type: String,
        default: 'button',
      },
      /**
       * Prop used to render the "primary" and "secondary" type buttons with ThreeFlow blue instead of branding colors.
       */
      noBranding: {
        type: Boolean,
        default: false,
      },
      /**
       * Prop used to update the css to reverse the css flex-direction.
       */
      prepend: {
        type: Boolean,
        default: false,
      },
      /**
       * Prop used the render an icon, button size, or text size version of the button.
       */
      size: {
        type: String,
        default: 'medium',
        validator: (v) => [
          'icon',
          'icon-small',
          'small',
          'medium',
          'large',
          'text',
          'text-small',
        ].includes(v),
      },
      /**
       * Prop used to render the element either as a `<button />` or `<a />` tag.
       */
      tag: {
        type: String,
        default: 'button',
        validator: (v) => ['a', 'button'].includes(v),
      },
      /**
       * Prop used to pass the {@target https://developer.mozilla.org/en-US/docs/Web/HTML/Element/a#attr-target} attribute used for an anchor tag.
       */
      target: {
        type: String,
        default: null,
      },
      /**
       * Prop used to override the default slot content.
       */
      text: {
        type: String,
        default: null,
      },
      /**
       * Prop used to render the green, red, or branded (or ThreeFlow blue) style.
       */
      type: {
        type: String,
        default: 'primary',
        validator: (v) => [
          'affirm', // deprecated: use 'success'
          'success',
          'decline', // deprecated: use 'danger'
          'danger',
          'primary',
          'secondary',
        ].includes(v),
      },
    },
    computed: {
      /**
       * Evaluate the disabled and isLoading props to determine if the button should be disabled.
       *
       * @returns {boolean}
       */
      disabled() {
        return this.isDisabled || this.isLoading;
      },
      /**
       * Evaluate the icon and size props to determine the icon size.
       *
       * @returns {string|null}
       */
      iconSize() {
        if (!this.icon) {
          return null;
        }

        return ['small', 'text-small', 'icon-small'].includes(this.size)
          ? 'sm'
          : 'lg';
      },
      /**
       * Evaluate the size prop to determine if the button should render as an icon.
       *
       * @returns {boolean}
       */
      isIcon() {
        return ['icon', 'icon-small'].includes(this.size);
      },
    },
  };
</script>

<style lang="scss" scoped>
  .app-button {
    white-space: nowrap;
    box-shadow: none;
    box-sizing: border-box;
    margin: 0;
    padding: 7px 14px;
    border: {
      radius: 0;
      style: solid;
    }
    display: inline-flex;
    align-items: center;
    cursor: pointer;

    + .app-button {
      margin-left: var(--tf-btn-margin-medium);
    }

    &.is-disabled {
      cursor: not-allowed;
    }
  }

  .is-block {
    width: 100%;
    justify-content: center;
  }

  .button-text {
    font: {
      size: 16px;
      weight: 600;
    }
  }

  // size
  .is-small {
    padding: 1px 13px;

    .button-text {
      font-size: var(--tf-body-font-size);
    }
  }

  .is-medium,
  .is-small {
    border-radius: 3px;
  }

  .is-medium {
    padding: 3px 18px;
  }

  .is-large {
    padding: 8px 18px;
    border-radius: 25px;

    .button-text {
      font-size: var(--tf-body-large-font-size);
    }
  }

  .is-icon,
  .is-icon-small,
  .is-text,
  .is-text-small {
    &.is-primary,
    &.is-secondary {
      color: var(--primary, var(--tf-primary));

      &.no-branding:not(.is-disabled) {
        color: var(--tf-primary);
      }
    }
  }

  .is-text,
  .is-text-small {
    padding: 0;
    background: transparent !important; // stylelint-disable-line
    border: none !important; // stylelint-disable-line
    vertical-align: inherit;

    &.is-success {
      color: var(--tf-success-font-color);
    }

    &.is-danger {
      color: var(--tf-danger-font-color);
    }

    &.is-disabled {
      color: var(--tf-disabled-font-color);
    }

    .app-alert & {
      color: inherit !important; // stylelint-disable-line
      text-decoration: underline;
    }
  }

  .is-text {
    .button-text {
      font-size: var(--tf-body-font-size);
    }
  }

  .is-text-small {
    .button-text {
      font-size: var(--tf-small-font-size);
    }
  }

  // Types
  .is-primary,
  .is-secondary {
    border-color: var(--primary, var(--tf-primary));

    &.no-branding:not(.is-disabled) {
      border-color: var(--tf-primary);
    }
  }

  .is-success,
  .is-danger,
  .is-primary,
  .is-secondary {
    color: var(--tf-white);
  }

  .is-primary {
    background-color: var(--primary, var(--tf-primary));

    &.no-branding {
      background-color: var(--tf-primary);
    }
  }

  .is-secondary {
    background-color: transparent;
    color: var(--primary, var(--tf-primary));

    &.no-branding {
      color: var(--tf-primary);
      border-color: var(--tf-primary);
    }

    &.is-disabled {
      border-color: var(--tf-disabled);
      color: var(--tf-disabled);
    }
  }

  .is-success {
    background-color: var(--tf-success);
    border-color: var(--tf-success-border-color);
  }

  .is-danger {
    background-color: var(--tf-danger);
    border-color: var(--tf-danger-border-color);
  }

  .is-success,
  .is-danger,
  .is-primary {
    &.is-disabled {
      border-color: var(--tf-disabled-light);
      background-color: var(--tf-disabled-light);
      color: var(--tf-disabled);
    }
  }

  // Icons
  .app-button-icon {
    line-height: inherit;
  }

  .is-icon,
  .is-icon-small {
    background: none !important; // stylelint-disable-line
    border: none;

    &.is-success {
      color: var(--tf-success-font-color);
    }

    &.is-danger {
      color: var(--tf-danger-font-color);
    }

    &.is-disabled {
      color: var(--tf-disabled-font-color) !important; // stylelint-disable-line
    }
  }

  .is-icon {
    padding: 7px;
  }

  .is-icon-small {
    padding: 9px;
  }

  .prepend-icon {
    flex-direction: row-reverse;
  }

  .has-icon {
    .button-text {
      padding: {
        left: 0;
        right: 6px;
      }
    }

    &.prepend-icon {
      .button-text {
        padding: {
          left: 6px;
          right: 0;
        }
      }
    }
  }
</style>
