<template>
  <Teleport to="body">
    <div
      ref="container"
      :class="containerClass"
      v-bind="$attrs"
    >
      <transition-group
        name="vc-toast-message"
        tag="div"
        @enter="onEnter"
        @after-leave="onLeave"
      >
        <VcNotificationMessage
          v-for="msg of messages"
          :key="msg.id"
          :message="msg"
          @close="remove($event)"
        />
      </transition-group>
    </div>
  </Teleport>
</template>

<script lang="ts">

import { defineComponent, PropType } from 'vue'
import { ToastPositionType, ToastMessageOptions } from './VcNotification.types'
import UniqueComponentId from '@/utils/UniqueComponentId'
import ZIndexUtils from '@/utils/ZIndexUtils'
import ToastEventBus from '@/utils/ToastEventBus'
import VcNotificationMessage from '@/components/VcNotification/VcNotificationMessage.vue'

const BASE_Z_INDEX = 3000

export default defineComponent({
  name: 'VcNotification',
  components: { VcNotificationMessage },
  inheritAttrs: false,
  props: {
    position: {
      type: String as PropType<ToastPositionType>,
      default: 'top-right'
    },
    group: {
      type: String,
      default: undefined
    },
    autoZIndex: {
      type: Boolean,
      default: true
    },
    baseZIndex: {
      type: Number,
      default: BASE_Z_INDEX
    }
  },
  data () {
    return {
      messages: [] as ToastMessageOptions[],
      messageIdx: 0,
      styleElement: null,
      customPosition: ''
    }
  },
  computed: {
    containerClass (): string[] {
      const position = this.customPosition || this.position
      return [
        'vc-toast vc-toast-component vc-toast-' + position
      ]
    },
    attributeSelector (): string {
      return UniqueComponentId('vc-toast-id_')
    }
  },
  mounted () {
    ToastEventBus.on('add', this.onAdd)
    ToastEventBus.on('remove-group', this.onRemoveGroup)
    ToastEventBus.on('remove-all-groups', this.onRemoveAllGroups)
  },
  beforeUnmount () {
    const container = this.$refs.container as HTMLElement
    if (container && this.autoZIndex) {
      ZIndexUtils.clear(container)
    }
    ToastEventBus.off('add', this.onAdd)
    ToastEventBus.off('remove-group', this.onRemoveGroup)
    ToastEventBus.off('remove-all-groups', this.onRemoveAllGroups)
  },
  methods: {
    add (message: ToastMessageOptions) {
      if (message.id == null) {
        message.id = this.messageIdx++
      }
      this.messages = [...this.messages, message]
    },
    remove (message: ToastMessageOptions) {
      let index = -1
      for (let i = 0; i < this.messages.length; i++) {
        if (this.messages[i] === message) {
          index = i
          break
        }
      }
      this.messages.splice(index, 1)
    },
    onAdd (message: ToastMessageOptions) {
      if (message.position) {
        this.customPosition = message.position
      }
      // eslint-disable-next-line eqeqeq
      if (this.group == message.group) {
        this.add(message)
      }
    },
    onRemoveGroup (group: string) {
      if (this.group === group) {
        this.messages = []
      }
    },
    onRemoveAllGroups () {
      this.messages = []
    },
    onEnter () {
      const container = this.$refs.container as HTMLElement
      if (!container) {
        return
      }
      container.setAttribute(this.attributeSelector, '')
      if (this.autoZIndex) {
        ZIndexUtils.set('toast', container, this.baseZIndex)
      }
    },
    onLeave () {
      const container = this.$refs.container as HTMLElement
      if (!container) {
        return
      }
      if (container && this.autoZIndex && !this.messages.length) {
        ZIndexUtils.clear(container)
      }
    }
  }
})
</script>

