<!-- eslint-disable vue/multi-word-component-names -->
<template>
  <button
    v-bind="$attrs"
    :disabled="buttonDisabled"
    :class="[
      'unnnic-button',
      `unnnic-button--size-${size}`,
      `unnnic-button--${buttonType}`,
      iconCenter ? `unnnic-button--icon-on-center` : null,
      float ? `unnnic-button--float` : null,
      pressed ? `unnnic-button--pressed` : null,
    ]"
  >
    <UnnnicIconLoading
      v-if="loading"
      :scheme="iconScheme"
      :size="iconSize"
      :style="{ position: 'absolute' }"
      data-testid="icon-loading"
    />

    <UnnnicIcon
      v-if="iconLeft"
      :icon="iconLeft"
      :scheme="iconScheme"
      :size="iconSize"
      :filled="iconsFilled"
      :class="{ 'unnnic-button__icon-left': hasText }"
      :style="{ visibility: loading ? 'hidden' : 'visible' }"
      clickable
      data-testid="icon-left"
    />

    <UnnnicIcon
      v-if="iconCenter"
      :icon="iconCenter"
      :scheme="iconScheme"
      :style="{ visibility: loading ? 'hidden' : 'visible' }"
      :size="iconSize"
      :filled="iconsFilled"
      clickable
      data-testid="icon-center"
    />

    <span
      v-if="!float"
      class="unnnic-button__label"
      :style="{ visibility: loading ? 'hidden' : 'visible' }"
      data-testid="button-label"
    >
      <slot /> {{ text }}
    </span>

    <UnnnicIcon
      v-if="iconRight"
      :icon="iconRight"
      :scheme="iconScheme"
      :size="iconSize"
      :filled="iconsFilled"
      :class="{ 'unnnic-button__icon-right': hasText }"
      :style="{ visibility: loading ? 'hidden' : 'visible' }"
      clickable
      data-testid="icon-right"
    />
  </button>
</template>

<script setup lang="ts">
import { computed, watch, useSlots } from 'vue';
import UnnnicIcon from '../Icon.vue';
import UnnnicIconLoading from '../IconLoading/IconLoading.vue';
import type { ButtonProps, ButtonSize, ButtonType } from './types';
import type { SchemeColor } from '@/types/scheme-colors';

defineOptions({
  name: 'UnnnicButton',
});

export type { ButtonProps, ButtonSize, ButtonType };

const props = withDefaults(defineProps<ButtonProps>(), {
  size: 'large',
  text: '',
  type: 'primary',
  float: false,
  iconLeft: '',
  iconRight: '',
  iconCenter: '',
  iconsFilled: false,
  disabled: false,
  loading: false,
  pressed: false,
});

const slots = useSlots();

const buttonDisabled = computed(() => {
  return props.disabled || props.loading;
});

const iconSize = computed(() => {
  if (props.size === 'extra-large') return 'lg';
  return 'ant';
});

const hasText = computed(() => {
  if (slots.default) return true;
  return props.text && props.text.length > 0;
});

const iconScheme = computed((): SchemeColor => {
  if (buttonDisabled.value) {
    return 'fg-muted';
  }

  const typeToSchemeMap: Record<ButtonType, SchemeColor> = {
    primary: 'fg-on-primary',
    secondary: 'fg-emphasized',
    tertiary: 'fg-emphasized',
    warning: 'fg-on-primary',
    attention: 'fg-on-primary',
  };

  return typeToSchemeMap[buttonType.value] || 'fg-on-primary';
});

const isSizePropValid = computed(() => {
  return (
    props.size === 'large' ||
    (!props.float && props.size === 'small') ||
    (props.float && props.size === 'extra-large')
  );
});

const buttonType = computed(() => {
  return (
    {
      alternative: 'tertiary',
    }[props.type] || props.type
  );
});

const isTypePropValid = computed(() => {
  const validTypes: ButtonType[] = [
    'primary',
    'secondary',
    'tertiary',
    'warning',
    'attention',
  ];
  return validTypes.includes(buttonType.value);
});

