<template>
  <Popup
    trigger-type="manual"
    popup-class="hive-picker"
    :direction="direction"
    :show="popupShow"
    @change="popupShowChangeHandler"
  >
    <!-- input框 -->
    <template v-slot:trigger>
      <div
        :class="triggerClassName"
        @click="showPopup"
      >
        <!-- input inline range -->
        <template v-if="isRange">
          <InputFormatted
            :get-input="getInput('startTimeInput')"
            :disabled="disabled"
            :placeholder="startPlaceholder"
            :size="size"
            :readonly="readonly"
            :parser="inputValueParser"
            :formatter="inputValueFormatter"
            :value="time[0]"
            @change="onInputChange(0)"
            @keydown="onInputKeyDown"
          />
          <span class="hive-picker__input-separator">{{ rangeSeparator || '至' }}</span>
          <InputFormatted
            :get-input="getInput('endTimeInput')"
            :disabled="disabled"
            :placeholder="endPlaceholder"
            :size="size"
            :readonly="readonly"
            :parser="inputValueParser"
            :formatter="inputValueFormatter"
            :value="time[1]"
            @change="onInputChange(1)"
            @keydown="onInputKeyDown"
          />
        </template>
        <!-- input inline single -->
        <template v-else>
          <InputFormatted
            :get-input="getInput"
            :disabled="disabled"
            :placeholder="placeholder"
            :size="size"
            :readonly="readonly"
            :parser="inputValueParser"
            :formatter="inputValueFormatter"
            :value="time"
            @change="onInputChange"
            @keydown="onInputKeyDown"
          />
        </template>

        <!-- input inline 后缀icon -->
        <div class="hive-picker__input-suffixicon">
          <span class="hive-picker__input-icon hive-picker__input-icon--suffix">
            <slot name="suffixIcon">
              <Icon :icon="type === 'time' ? 'line_circle_time' : 'calendar'" />
            </slot>
          </span>
          <span
            class="hive-picker__input-icon hive-picker__input-icon--clear"
            @click.stop="clear"
          >
            <slot
              v-if="allowClear"
              name="clearIcon"
            >
              <Icon :icon="clearIcon || 'circle_clear'" />
            </slot>
          </span>
        </div>
      </div>
    </template>

    <!-- 弹层 -->
    <div class="hive-picker__popup">
      <!-- shortcut -->
      <div
        v-if="shortCut"
        class="hive-picker__popup-shortcut"
      >
        <Button
          v-for="(item, i) in shortCut"
          class="hive-picker__popup-shortcut-btn"
          type="text"
          size="small"
          :key="i"
          @click="shortCutClickHandler(item.value)"
        >
          {{ item.text }}
        </Button>
      </div>

      <!-- panel -->
      <slot v-bind="panelProps" />
    </div>
  </Popup>
</template>

<script>
import Popup from '../popup';
import Icon from '../icon';
import Button from '../button';
import Input from '../input';
import valueFormat from '../input/value-format';
import { parseToDate, dateToFormat, isSameTime, isSame, outOfRanges } from './util';

const InputFormatted = valueFormat(Input, { input: false, blur: true, enter: true });

const DEFAULT_FORMAT = {
  time: 'HH:mm:ss',
  date: 'YYYY-MM-DD',
  datetime: 'YYYY-MM-DD HH:mm:ss',
  month: 'YYYY-MM',
  year: 'YYYY'
};

