<template>
  <div class="itf-datepicker-inline">
    <div ref="calendar"></div>

    <div class="air-datepicker -inline-" v-if="!onlyCalendar">
      <nav class="air-datepicker-nav align-items-center">
        <div class="air-datepicker-title">{{$t('components.relativeDates')}}</div>
      </nav>

      <div class="d-grid gap-1 p-2">
        <button
          v-for="(item, n) in daysList"
          :key="n"
          :disabled="!isEnabled(item.date)"
          :class="{'active': isSelected(item.date)}"
          @click="selectDate(item.date)"
          class="btn btn-outline-primary btn-sm text-start">
          {{item.title}}
        </button>
      </div>
    </div>
  </div>
</template>
<script>
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';
import { DateTime } from 'luxon';
import ITFSettings from '../../ITFSettings';

export default @Component({
  name: 'itfDatePickerInline',
})
class itfDatePickerInline extends Vue {
  @Prop({ type: String }) value;
  @Prop({ type: String, default: 'yyyy-MM-dd' }) valueFormat;
  @Prop({ type: String, default: ITFSettings.defaultDisplayDateFormat }) displayFormat;
  @Prop({ type: String, default: 'days', validator: (value) => ['days', 'months', 'years'].includes(value) }) startView;
  @Prop({ type: String, default: 'days', validator: (value) => ['days', 'months', 'years'].includes(value) }) minView;
  @Prop({ type: Boolean, default: false }) onlyCalendar;
  @Prop({ type: Boolean, default: false }) range;
  @Prop({ type: Object, default: () => ({}) }) customDays;
  @Prop({ type:  [String, Date], default: '' }) minDate;
  @Prop({ type:  [String, Date], default: '' }) maxDate;
  @Prop({
    type: Array,
    default: function () {
      return [
        { title: this.$t('components.today'), date: {} },
        { title: this.$t('components.tomorrow'), date: { days: 1 } },
        { title: this.$t('components.inAWeek'), date: { week: 1 } },
        { title: this.$t('components.inAMonth'), date: { month: 1 } },
        { title: this.$t('components.inAHalfYear'), date: { month: 6 } },
        { title: this.$t('components.inAYear'), date: { year: 1 } },
      ];
    }
  }) daysList;

  calendar = null;

  mounted() {
    this.createCalendar();
  }

  @Watch('minDate')
  async createCalendar() {
    if (this.calendar) {
      this.destroyCalendar();
    }

    const [
      { default: AirDatepicker },
      { default: localeEn },
      { default: localeUk },
      { default: localeDe }
    ] = await Promise.all([
      import('babel-loader!../../../libs/air-datepicker/air-datepicker'),
      import('babel-loader!../../../libs/air-datepicker/locale/en'),
      import('babel-loader!../../../libs/air-datepicker/locale/uk'),
      import('babel-loader!../../../libs/air-datepicker/locale/de')
    ]);

    const locales = {
      en: localeEn,
      uk: localeUk,
      de: localeDe,
    };
    this.calendar = new AirDatepicker(this.$refs.calendar, {
      locale: locales[this.$i18n.locale] || locales.en,
      firstDay: 1,
      altFieldDateFormat: this.valueFormat,
      range: this.range,
      view: (this.valueAsLuxon && !this.minView) ? 'days' : this.startView,
      minView: this.minView,
      minDate: this.minDate === 'today' ? new Date() : this.minDate,
      maxDate: this.maxDate === 'today' ? new Date() : this.maxDate,
      selectedDates: this.valueAsLuxon ? [this.valueAsLuxon.toJSDate()] : [],
      onSelect: ({ date }) => {
        if (this.range && !this.calendar.rangeDateTo) {
          return;
        }
        if (this.range) {
          this.updateValue(
            DateTime.fromJSDate(this.calendar.rangeDateFrom).toFormat(this.displayFormat),
            false
          );
        } else {
          this.updateValue(DateTime.fromJSDate(date).toFormat(this.displayFormat));
        }
      },
      onRenderCell: ({ date }) => {
        const strDate = DateTime.fromJSDate(date).toFormat('yyyy-MM-dd');
        if (!this.customDays[strDate]) {
          return { html: false, classes: false };
        }
        return {
          html: this.customDays[strDate].text || false,
          classes: this.customDays[strDate].class || false
        };
      },
    });
    if (this.valueAsLuxon) {
      this.calendar.setViewDate(this.valueAsLuxon.toJSDate());
    }
  }

  beforeDestroy() {
    this.destroyCalendar();
  }

  destroyCalendar() {
    if (!this.calendar) {
      return;
    }
    this.calendar.destroy();
    this.calendar = null;
  }

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

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

  updateValue(value, emitEmpty = false) {
    const val = value && DateTime.fromFormat(value, this.displayFormat);
    if (!val || !val.isValid) {
      if (emitEmpty) {
        this.$emit('input', null);
      }
      return;
    }
    if (this.valueFormat === 'ISO') {
      return this.$emit('input', val.toISO());
    }
    this.$emit('input', val.toFormat(this.valueFormat));
  }

  isSelected(date) {
    if (!this.valueAsLuxon) {
      return false;
    }
    return this.valueAsLuxon.hasSame(DateTime.local().plus(date), 'day');
  }

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

  isEnabled(date) {
    const lxDate = DateTime.local().plus(date);
    return !(this.minDateLuxon && lxDate < this.minDateLuxon);
  }

  selectDate(date) {
    let lxDate = DateTime.local().plus(date);
    if (this.minDateLuxon && lxDate < this.minDateLuxon) {
      return;
    }
    this.calendar.selectDate(lxDate.toJSDate());
    this.updateValue(lxDate.toFormat(this.displayFormat));
  }

  @Watch('value')
  onValueChanged() {
    if (!this.valueAsLuxon || !this.calendar) {
      this.calendar && this.calendar.clear({ silent: true });
      return;
    }
    this.calendar.selectDate(this.valueAsLuxon.toJSDate(), { silent: true });
  }
}
</script>
