<template>
  <el-popper :popup-style="popupStyle" :visible="isShow" placement="bottom-left" :auto-width="true" class="fbg-date" @click="handleClickBox">
    <fbg-input :value="text" readonly @click="handleChangeDownUp" :placeholder="placeholder" @clear="handleClear">
      <template v-if="$scopedSlots.selection">
        <slot slot="selection" name="selection" />
      </template>
      <i v-else class="fbg-icon-date" slot="prepend" />
    </fbg-input>
    <div slot="popup"  :style="{width: isRange? '550px': '265px'}" @click="handleClickBox">
      <div v-if="isRange"> 
        <fbg-date-time 
        :visible="isShow" 
        ref="startDate" 
        v-bind="$attrs" 
        com-type="start" 
        :value="value" 
        :type="type" 
        :value-format="valueFormat" 
        :default-value="startDate" 
        :select-date="selectDate" 
        :choose-date="chooseDate" 
        :isShow.sync="isShow" 
        :showRightButton="false" 
        @onClick="handleTimePickClick"
        @changeShowDate="handleChangeStartDateShowDate"/>
        <div class="fbg-date-split-line"></div>
        <fbg-date-time 
        :visible="isShow" 
        ref="endDate" 
        v-bind="$attrs" 
        com-type="end" 
        :value="value" 
        :type="type" 
        :value-format="valueFormat" 
        :default-value="endDate" 
        :select-date="selectDate" 
        :choose-date="chooseDate" 
        :isShow.sync="isShow" 
        :showLeftButton="false"  
        @onClick="handleTimePickClick"
        @changeShowDate="handleChangeEndDateShowDate"/>
        <div class="fbg-date-tools">
          <fbg-button @click="handleCancel">取消</fbg-button><fbg-button style="margin-left: 10px;" type="primary" :disabled="confirmDisabled" @click="handleConfirm">确定</fbg-button>
        </div>
      </div>
      <template v-else>
        <div>
          <fbg-date-time 
          :visible="isShow" 
          ref="date" 
          v-bind="$attrs" 
          :value="value" 
          :type="type" 
          :value-format="valueFormat" 
          :default-value="showDate" 
          :isShow.sync="isShow" 
          @onClick="handleTimePickClick"  
          @change="handleChange" 
          @timeChange="handleTimeChange"/>
          <div class="fbg-date-tools" v-if="isDateTime">
            <fbg-button @click="handleCancel" >取消</fbg-button><fbg-button type="primary" style="margin-left: 10px;" :disabled="!text" @click="handleConfirm">确定</fbg-button>
          </div>
        </div>
      </template>
    </div>
  </el-popper>
</template>
<script>
import Input from '../input';
import DateTime from '../dateTime';
import Button from '../button';
import extendData from '../common/datetimeExtend';
import util from '../../utils';
import Popper from '../popper/index.vue';

