<template>
  <div
    @click="tryClose"
    data-notify="container"
    class="alert alert-notify alert-dismissible"
    :class="[{ 'alert-with-icon': icon }, verticalAlign, horizontalAlign, alertType]"
    role="alert"
    :style="customPosition"
    data-notify-position="top-center"
  >
    <template v-if="icon || $slots.icon">
      <slot name="icon">
        <span class="alert-icon" data-notify="icon">
          <i :class="icon"></i>
        </span>
      </slot>
    </template>

    <span class="alert-text">
      <span v-if="title" class="title">
        <b>
          {{ title }}
          <br />
        </b>
      </span>
      <span v-if="message" v-html="message"></span>
      <content-render v-if="!message && component" :component="component"></content-render>
    </span>

    <slot name="dismiss-icon">
      <button type="button" class="close" data-dismiss="alert" aria-label="Close" @click="close">
        <span aria-hidden="true">×</span>
      </button>
    </slot>
  </div>
</template>
<script>
export default {
  name: 'notification',
  components: {
    contentRender: {
      props: ['component'],
      render: function (createElement) {
        return createElement(this.component)
      },
    },
  },
  props: {
    message: String,
    title: {
      type: String,
      description: 'Notification title',
    },
    icon: {
      type: String,
      description: 'Notification icon',
    },
    verticalAlign: {
      type: String,
      default: 'top',
      validator: (value) => {
        let acceptedValues = ['top', 'bottom']
        return acceptedValues.indexOf(value) !== -1
      },
      description: 'Vertical alignment of notification (top|bottom)',
    },
    horizontalAlign: {
      type: String,
      default: 'right',
      validator: (value) => {
        let acceptedValues = ['left', 'center', 'right']
        return acceptedValues.indexOf(value) !== -1
      },
      description: 'Horizontal alignment of notification (left|center|right)',
    },
    type: {
      type: String,
      default: 'info',
      validator: (value) => {
        let acceptedValues = ['default', 'info', 'primary', 'danger', 'warning', 'success']
        return acceptedValues.indexOf(value) !== -1
      },
      description:
        'Notification type of notification (default|info|primary|danger|warning|success)',
    },
    timeout: {
      type: Number,
      default: 5000,
      validator: (value) => {
        return value >= 0
      },
      description: 'Notification timeout (closes after X milliseconds). Default is 5000 (5s)',
    },
    timestamp: {
      type: Date,
      default: () => new Date(),
      description:
        'Notification timestamp (used internally to handle notification removal correctly)',
    },
    component: {
      type: [Object, Function],
      description: 'Custom content component. Cane be a `.vue` component or render function',
    },
    showClose: {
      type: Boolean,
      default: true,
      description: 'Whether to show close button',
    },
    closeOnClick: {
      type: Boolean,
      default: true,
      description: "Whether to close notification when clicking it' body",
    },
    clickHandler: {
      type: Function,
      description: 'Custom notification click handler',
    },
  },
  data() {
    return {
      elmHeight: 0,
    }
  },
  computed: {
    hasIcon() {
      return this.icon && this.icon.length > 0
    },
    alertType() {
      return `alert-${this.type}`
    },
    customPosition() {
      let initialMargin = 20
      let alertHeight = this.elmHeight + 10
      let sameAlertsCount = this.$notifications.state.filter((alert) => {
        return (
          alert.horizontalAlign === this.horizontalAlign &&
          alert.verticalAlign === this.verticalAlign &&
          alert.timestamp <= this.timestamp
        )
      }).length
      if (this.$notifications.settings.overlap) {
        sameAlertsCount = 1
      }
      let pixels = (sameAlertsCount - 1) * alertHeight + initialMargin
      let styles = {}
      if (this.verticalAlign === 'top') {
        styles.top = `${pixels}px`
      } else {
        styles.bottom = `${pixels}px`
      }
      return styles
    },
  },
  methods: {
    close() {
      this.$emit('close', this.timestamp)
    },
    tryClose(evt) {
      if (this.clickHandler) {
        this.clickHandler(evt, this)
      }
      if (this.closeOnClick) {
        this.close()
      }
    },
  },
  mounted() {
    this.elmHeight = this.$el.clientHeight
    if (this.timeout) {
      setTimeout(this.close, this.timeout)
    }
  },
}
</script>
<style lang="scss">
.notifications .alert {
  position: fixed;
  z-index: 10000;

  &[data-notify='container'] {
    max-width: 500px;
  }

  &.center {
    margin: 0 auto;
  }
  &.left {
    left: 20px;
  }
  &.right {
    right: 20px;
  }
}
</style>
