<template>
  <div class="itf-datepicker input-group" :class="{'with-addon addon-start': prependIcon, 'with-addon addon-end': clearable}">
    <div class="addon" v-if="prependIcon">
      <slot name="addon">
        <itf-icon :name="prependIcon" />
      </slot>
    </div>
    <i-mask-component
      ref="input"
      class="form-control"
      :class="{ 'is-invalid': isInvalid(), 'is-valid': isSuccess() }"
      @input="updateValue($event)"
      @focus="onFocus"
      @blur="onBlur"
      :value="displayValue"
      :mask="Date"
      :pattern="dateFormat"
      :blocks="blocks"
      :format="format"
      :parse="parse"
      :unmask="false"
      :lazy="!focused"
      :placeholder="placeholder"
      :disabled="disabled"
    />

    <div class="addon-end" v-if="clearable && value">
      <slot name="clear">
        <itf-button
          icon
          small
          @click="$emit('input', '')"
        >
          <itf-icon name="close" />
        </itf-button>
      </slot>
    </div>
    <div style="display: none">
      <div ref="dropdown" class="itf-datepicker__dropdown">
        <itf-date-picker-inline
          :value="value"
          :start-view="startView"
          :only-calendar="onlyCalendar"
          :display-format="dateFormat"
          :value-format="valueFormat"
          :min-date="minDate"
          :max-date="maxDate"
          :days-list="daysList"
          @input="selectInlineDate"
        ></itf-date-picker-inline>
      </div>
    </div>
  </div>
</template>
<script>
import {
  Vue, Component, Prop, Inject
} from 'vue-property-decorator';
import { IMask, IMaskComponent } from 'vue-imask';
import { DateTime } from 'luxon';
import tippy from 'tippy.js';
import { debounce } from '../../helpers/debounce';
import itfIcon from '../icon/Icon.vue';
import itfButton from '../button/Button.vue';
import itfDatePickerInline from './DatePickerInline.vue';
import ITFSettings from '../../ITFSettings';

export default @Component({
  name: 'itfDatePicker',
  components: {
    itfIcon,
    itfButton,
    itfDatePickerInline,
    IMaskComponent,
  },
})
class itfDatePicker extends Vue {
  @Inject({ default: null }) itemLabel;

  @Prop({ type: String }) value;
  @Prop({ type: [Number, String], default: 300 }) delayInput;
  @Prop({ type: String, default: 'ISO' }) valueFormat;
  @Prop({ type: String }) displayFormat;
  @Prop({ type: Array }) daysList;
  @Prop({ type: String, default: 'days', validator: (value) => ['days', 'months', 'years'].includes(value) }) startView;
  @Prop({ type: Boolean, default: false }) onlyCalendar;
  @Prop({ type: String, default: '' }) placeholder;
  @Prop({ type: String, default: '' }) prependIcon;
  @Prop({ type: String, default: 'bottom-start' }) placement;
  @Prop({ type:  [String, Date], default: '' }) minDate;
  @Prop({ type:  [String, Date], default: '' }) maxDate;
  @Prop(Boolean) clearable;
  @Prop(Boolean) disabled;

  focused = false;

  tooltip = null;

  blocks = {
    yyyy: {
      mask: IMask.MaskedRange,
      from: 1970,
      to: 2100,
    },
    MM: {
      mask: IMask.MaskedRange,
      from: 1,
      to: 12,
    },
    dd: {
      mask: IMask.MaskedRange,
      from: 1,
      to: 31,
    },
  };

  isInvalid() {
    return this.itemLabel && this.itemLabel.isHasError();
  }

  isSuccess() {
    return this.itemLabel && this.itemLabel.isHasSuccess();
  }

  mounted() {
    if (this.disabled) {
      return;
    }
    // якщо в модалці, то контекст модалки, якщо ні, то аплікейшена
    const context = this.$el.closest('.itf-append-context') || document.body;
    this.tooltip = tippy(this.$refs.input.$el, {
      interactiveBorder: 30,
      interactiveDebounce: 75,
      animation: 'scale',
      arrow: true,
      content: this.$refs.dropdown,
      allowHTML: true,
      trigger: 'click',
      interactive: true,
      placement: this.placement,
      appendTo: context
    });

    this.setValue = debounce((val) => this.$emit('input', val), this.delayInput)
  }

  get valueAsLuxon() {
    if (!this.value) {
      return null;
    }
    if (this.valueFormat === 'ISO') {
      return DateTime.fromISO(this.value, { zone: 'UTC' });
    }
    return DateTime.fromFormat(this.value, this.valueFormat);
  }

  get dateFormat() {
    return this.displayFormat || ITFSettings.defaultDisplayDateFormat;
  }

  get displayValue() {
    if (!this.valueAsLuxon) {
      return '';
    }
    return this.valueAsLuxon.toFormat(this.dateFormat);
  }

  get minDateLuxon() {
    return this.minDate && (typeof this.minDate === 'string' ? DateTime.fromISO(this.minDate) : DateTime.fromJSDate(this.minDate));
  }

  updateValue(value, emitEmpty = false) {
    const val = value && DateTime.fromFormat(value, this.dateFormat, { zone: 'UTC' });
    if (!val || !val.isValid) {
      if (emitEmpty) {
        this.setValue(null);
      }
      return;
    }
    if (this.minDateLuxon && val < this.minDateLuxon) {
      return;
    }
    this.setValue(this.valueFormat === 'ISO' ? val.toISO() : val.toFormat(this.valueFormat));
  }

  format(date) {
    return DateTime.fromJSDate(date).toFormat(this.dateFormat);
  }

  parse(str) {
    return DateTime.fromFormat(str, this.dateFormat).toJSDate();
  }

  onFocus() {
    if (this.disabled) {
      return;
    }
    this.focused = true;
  }

  onBlur(e) {
    if (this.disabled) {
      return;
    }
    this.focused = false;
    this.updateValue(e.target.value, !!e.target.value);
  }

  selectInlineDate(date) {
    this.$emit('input', date);
    this.tooltip.hide();
  }
}
</script>