export default {
  name: 'HiveDatePicker',
  components: {
    InputFormatted,
    Popup,
    Icon,
    Button
  },
  props: {
    value: { type: [Date, String, Array] },
    isRange: Boolean,
    format: String,
    valueFormat: String,
    shortCut: Array,
    allowClear: { type: Boolean, default: true },
    size: { type: String, default: 'default', validator(v) { return ['default', 'small'].indexOf(v) > -1; } },
    error: Boolean,
    disabled: Boolean,
    readonly: Boolean,
    placeholder: String,
    startPlaceholder: String,
    endPlaceholder: String,
    rangeSeparator: String,
    suffixIcon: String,
    clearIcon: String,
    direction: { type: String, default: 'bottom left' },
    /**
     * @ignore
     */
    type: { type: String, validator(v) { return ['time', 'date', 'datetime', 'month', 'year'].indexOf(v) > -1; } }
  },
  data() {
    return {
      time: this.getCleanValue(this.value),
      popupShow: false
    };
  },
  computed: {
    triggerClassName() {
      return [
        'hive-picker__input',
        `hive-picker__input--size-${this.size}`,
        {
          'hive-picker__input--focused': this.popupShow,
          'hive-picker__input--disabled': this.disabled,
          'hive-picker__input--readonly': this.readonly,
          'hive-picker__input--error': this.error,
          'hive-picker__input--empty': this.isRange && this.time ? !this.time.filter(item => item).length : !this.time,
          'hive-picker__input--no-clear': !this.allowClear
        }
      ];
    },
    panelProps() {
      return {
        time: this.time,
        onChangeHandler: this.onChangeHandler.bind(this)
      };
    }
  },
  watch: {
    value(newValue) {
      this.time = this.getCleanValue(newValue);
    }
  },
  methods: {
    popupShowChangeHandler(visible) {
      if (!visible) this.hidePopup();
    },
    shortCutClickHandler(value) {

    },
    showPopup() {
      const { disabled, readonly } = this;
      if (!disabled && !readonly && !this.popupShow) {
        this.popupShow = true;
        this.$emit('focus');
      }
    },
    hidePopup() {
      this.popupShow = false;
      this.$emit('blur');
    },
    clear() {
      const { isRange, allowClear } = this;
      if (!allowClear) return;

      if (isRange) {
        this.onChangeHandler(['', '']);
      } else {
        this.onChangeHandler('');
      }
    },
    onChangeHandler(newTime, fromInput) {
      const { valueFormat, isRange, type } = this;

      // 非受控组件，props没有设置value
      if (typeof this.$props.value === 'undefined') {
        this.time = this.getCleanValue(newTime);
      }

      if (isRange) {
        this.$emit('change', valueFormat ? newTime.map(time => (time ? dateToFormat(time, valueFormat) : time)) : newTime);
      } else {
        this.$emit('change', valueFormat && newTime ? dateToFormat(newTime, valueFormat) : newTime);
      }
      if (!fromInput && type.indexOf('time') === -1) {
        this.hidePopup();
      }
    },
    getInput(el, attr) {
      if (attr) { this.inputTimeEle[attr] = el; } else { this.inputTimeEle = el; }
    },
    onInputChange(value, index) {
      const { isRange } = this;
      let time = value;
      let isChanged = false;
      if (isRange) {
        time = this.time.map((v, i) => {
          if (i === index) {
            isChanged = this.isReallyChanged(v, value);
            return value;
          }
          return v;
        });
      } else {
        isChanged = this.isReallyChanged(this.time, value);
      }
      if (isChanged) this.onChangeHandler(time, true);
    },
    onInputKeyDown(e) {
      if (e.keyCode === 13) {
        this.hidePopup();
      }
    },
    inputValueFormatter(date) {
      if (!date) return '';
      const { format, type } = this;
      return dateToFormat(date, format || DEFAULT_FORMAT[type]);
    },
    inputValueParser(dateStr) {
      if (dateStr === '') return dateStr;
      const { format, type } = this;
      const { disabledDate } = this.$attrs;
      let value = parseToDate(dateStr, format || DEFAULT_FORMAT[type]);
      if (!value) value = new Date(dateStr);
      if (
        value.toDateString() === 'Invalid Date' ||
        (disabledDate && disabledDate(value)) ||
        outOfRanges(value, this.minDate, this.maxDate)
      ) return this.time;

      return value;
    },
    isReallyChanged(oldValue, newValue) {
      const { type } = this;
      if (oldValue instanceof Date && newValue instanceof Date) {
        switch (type) {
          case 'year':
          case 'month':
          case 'date':
            return !isSame(oldValue, newValue, type);
          case 'time':
            return !isSameTime(oldValue, newValue);
          default:
            return !isSame(oldValue, newValue) || !isSameTime(oldValue, newValue);
        }
      }
      if (oldValue === undefined && newValue === '') return false;
      return true;
    },
    getCleanValue(value) {
      let time = [];
      if (this.isRange) {
        value.forEach((v, i) => {
          if (v instanceof Date) {
            time[i] = v;
          } else {
            time[i] = v === '' ? undefined : parseToDate(v, this.valueFormat || DEFAULT_FORMAT[this.type]);
          }
        });
      } else if (value instanceof Date) {
        time = value;
      } else {
        time = value === '' ? undefined : parseToDate(value, this.valueFormat || DEFAULT_FORMAT[this.type]);
      }
      return time;
    }
  }
};
</script>
