<template>

  <div class="itf-modal modal fade" ref="modal" tabindex="-1" :aria-labelledby="modalId" aria-hidden="true">
    <div
      class="modal-dialog modal-dialog-centered"
      :class="{[`modal-${size}`]: size, 'modal-fullscreen': fullscreen, 'modal-fullscreen-sm-down': !fullscreen}"
    >
      <slot name="content">
        <div class="modal-content itf-append-context" ref="content" @click.stop>
          <div v-if="title || $slots.title" class="modal-header">
            <slot name="title">
              <h5 class="modal-title" :id="modalId">{{title}}</h5>
            </slot>
            <itf-button icon @click="close" :aria-label="$t('components.close')" class="btn-close"></itf-button>
          </div>
          <div class="modal-body" v-if="value" v-loading="loading">
            <slot></slot>
          </div>
          <div class="modal-footer" v-if="$slots.footer">
            <slot name="footer"></slot>
          </div>
        </div>
      </slot>
    </div>
  </div>

</template>
<script>
import { Vue, Component, Prop, Watch, PropSync, Inject } from 'vue-property-decorator';
import itfButton from '../button/Button';
import loading from '../../directives/loading';

let globalModalIndex = 0; // base modal z-index
let globalZIndexStack = 300; // base modal z-index
let modalStack = [];

export default @Component({
  name: 'itfModal',
  components: {
    itfButton
  },
  directives: {
    loading
  }
})
class itfModal extends Vue {
  @Inject({ default: null }) globalApp;

  @PropSync('visible') value;
  @Prop({ type: String }) title;
  @Prop({ type: String, default: '', validator: (value) => ['', 'sm', 'lg', 'xl'].includes(value) }) size;

  @Prop({ type: Number, default: 500 }) animationDuration
  @Prop({ type: Boolean, default: false }) loading;
  @Prop({ type: Boolean, default: false }) fullscreen;
  @Prop({ type: Boolean, default: false }) basic;
  @Prop({ type: Boolean, default: false }) image;
  @Prop({ type: Boolean, default: false }) closable
  @Prop({ type: Boolean, default: false }) closeIcon
  @Prop({ type: Boolean, default: false }) persistent
  @Prop({ type: Boolean, default: false }) slider
  @Prop({ type: Boolean, default: false }) escClose
  @Prop({ type: Function, default: null }) onEscClose;
  @Prop({ type: Boolean, default: true }) appendToBody;
  @Prop({ type: Boolean, default: false }) appendToContext;
  @Prop({ type: Boolean, default: false }) content;
  @Prop({ type: Boolean, default: false }) scrolling;
  @Prop({ type: Number, default: null }) zIndex;

  modalId = '';
  modalEl = null;
  preventEvents = false;
  onClose = null;

  beforeDestroy () {
    this.close();
  }

  @Watch('value')
  onVisibleChanged(newValue, oldValue) {
    if (!this.modalEl || (this.preventEvents && oldValue !== true) || (typeof oldValue === 'undefined' && !newValue)) {
      return;
    }
    if (newValue) {
      if (modalStack.length > 0) {
        modalStack[modalStack.length - 1].unbindEvents();
        modalStack[modalStack.length - 1].hide(true);
      }
      setTimeout(() => {
        this.modalEl.show();
        modalStack.push(this);
      }, modalStack.length ? 500 : 0);
    } else {
      this.modalEl.hide();
      modalStack.pop();
      if (modalStack.length > 0) {
        setTimeout(() => {
          modalStack[modalStack.length - 1].show();
          modalStack[modalStack.length - 1].bindEvents();
        }, modalStack.length ? 500 : 0);
      }
    }
  }

  created() {
    globalModalIndex += 1;
    this.modalId = `modalId${globalModalIndex}`;
    this.onClose = () => {
      this.value = false;
      this.$emit('close');
    };
  }

  async mounted() {
    if (typeof window === 'undefined') {
      return;
    }
    let context = document.body;
    if (this.appendToContext && this.$el instanceof Node && this.$el.parentNode) {
      context = this.$el.closest('.itf-append-context:not(.modal-content)') || document.body;
      this.$el.parentNode.removeChild(this.$el);
      context.appendChild(this.$el); // should append only to body
    } else if (this.appendToBody && this.$el instanceof Node && this.$el.parentNode) {
      this.$el.parentNode.removeChild(this.$el);
      context.appendChild(this.$el); // should append only to body
    }
    const { default: Modal } = await import('./modalSrc');
    this.modalEl = new Modal(this.$el, { context, backdrop: 'static' });
    this.onVisibleChanged(this.value);
    this.bindEvents();
  }

  bindEvents() {
    this.preventEvents = false;
    if (this.$refs.modal) {
      this.$refs.modal.addEventListener('hidden.bs.modal', this.onClose);
    }
  }

  unbindEvents() {
    this.preventEvents = true;
    if (this.$refs.modal) {
      this.$refs.modal.removeEventListener('hidden.bs.modal', this.onClose);
    }
  }

  show() {
    if (this.modalEl) {
      this.modalEl.show();
    }
  }

  hide() {
    if (this.modalEl) {
      this.modalEl.hide();
    }
  }

  close() {
    if (this.modalEl) {
      this.value = false;
      this.$emit('close');
    }
  }

  scrollModalTop() {
    const scrollEl = this.$el.closest('.itf-modal');
    if (scrollEl) {
      scrollEl.scrollTop = 0;
    }
  }
}
</script>
