<template>
  <div class="filter-date-range-container">
    <ElForm label-position="top">
      <ElFormItem
        v-for="input in [ 'from', 'to' ]"
        :key="input"
        :for="input"
        :label="input"
      >
        <ElInput
          :ref="`input-${input}`"
          :class="{ 'is-active': selectedValueType === input }"
          :data-test="`filter date range edit ${input}`"
          :value="inputValues[input]"
          readonly
          placeholder="Select Date"
          @focus="focusInput(input)"
        >
          <icon
            slot="prefix"
            name="regular/calendar-alt"
          />
        </ElInput>
      </ElFormItem>
    </ElForm>
    <div
      v-for="calendarType in [ 'start', 'end' ]"
      :key="calendarType"
      :class="`calendar-${calendarType}`"
    >
      <!-- Temporarily watching the @changed-decade event because of a Datepicker bug -->
      <!-- Follow bug at: https://github.com/sumcumo/vue-datepicker/issues/121 -->
      <TfDatePicker
        v-bind="{
          ...datepickerOptions,
          highlighted,
          openDate: calendarType === 'start' ? openDate : openToDate,
          value: localSelectedDate[calendarType],
          showEdgeDates: false,
        }"
        :data-test="`filter date range ${calendarType} calendar`"
        @changed-decade="changeMonth(calendarType)"
        @changed-month="changeMonth(calendarType)"
        @selected="selectDate($event, calendarType)"
      />
    </div>
    <TfButton
      class="btn-to-current"
      type="primary"
      size="text-small"
      :data-test="`filter date range select to today`"
      @click="changeToToday"
      v-text="'Back to Today'"
    />
  </div>
</template>
<script>
  import moment from 'moment';

  export default {
    name: 'TfFilterDateRange',
    props: {
      value: {
        type: Array,
        required: true,
      },
    },
    data: () => ({
      datepickerOptions: {
        inline: true,
        maximumView: 'day',
        minimumView: 'day',
      },
      localSelectedDate: {
        end: '',
        start: '',
      },
      openDate: null,
      selectedValueType: 'from',
    }),
    computed: {
      /**
       * Create an object with 'from' and 'to' based on the model value.
       * 'from' and 'to' should be dates or empty strings.
       *
       * @returns {object}
       */
      highlighted() {
        const [from, to] = this.value || ['', ''];
        const resetTime = (value) => {
          // when dates come through as strings we convert back to date or setHours doesnt exist
          const validatedDate = value instanceof Date ? value : new Date(value);
          return new Date(validatedDate.setHours(0, 0, 0, 0));
        };

        return {
          from: from ? resetTime(from) : '',
          to: to ? resetTime(to) : '',
        };
      },
      /**
       * Format 'from' and 'to' from this.highlighted into date strings for the input values.
       * 'from' and 'to' should be formatted strings or empty strings.
       *
       * @returns {object}
       */
      inputValues() {
        const { from, to } = this.highlighted;
        const format = (value) => this.$TF.DatesUtils.formatSimpleDate(value, 'MM/DD/YY');

        return {
          from: from ? format(from) : '',
          to: to ? format(to) : '',
        };
      },
      /**
       * Add one month to this.openDate and format it to a string.
       *
       * @returns {string}
       */
      openToDate() {
        return new Date(moment(this.openDate).add(1, 'months'));
      },
    },
    created() {
      const openDate = this.highlighted.from ? new Date(this.highlighted.from) : new Date();

      this.openDate = openDate;
    },
    methods: {
      /**
       * Subtract or add 2 months to this.openDate based on the passed param.
       *
       * @param {string} calendarType
       */
      changeMonth(calendarType) {
        let openDate = moment(this.openDate);

        if (calendarType === 'start') {
          openDate = openDate.subtract(2, 'months');
        } else if (calendarType === 'end') {
          openDate = openDate.add(2, 'months');
        }

        this.openDate = new Date(openDate);
      },
      /**
       * Changes the open date and to today's date, sets the 'from' value to today's date, and focuses on the 'to' input.
       */
      changeToToday() {
        const openDate = new Date();

        this.openDate = openDate;
        this.selectedValueType = 'to';
        this.localSelectedDate.start = openDate;
        this.localSelectedDate.end = '';
        this.$emit('input', [openDate, '']);
      },
      /**
       * Focus on the first checkbox.
       *
       * @param {string} value
       */
      focusInput(value) {
        this.selectedValueType = value;
        this.$refs[`input-${value}`][0].$el.querySelector('input').blur();
      },
      /**
       * $emit 'input' with new "from" and "to" dates.
       * Update this.selectedValueType based on different scenarios.
       * Clear the localSelectedDate start and end values as well,
       * followed by setting the selected value for that calendar appropriately.
       * This is to hack some of the logic for the datepicker component.
       *
       * @param {object} value
       * @param {string} calendarType
       */
      selectDate(value, calendarType) {
        let { from, to } = this.highlighted;
        let selectedValueType;

        this.localSelectedDate.start = '';
        this.localSelectedDate.end = '';

        if (this.selectedValueType === 'from') {
          from = value;
          selectedValueType = 'to';

          if (to && moment(value).isSameOrAfter(to)) {
            to = value;
          }
        } else if (this.selectedValueType === 'to') {
          selectedValueType = 'from';
          to = value;

          if (from && moment(value).isSameOrBefore(from)) {
            from = value;
            selectedValueType = 'to';
          }
        }

        this.localSelectedDate[calendarType] = value;
        this.$emit('input', [from, to]);
        this.selectedValueType = selectedValueType;
      },
    },
  };
</script>

<style lang="scss" scoped>
  @import 'src/assets/styles/variables';

  .btn-to-current {
    margin: 10px 0 20px;
  }

  /* stylelint-disable selector-max-compound-selectors */
  .calendar-start {
    margin-right: 75px;

    ::v-deep header {
      .next {
        display: none !important; // stylelint-disable-line
      }

      .prev {
        flex: 1;
      }

      &:after {
        flex: 1;
        content: '';
      }
    }
  }

  .calendar-end {
    ::v-deep header {
      .next {
        flex: 1;
      }

      .prev {
        display: none !important; // stylelint-disable-line
      }

      &:before {
        flex: 1;
        content: '';
      }
    }
  }
  /* stylelint-enable selector-max-compound-selectors */
  form,
  .el-input {
    display: flex;
    flex-direction: row;
    width: 100%;
  }

  .el-form-item {
    margin-bottom: 10px;

    ::v-deep &__label {
      text-transform: capitalize;
      font-weight: 600;
      line-height: inherit;
    }
  }

  .filter-date-range-container {
    display: flex;
    flex-flow: wrap;
    width: 675px;
    padding: 10px 20px;
  }

  ::v-deep .el-input {
    width: 120px;
    margin-right: 20px;

    &__prefix {
      top: 6px;
    }

    &__inner:focus {
      border-color: inherit;
    }
  }
</style>
