<template>
  <Transition
    :name="cn.b()"
    @before-leave="$emit('close')"
    @after-leave="$emit('destroy')"
  >
    <UiAlert
      v-show="visible"
      :id="id"
      :class="[cn.b(), verticalSide, horizontalSide]"
      :title="title"
      :type="type"
      @mouseenter="clearTimer"
      @mouseleave="startTimer"
    >
      <slot />
    </UiAlert>
  </Transition>
</template>

<script setup lang="ts">
import type { NotificationPlacement, NotificationType } from './types'
import { computed, onMounted, ref } from 'vue'

export interface Props {
  duration?: number
  id?: string | number
  offset?: number
  placement?: NotificationPlacement
  type?: NotificationType
  title?: string
  zIndex?: number
}

defineOptions({
  name: 'UiNotification',
})

const props = withDefaults(defineProps<Props>(), {
  type: 'neutral',
  duration: 5000,
  offset: 0,
  placement: 'top-right',
  zIndex: 0,
})

defineEmits(['close', 'destroy'])

const cn = useClassname('ui-notification')

const timerId = ref()
const visible = ref(false)

const verticalSide = computed(() => props.placement.split('-')[0])
const horizontalSide = computed(() => props.placement.split('-')[1])

function close() {
  visible.value = false
}

function startTimer() {
  if (props.duration > 0) {
    timerId.value = setTimeout(() => {
      if (visible.value)
        close()
    }, props.duration)
  }
}

function clearTimer() {
  if (timerId.value)
    clearTimeout(timerId.value)
}

onMounted(() => {
  startTimer()
  visible.value = true
})

defineExpose({
  visible,
  close,
})
</script>

<style lang="scss">
.ui-notification {
  position: fixed;
  transition-duration: $transition-duration;
  transition-property: opacity, transform, left, right, top, bottom;
  z-index: calc(8000 + v-bind('zIndex'));
  width: 400px;
  transform-origin: right top;

  @include mobile {
    width: calc(100% - 32px);
  }

  &.top {
    top: calc(v-bind('`${offset}px`') + 80px);

    @include mobile {
      top: auto;
      bottom: v-bind('`${offset}px`');
    }
  }

  &.bottom {
    bottom: v-bind('`${offset}px`');
  }

  &.left {
    left: 32px;

    @include mobile {
      left: 16px;
    }
  }

  &.right {
    right: 32px;

    @include mobile {
      right: 16px;
    }
  }
}
</style>