export default {
  extends: extendData,
  components: {
    'fbg-input': Input,
    'fbg-date-time': DateTime,
    'fbg-button': Button,
    'el-popper': Popper
  },
  props: {
    value: {
      type: [Date, Number, Array, String],
      default() {
        if (this.type === 'daterang' || this.type === 'datetimerange') {
          return [];
        } else {
          return new Date();
        }
      }
    },
    type: {
      type: String,
      default: 'date'
    },
    rangeSeparator: {
      type: String,
      default: ' - '
    },
    placeholder: {
      type: String,
      default: ''
    },
    format: {
      type: String,
      default() {
        return util.getDefaultDateType(this.type);
      } 
    },
    valueFormat: {
      type: String,
      default() {
        return util.getDefaultDateType(this.type);
      }
    }
  },
  data() {
    return {
      popupStyle: '',
      openStatus: false,
      isShow: false,
      text: '',
      selectDate: [],
      chooseDate: [],
      isUpdateCache: true,
      cacheValue: '',
      cacheText: '',
      startDate: new Date(),
      endDate: new Date(),
      showDate: new Date(),
      startTime: {
        hour: 0,
        minute: 0,
        second: 0
      },
      endTime: {
        hour: 0,
        minute: 0,
        second: 0
      },
      date: new Date()
    }
  },
  computed: {
    isDateTime() {
      return this.type === 'datetime' || this.type === 'datetimerange';
    },
    isDateTimePicker() {
      return this.type === 'datetime' && !this.isRange;
    },
    confirmDisabled() {
      return this.chooseDate.length < 2;
    }
  },
  watch: {
    '$slots.selection': {
      immediate: true,
      handler(vnode) {
        if (vnode && vnode.length) {
          this.$nextTick(() => {
            this.popupStyle = `margin-left: ${util.getElWidth(vnode[0].elm)}px;`;
          });
        }
      }
    },
    isShow() {
      if (this.chooseDate.length === 1) {
        this.selectDate = [];
        this.chooseDate = [];
      }
    },
    value: {
      immediate: true,
      handler(value) {
        if (this.isRange) {
          if (value.length === 2) {
            const v1 = this.valueToDateTime(value[0], this.valueFormat);
            const v2 = this.valueToDateTime(value[1], this.valueFormat);
            if (value[0] && value[1]) {
              try {
                const date1 = this.getDateObj(v1);
                const date2 = this.getDateObj(v2);
                if (!(date1 instanceof Date) || !(date2 instanceof Date)) {
                  throw new Error('The value of the date component is not a legal date value');
                  return false;
                }
                if (date1.getTime() > date2.getTime()) {
                  this.startDate = date2;
                } else {
                  this.startDate = date1;          
                }
                let startDate = null;
                let endDate = null;
                if (this.isDateTime) {
                  startDate = this.getDateTimeInfo(date1);
                  endDate = this.getDateTimeInfo(date2);
                } else {
                  startDate = this.getDateInfo(date1);
                  endDate = this.getDateInfo(date2);
                }
                this.text = this.createdText(startDate, endDate);
              } catch(e) {
                console.error(e);
              }
            } else {
              this.init();
            }
          } else {
            this.text = '';
            this.init();
            this.startDate = new Date();
          }
        } else {
          try {
            if (value) {
              const v = this.valueToDateTime(value, this.valueFormat);
              const date = this.getDateObj(v);
              this.showDate = date;
              const dateInfo = this.getDateTimeInfo(date);
              this.text = this.formatDateTime(dateInfo, this.format);
            } else {
              this.showDate = new Date();
              this.text = '';
            }
            if (this.isDateTimePicker) {
              if (this.isUpdateCache) {
                this.updateCache(this.value, this.text);
              }
            }
            this.isUpdateCache = true;
          } catch(e) {
            console.error(e);
          }
        }
      }
    },
    startDate: {
      immediate: true,
      handler(date) {
        if (!this.isDifferenceOneMonth(date, this.endDate)) {
          this.endDate = this.changeMonth(date, 1);
        }
      }
    },
    endDate: {
      immediate: true,
      handler(date) {
        if (!this.isDifferenceOneMonth(this.startDate, date)) {
          this.startDate = this.changeMonth(date, -1);
        }
      }
    }
  },
  created() {
    
  },
  mounted() {
    document.addEventListener('click', () => {
      if (!this.openStatus) {
        if (this.isShow !== false && this.isDateTimePicker) {
          this.useCache();
        }
        this.isShow = false;
      }
      this.openStatus = false;
    });
  },
  methods: { 
    init() {
      this.selectDate = [];
      this.chooseDate = [];
      this.startDate = new Date();
      this.endDate = new Date();
      this.date = new Date();
    },
    changeMonth(date, n = 1) {
      const nDate = new Date(date);
      nDate.setMonth(nDate.getMonth() + n);
      return nDate;
    },
    isDifferenceOneMonth(start, end) {
      let y1 = start.getFullYear();
      let y2 = end.getFullYear();
      let m1 = start.getMonth();
      let m2 = end.getMonth();
      if (y1 === y2) {
        const s = m2 - m1;
        if (s === 1) {
          return true;
        } else {
          return false;
        }
      } else if (y2 - y1 === 1) {
        if (m1 === 11 && m2 === 0) {
          return true;
        } else {
          return false;
        }
      }
      return false;
    },
    mergeDateTimeVsFormat(value, timeObj, format) {
      let date = this.getDateObj(value);
      date = this.setTimeContent(date, timeObj);
      value = this.formatDateTime(this.getDateTimeInfo(date), format);
      return value;
    },
    updateCache(value, text) {
      this.cacheValue = value;
      this.cacheText = text;
    },
    useCache() {
      this.$emit('input', this.cacheValue);
      this.text = this.cacheText;
    },
    handleChangeDownUp() {
      this.openStatus = true;
      this.isShow = !this.isShow;
    },
    handleTimePickClick() {
      this.openStatus = true;
    },
    handleTimeChange(obj) {
      if (this.value) {
        const v = this.valueToDateTime(this.value, this.valueFormat);
        const value = this.mergeDateTimeVsFormat(v, obj, this.valueFormat);
        const text = this.mergeDateTimeVsFormat(v, obj, this.format);
        this.isUpdateCache = false;
        this.$emit('input', value);
        this.$emit('change', value);
        this.text = text;
      }
    },
    handleChange(data) {
      const text = this.formatDateTime(data, this.format);
      const value = this.mergeDateTimeVsFormat(data.stampTime, this.$refs.date.timeValue, this.valueFormat);
      this.isUpdateCache = false;
      this.$emit('input', value);
      this.$emit('change', value);
      this.text = text;
      if (!this.isDateTime) {
        this.isShow = false;
      }
    },
    // 防止点击popup-box隐藏弹出窗口问题
    handleClickBox() {
      this.openStatus = true;
    },
    handleChangeStartDateShowDate(date) {
      this.startDate = date;
    },
    handleChangeEndDateShowDate(date) {
      this.endDate = date;
    },
    handleConfirm() {
      try {
        if (this.isRange) {
          if (this.chooseDate.length === 2) {
            let startDate = this.chooseDate[0];
            let endDate = this.chooseDate[1];
            if (startDate.stampTime > endDate.stampTime) {
              startDate = this.chooseDate[1];
              endDate = this.chooseDate[0];
            }
            if (this.isDateTime) {
              startDate.date = this.setTimeContent(startDate.date, this.$refs.startDate.timeValue);
              endDate.date = this.setTimeContent(endDate.date, this.$refs.endDate.timeValue);
              startDate = this.getDateTimeInfo(startDate.date);
              endDate = this.getDateTimeInfo(endDate.date);
            }
            this.text = this.createdText(startDate, endDate);
            const value = [this.transformValue(this.value[0], startDate, this.valueFormat), this.transformValue(this.value[1], endDate, this.valueFormat)];
            this.$emit('input', value);
            this.$emit('change', value);
            this.$emit('confirm', value);
            this.isShow = false;
          }
        } else if (this.isDateTimePicker) {
          this.updateCache(this.value, this.text);
          this.$emit('confirm', this.value);
          this.isShow = false;
        }

      } catch(e) {
        throw new Error(e);
      }

    },
    handleCancel() {
      this.isShow = false;
      if (this.isDateTimePicker) {
        this.useCache();
      }
    },
    handleClear() {
      this.init();
      if (this.isRange) {
        this.$emit('input', []);
        this.$emit('change', []);
      } else {
        this.$emit('input', '');
        this.$emit('change', '');
      }
    },
    createdText(startDate, endDate) {
        const formatStartDate = this.formatDateTime(startDate, this.format);
        const formatEndDate = this.formatDateTime(endDate, this.format);
        return formatStartDate + this.rangeSeparator + formatEndDate;
    }
  }
}
</script>
<style lang="scss" scoped>

.fbg {
  &-date {
    position: relative;
    &-split-line {
      width: 1px;
      display: inline-block;
      position: relative;
      height: 230px;
      vertical-align: top;
      margin-top: 30px;
      background-color: #ddd;
      &:after {
        content: 'to';
        color: #999;
        background-color: #fff;
        top: 50%;
        margin-top: -15px;
        position: absolute;
        left: -5px;
      }
    }
    &-tools {
      padding: 10px 0px;
      text-align: center;
    }
    &-box {
      position: absolute;
      top: 100%;
      left: 0px;
      z-index: 99999;
      transition: all 0.2s ease-in-out;
      box-shadow: 0px 0px 5px $themeShadowColor;
      background-color: #fff;
    }
    
    &-box.open {
      visibility: visible;
      max-height: 500px;
      animation: overflowAnimation 0.3s;
    }
    &-box.hide {
      visibility: hidden;
      max-height: 0px;
      overflow: hidden;
    }
  }
}
</style>