<template>
  <transition
    name="el-zoom-in-top"
    @before-enter="handleMenuEnter"
    @after-leave="$emit('dodestroy')"
  >
    <div
      ref="popper"
      v-show="visible"
      :style="{ width: width + 'px' }"
      :class="popperClass"
      class="el-picker-panel time-select el-popper"
    >
      <el-scrollbar noresize wrap-class="el-picker-panel__content">
        <div
          class="time-select-item"
          v-for="item in items"
          :class="{
            selected: value === item.value,
            disabled: item.disabled,
            default: item.value === defaultValue,
          }"
          :disabled="item.disabled"
          :key="item.value"
          @click="handleClick(item)"
        >
          {{ item.value }}
        </div>
      </el-scrollbar>
    </div>
  </transition>
</template>

<script type="text/babel">
/* eslint-disable */
import ElScrollbar from "element-ui/packages/scrollbar";
import scrollIntoView from "element-ui/src/utils/scroll-into-view";

const parseTime = function (time) {
  const values = (time || "").split(":");
  if (values.length >= 2) {
    const hours = parseInt(values[0], 10);
    const minutes = parseInt(values[1], 10);

    return {
      hours,
      minutes,
    };
  }
  /* istanbul ignore next */
  return null;
};

const compareTime = function (time1, time2) {
  const value1 = parseTime(time1);
  const value2 = parseTime(time2);

  const minutes1 = value1.minutes + value1.hours * 60;
  const minutes2 = value2.minutes + value2.hours * 60;

  if (minutes1 === minutes2) {
    return 0;
  }

  return minutes1 > minutes2 ? 1 : -1;
};

const formatTime = function (time) {
  return (
    (time.hours < 10 ? "0" + time.hours : time.hours) +
    ":" +
    (time.minutes < 10 ? "0" + time.minutes : time.minutes)
  );
};

const nextTime = function (time, step) {
  const timeValue = parseTime(time);
  const stepValue = parseTime(step);

  const next = {
    hours: timeValue.hours,
    minutes: timeValue.minutes,
  };

  next.minutes += stepValue.minutes;
  next.hours += stepValue.hours;

  next.hours += Math.floor(next.minutes / 60);
  next.minutes = next.minutes % 60;

  return formatTime(next);
};

export default {
  components: { ElScrollbar },

  watch: {
    value(val) {
      if (!val) return;
      this.$nextTick(() => this.scrollToOption());
    },
  },

  methods: {
    handleClick(item) {
      if (!item.disabled) {
        this.$emit("pick", item.value);
      }
    },

    handleClear() {
      this.$emit("pick", null);
    },

    scrollToOption(selector = ".selected") {
      const menu = this.$refs.popper.querySelector(".el-picker-panel__content");
      scrollIntoView(menu, menu.querySelector(selector));
    },

    handleMenuEnter() {
      const selected =
        this.items.map((item) => item.value).indexOf(this.value) !== -1;
      const hasDefault =
        this.items.map((item) => item.value).indexOf(this.defaultValue) !== -1;
      const option =
        (selected && ".selected") ||
        (hasDefault && ".default") ||
        ".time-select-item:not(.disabled)";
      this.$nextTick(() => this.scrollToOption(option));
    },

    scrollDown(step) {
      const items = this.items;
      const length = items.length;
      let total = items.length;
      let index = items.map((item) => item.value).indexOf(this.value);
      while (total--) {
        index = (index + step + length) % length;
        if (!items[index].disabled) {
          this.$emit("pick", items[index].value, true);
          return;
        }
      }
    },

    isValidValue(date) {
      return (
        this.items
          .filter((item) => !item.disabled)
          .map((item) => item.value)
          .indexOf(date) !== -1
      );
    },

    handleKeydown(event) {
      const keyCode = event.keyCode;
      if (keyCode === 38 || keyCode === 40) {
        const mapping = { 40: 1, 38: -1 };
        const offset = mapping[keyCode.toString()];
        this.scrollDown(offset);
        event.stopPropagation();
        return;
      }
    },
  },

  data() {
    return {
      popperClass: "",
      start: "09:00",
      end: "18:00",
      step: "00:30",
      value: "",
      defaultValue: "",
      visible: false,
      minTime: "",
      maxTime: "",
      width: 0,
    };
  },

  computed: {
    items() {
      const start = this.start;
      const end = this.end;
      const step = this.step;

      const result = [];

      if (start && end && step) {
        let current = start;
        while (compareTime(current, end) <= 0) {
          result.push({
            value: current,
            disabled:
              compareTime(current, this.minTime || "-1:-1") <= 0 ||
              compareTime(current, this.maxTime || "100:100") >= 0,
          });
          current = nextTime(current, step);
        }
      }

      return result;
    },
  },
};
</script>