<style lang="scss">
$toastWidth: 27rem;
.vc-toast {
  @apply fixed box-border text-white;
  width: $toastWidth;
  max-width: calc(100% - 2.5rem);
  /* Positions */
  &.vc-toast-top-right {
    @apply top-5 right-5;
  }
  &.vc-toast-top-left {
    @apply top-5 left-5;
  }
  &.vc-toast-bottom-left {
    @apply bottom-5 left-5;
  }
  &.vc-toast-bottom-right {
    @apply bottom-5 right-5;
  }
  &.vc-toast-top-center {
    @apply top-5;
    left: 50%;
    transform: translateX(-50%);
  }
  &.vc-toast-bottom-center {
    @apply bottom-5;
    left: 50%;
    transform: translateX(-50%);
  }
  &.vc-toast-center {
    left: 50%;
    top: 50%;
    min-width: 20vw;
    transform: translate(-50%, -50%);
  }

  /* Message */
  .vc-toast-message {
    @apply shadow-card bg-white opacity-90 hover:opacity-100;
    margin: 0 0 1rem 0;
    border-radius: 0 6px 6px 0;
    transition: all .3s ease;

    .vc-toast-message-content {
      @apply flex items-start p-4;
      border-width: 0 0 0 4px;
      border-color: currentColor;
    }
    .vc-toast-message-text {
      @apply text-default-text pl-4;
      flex: 1 1 auto;
      .vc-toast-summary {
        @apply font-bold text-base mb-2;
      }
      .vc-toast-detail {
        @apply font-medium text-sm;
        line-height: 145%;
      }
    }
    .vc-toast-message-icon {
      @apply self-center flex-shrink-0 text-current;
    }
    .vc-toast-icon-close {
      @apply
      flex
      items-center
      justify-center
      overflow-hidden
      relative
      cursor-pointer
      flex-shrink-0
      text-secondary-actions;
      transition: all .3s ease;
      &:hover {
        @apply text-active-elements--focus;
      }
      &:active {
        @apply text-active-elements--pressed;
      }
    }

    &.vc-toast-message-info {
      @apply text-primary-actions;
    }
    &.vc-toast-message-warn {
      @apply text-warning;
    }
    &.vc-toast-message-error {
      @apply text-error;
    }
    &.vc-toast-message-success {
      @apply text-success;
    }
  }
}

/* Animations */
.vc-toast-message-enter-from {
  opacity: 0;
  transform: translateX(100%);
}
.vc-toast-top-left, .vc-toast-bottom-left {
  .vc-toast-message-enter-from {
    transform: translateX(-100%);
  }
}
.vc-toast-top-right, .vc-toast-bottom-right {
  .vc-toast-message-enter-from {
    transform: translateX(100%);
  }
}
.vc-toast-top-center {
  .vc-toast-message-enter-from {
    transform: translateY(-32px);
  }
}
.vc-toast-bottom-center, .vc-toast-center {
  .vc-toast-message-enter-from {
    transform: translateY(32px);
  }
}

.vc-toast-message-leave-from {
  max-height: 1000px;
}
.vc-toast .vc-toast-message.vc-toast-message-leave-to {
  max-height: 0;
  opacity: 0;
  margin-bottom: 0;
  overflow: hidden;
  transform: translateY(-32px);
}
.vc-toast-message-enter-active {
  -webkit-transition: transform .3s, opacity .3s;
  transition: transform .3s, opacity .3s;
}
.vc-toast-message-leave-active {
  -webkit-transition: max-height .45s cubic-bezier(0, 1, 0, 1), opacity .3s, margin-bottom .3s;
  transition: max-height .45s cubic-bezier(0, 1, 0, 1), opacity .3s, margin-bottom .3s;
}

[dir='rtl'] {
  .vc-toast {
    .vc-toast-message {
      border-radius: 6px 0 0 6px;
      .vc-toast-message-content {
        border-width: 0 4px 0 0;
      }
      .vc-toast-message-text {
        @apply pl-1 pr-4;
      }
    }
  }
}
</style>