const validateProps = () => {
  if (!isSizePropValid.value || !isTypePropValid.value) {
    let errorMessage = 'TypeError:';

    if (!isSizePropValid.value) {
      errorMessage += ' Invalid size prop.';
      errorMessage += ` Please provide 'large', 'small' (only if float prop is false), or 'extra-large' (only if float prop is true).`;
    }

    if (!isTypePropValid.value) {
      errorMessage += ' Invalid type prop.';
      errorMessage +=
        ' Please provide one of the following types: primary, secondary, tertiary, warning, attention. Alternative is discontinued and it was forced renamed to tertiary.';
    }

    throw new Error(errorMessage);
  }
};

watch(
  () => props,
  () => {
    validateProps();
  },
  { deep: true, immediate: true },
);
</script>

<style lang="scss" scoped>
.rotation {
  animation: rotation 1300ms linear infinite;
}

@keyframes rotation {
  0% {
  }

  100% {
    transform: rotate(360deg);
  }
}
</style>

<style lang="scss" scoped>
@use '@/assets/scss/unnnic' as *;

.unnnic-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: $unnnic-radius-2;
  border: 0;
  outline: none;
  overflow: hidden;
  white-space: nowrap;
  font: $unnnic-font-action;
  cursor: pointer;
  position: relative;

  transition-property: color, background-color, border-color;
  transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
  transition-duration: 0.15s;

  &__icon {
    &-left {
      margin-right: $unnnic-inline-nano;
    }

    &-right {
      margin-left: $unnnic-inline-nano;
    }
  }

  &--primary,
  &--warning,
  &--attention {
    color: $unnnic-color-fg-on-primary;
  }

  &--secondary,
  &--tertiary {
    color: $unnnic-color-fg-emphasized;
  }

  &--primary {
    background-color: $unnnic-color-bg-accent-strong;

    &:hover:enabled {
      background-color: $unnnic-color-teal-11;
    }

    &:active:enabled,
    &.unnnic-button--pressed {
      background-color: $unnnic-color-teal-12;
    }
  }

  &--secondary {
    background-color: $unnnic-color-bg-base;
    box-shadow: inset 0 0 0 1px $unnnic-color-border-base;

    &:hover:enabled {
      background-color: $unnnic-color-bg-base-soft;
    }

    &:active:enabled,
    &.unnnic-button--pressed {
      background-color: $unnnic-color-bg-muted;
    }

    &:disabled {
      box-shadow: none;
    }
  }

  &--tertiary {
    background-color: transparent;

    &:hover:enabled {
      background-color: $unnnic-color-bg-base-soft;
    }

    &:active:enabled,
    &.unnnic-button--pressed {
      background-color: $unnnic-color-bg-muted;
    }
  }

  &--warning {
    background-color: $unnnic-color-bg-red-strong;

    &:hover:enabled {
      background-color: $unnnic-color-red-11;
    }

    &:active:enabled,
    &.unnnic-button--pressed {
      background-color: $unnnic-color-red-12;
    }
  }

  &--attention {
    background-color: $unnnic-color-bg-yellow-strong;

    &:hover:enabled {
      background-color: $unnnic-color-yellow-11;
    }

    &:active:enabled,
    &.unnnic-button--pressed {
      background-color: $unnnic-color-yellow-12;
    }
  }

  &--primary:disabled,
  &--secondary:disabled,
  &--tertiary:disabled,
  &--warning:disabled,
  &--attention:disabled {
    background-color: $unnnic-color-bg-muted;
    color: $unnnic-color-fg-muted;
    cursor: not-allowed;

    :deep(.unnnic--clickable) {
      cursor: not-allowed;
    }
  }

  &--float {
    position: absolute;
    bottom: 0;
    right: 0;

    border-radius: $unnnic-border-radius-pill;
    box-shadow: $unnnic-shadow-1;
  }

  &--size-large {
    padding: $unnnic-space-3 $unnnic-space-4;
  }

  &--size-small {
    padding: $unnnic-space-2 $unnnic-space-4;
  }
}
</style>

<style lang="scss" scoped>
@use '@/assets/scss/unnnic' as *;

.unnnic-button--icon-on-center {
  min-width: auto;

  &.unnnic-button--size {
    &-extra-large {
      height: 58px;
      width: 58px;
    }

    &-large {
      height: 45px;
      width: 45px;
    }

    &-large,
    &-extra-large {
      padding: $unnnic-inset-xs;
    }

    &-small {
      padding: $unnnic-inset-nano;
      height: 37px;
      width: 37px;
    }
  }
}
</style>
