<template>
  <transition
      appear
      :name="transition"
      :css="!!transition"
      @before-leave="beforeLeave"
      @after-leave="$emit('destroy')"
  >
    <div
        v-show="isActive"
        :class="containerClass"
        :style="positionStyle"
        :id="id"
        ref="refAlert"
        role="alert"
        @mouseenter="mouseenter"
        @mouseleave="mouseleave">
      <!---->
      <div class="nv-alert__underlay"></div>
      <div class="nv-alert__border"></div>
      <div v-if="iconComputed" class="nv-alert__prepend">
        <NvIcon :icon="iconComputed" class="my-0.5"/>
      </div>
      <div class="nv-alert__content">
        <div class="nv-alert-title">
          <slot name="title">{{ title }}</slot>
        </div>
        <div class="nv-alert-text">
          <slot>{{ text }}</slot>
        </div>
        <!---->
      </div>
      <div class="nv-alert__append">
        <slot name="append"/>
      </div>
      <template v-if="false">
        <div v-if="closable" class="nv-alert__close">
          <NvIcon icon="nvi-close" @click="close"/>
        </div>
      </template>
      <div v-if="buttons.length || closable" class="nv-alert__btns">
        <div v-if="closable" @click="close" class="nv-alert__btn">
          <NvIcon icon="nvi-close" class="mx-auto"/>
        </div>
        <template v-for="btn in buttons">
          <div @click="btnClick(btn)" class="nv-alert__btn">
            {{ btn.title }}
          </div>
        </template>
      </div>
      <div v-if="duration" class="nv-alert__progress" :class="progressClass" :style="progressStyle"></div>
    </div>
  </transition>
</template>

<script>

import {NvIcon} from "../NvIcon/index";
import {computed, watch, ref, nextTick} from "vue";
import {onBeforeMount, onMounted} from "vue";

const allowedVariants = [
  'outlined',
  'plain',
  'text',
  'contained',
  'contained-flat',
  'contained-text',
]
const allowedTypes = [
  'info',
  'alert',
  'success',
  'warning',
  'dark',
]

export default {
  name: 'Alert',
  components: {NvIcon},
  emits: ['update:modelValue', 'destroy'],
  props: {
    modelValue: {
      type: Boolean,
      default: true,
    },
    type: {
      type: String,
      validator: (v) => allowedTypes.includes(v),
      default: 'dark'
    },
    closable: Boolean,
    icon: {
      type: [String, Boolean],
      default: ''
    },
    prominent: Boolean,
    title: String,
    text: String,
    variant: {
      type: String,
      default: 'contained-flat',
      validator: (v) => allowedVariants.includes(v),
    },
    duration: Number,
    id: String,
    fixed: Boolean,
    position: {
      type: String,
      default: '',
      validator(v) {
        return [
          '',
          'top',
          'top-right',
          'top-left',
          'bottom',
          'bottom-right',
          'bottom-left'
        ].includes(v)
      }
    },
    offset: Number,
    onClose: {
      type: Function,
      required: false,
    },

    transition: String,
    buttons: {
      type: Array,
      default: []
    },
    border: {
      type: [Boolean, String],
      validator: (val) => {
        return typeof val === 'boolean' || [
          'top',
          'end',
          'bottom',
          'start',
        ].includes(val)
      },
    },
  },

  setup(props, {emit}) {
    const isActive = ref(true)
    const refAlert = ref(null);

    const containerClass = computed(() => {
      const type = allowedTypes.includes(props.type) ? props.type : 'dark'
      return ['nv-alert', `nv-alert--${type}`, `nv-alert--variant-${props.variant}`,
        props.position ? `nv-alert--${props.position}` : '',
        props.border ? `nv-alert--border-${props.border}` : '',
        // props.variant === 'outlined' ? `text-${props.type}`: '',
        {
          'nv-alert--prominent': props.prominent,
          'nv-alert--fixed': props.fixed,
          'nv-alert--border': !!props.border,
          [`nv-alert--border-${props.border === true ? 'start' : props.border}`]: true,
        },
      ]
    })

    const iconComputed = computed(() => {
      if (props.icon === false) return ''
      return props.icon ? props.icon :
          props.type === 'info' ? 'nvi-alert-box-outline' :
              props.type === 'success' ? 'nvi-checkbox-on-outline' :
                  props.type === 'warning' ? 'nvi-alert-outline' :
                      props.type === 'alert' ? 'nvi-close-box-outline' : ''
    })

    function close() {
      isActive.value = false
      emit('update:modelValue', false)
    }

    let timer = null

    function startTimer() {
      if (props.duration > 0) {
        timer = setTimeout(() => {
          if (props.modelValue) close()
        }, props.duration);
      }
    }

    function clearTimer() {
      if (timer) clearTimeout(timer)
    }

    const progressClass = ref('')
    const progressStyle = ref({
      transition: `all ${props.duration / 1000}s linear`
    })

    // lifecycle
    onMounted(() => {
      startTimer();

      if (props.duration) {
        setTimeout(() => {
          progressClass.value = 'nv-alert__progress_scale'
        }, 0)
      }
    })

    const verticalProperty = computed(() =>
        props.position.startsWith('top') ? 'top' : 'bottom'
    )

    const positionStyle = computed(() => {
      return {
        [verticalProperty.value]: `${props.offset}px`
      }
    })

    function beforeLeave() {
      if (props.onClose) props.onClose();
    }

    function mouseenter() {
      if (props.duration) {
        progressStyle.value.transition = 'none'
        progressClass.value = ''
      }
      clearTimer()
    }

    function mouseleave() {
      if (props.duration) {
        progressStyle.value.transition = `all ${props.duration / 1000}s linear`
        progressClass.value = 'nv-alert__progress_scale'
      }
      startTimer()
    }

    function btnClick(btn) {
      btn.action();
      if (btn.closeOnClick) {
        close()
      }
    }

    return {
      containerClass,
      iconComputed,
      positionStyle,
      beforeLeave,
      close,
      mouseleave,
      mouseenter,
      refAlert,
      isActive,
      timer,
      progressClass,
      progressStyle,
      btnClick
    }
  }
}
</script>
