<template>
<div class="relative">
  <div class="w-32 px-1 border border-neutral-500 cursor-pointer" @click="openTimeSelect = !openTimeSelect" :id="size">
    <div v-if="totalSeconds === 0" class="text-center">
      <p>0</p>
    </div>
    <div v-else class="flex justify-center items-center gap-1">
      <p>{{ days }}d</p>
      <p>{{ hours }}h</p>
      <p>{{ minutes }}m</p>
      <p>{{ seconds }}s</p>
    </div>
  </div>
  <div class="duration-container absolute left-0 top-full translate-y-2" v-show="openTimeSelect" v-closable="{id: size, handler: onClose}">
    <div class="duration-box" v-for="(unit, index) in inputTypes" :key="unit">
      <input
        type="text"
        class="duration duration-val"
        :data-index="index"
        :data-tunit="unit"
        :data-max="tUnits[unit].max"
        :data-min="tUnits[unit].min"
        :maxlength="tUnits[unit].dsp === 'd' ? 3 : 2"
        :value="tUnits[unit].val.toString().padStart(2, '0')"
        @focus="onFocus"
        @blur="onBlur"
        @keyup="onKeyUp"
      />
      <label class="duration">{{ tUnits[unit].dsp }}</label>
    </div>
  </div>
</div>
</template>

<script>
export default {
  props: {
    max: {
      type: Number,
      default: 0,
      required: true,
      validator(value) {
        return value >= 0;
      },
    },
    min: {
      type: Number,
      default: 0,
      required: true,
      validator(value) {
        return value >= 0;
      },
    },
    updateMax: {
      type: Number,
      required: false,
      validator(value) {
        return value >= 0;
      },
    },
    size: {
      type: String,
      default: false,
      required: true,
    },
  },
  data() {
    return {
      display: 'dhms',
      seconds: 0,
      minutes: 0,
      hours: 0,
      days: 0,
      maxDays: 0,
      minDays: 0,
      totalSeconds: 0,
      maxTotal: null,
      minTotal: null,
      inputTypes: [],
      lastInput: null,
      openTimeSelect: false,
    };
  },
  computed: {
    tUnits: {
      get() {
        return {
          s: { dsp: 's', inc: 1, val: this.seconds, max: 59, rate: 1, min: 0 },
          m: { dsp: 'm', inc: 1, val: this.minutes, max: 59, rate: 60, min: 0 },
          h: { dsp: 'h', inc: 1, val: this.hours, max: 23, rate: 3600, min: 0 },
          d: { dsp: 'd', inc: 1, val: this.days, max: this.maxDays, rate: 86400, min: this.minDays }
        };
      },
      set(newValues) {
        // 大於最大值時要等於最大值
        for (const unit in newValues) {
          this[unit] = newValues[unit].val;
          const input = document.querySelector(`[data-tunit="${unit}"]`);
          if (input) {
            input.value = newValues[unit].val.toString().padStart(2, '0');
          }
        }
      },
    },
  },
  watch: {
    max: {
      handler: function(newValue, oldValue) {
        this.maxTotal = newValue;
        this.size === 'max' && newValue !== oldValue ? this.createData() : null;
      },
      immediate: true,
    },
    min: {
      handler: function(newValue, oldValue) {
        this.minTotal = newValue;
        this.size === 'min' && newValue !== oldValue ? this.createData() : null;
      },
      immediate: true,
    },
    // min 的最大值要等於 max 的總秒數
    updateMax: {
      handler: function(newValue, oldValue) {
        this.maxTotal = newValue;
        this.calculateTotalSeconds();
      },
    },
  },
  methods: {
    onClose () {
    this.openTimeSelect = false;
    },
    /**
     * get focus element
     * @param {event} event
     */
    onFocus(event) {
      this.lastInput = event.target;
      this.lastInput.select(); // 當呼叫該方法時，文本框內的文字會被自動選中，這樣使用者可以方便地進行複製或刪除等操作。
    },
    /**
     * when blur update input value and show number
     * @param {event} event
     */
    onBlur(event) {
      let baseInputValue = event.target.value;
      // 讓前綴數字自動補 0
      isNaN(event.target.value) ?
      event.target.value = '00' :
      event.target.value = event.target.value.toString().padStart(2, '0');

      // 手 key 數值大於最大值時，要等於最大值
      // 先將字串轉為數字才能比大小
      const inputValue = parseInt(event.target.value, 10);
      const max = parseInt(event.target.dataset.max, 10); // 設定最大值
      const min = parseInt(event.target.dataset.min, 10);
      if(inputValue > max) {
        event.target.value = max.toString().padStart(2, '0');
      }else if(inputValue < min) event.target.value= min.toString().padStart(2, '0');

      // 數值更新, tUnits 也更新, 並計算 totalSeconds
      const dsp = event.target.dataset.tunit;
      this.tUnits[dsp].val = event.target.value;
      switch (dsp) {
        case 'd':
          this.days = baseInputValue;
          break;
        case 'h':
          this.hours = event.target.value;
          break;
        case 'm':
          this.minutes = event.target.value;
          break;
        case 's':
          this.seconds = event.target.value;
          break;
      };

      this.calculateTotalSeconds();
    },
    /**
     * 上下箭頭時的行為
     * @param {event} event
     */
    onKeyUp(event) {
      event.target.value = event.target.value.replace(/\D/g, '');

      if (event.keyCode === 38 || event.keyCode === 40) {
        this.actionUpDown(event.target, event.keyCode === 38, true);
      };
    },
    /**
     * 上下箭頭時的行為
     * @param {element} input
     * @param {number} goUp
     * @param {boolean} selectIt
     */
    actionUpDown(input, goUp, selectIt = false) {
      const tUnit = input.dataset.tunit;
      let newVal = parseInt(input.value, 10);
      newVal = isNaN(newVal) ? 0 : newVal;

      // if (newVal <= 0 || newVal > this.tUnits[tUnit].max) {
      //   if (newVal === 0 || (newVal < 0 && input.dataset.index < 1)) {
      //     newVal = '00';
      //   } else if (input.dataset.index >= 1) {
      //     const nextUnit = document.querySelector(`input[data-index="${parseInt(input.dataset.index) - 1}"]`);
      //     let nextUnitVal = parseInt(nextUnit.value);

      //     if (newVal < 0 && nextUnitVal > 0) {
      //       nextUnit.value = nextUnitVal - 1;
      //       nextUnit.dispatchEvent(new Event('blur'));
      //       newVal = this.tUnits[tUnit].max;
      //     } else if (newVal > 0) {
      //       nextUnit.value = nextUnitVal + 1;
      //       nextUnit.dispatchEvent(new Event('blur'));
      //       newVal = '00';
      //     } else {
      //       newVal = '00';
      //     }
      //   }
      // }

      if(goUp) {
        // 箭頭向上，數字加一
        newVal += this.tUnits[tUnit].inc;
        if(newVal > this.tUnits[tUnit].max) {
          // 超過該單位最大值時要進位為零
          newVal = newVal % (this.tUnits[tUnit].max + 1);
          // 前一個更大的單位要進位
          if(input.dataset.index > 0) {
            const prevUnit = document.querySelector(`input[data-index="${parseInt(input.dataset.index) - 1}"]`);
            this.actionUpDown(prevUnit, true);
          }
        }
      } else {
        // 箭頭向下，數字減一
        newVal -= this.tUnits[tUnit].inc;
        if (newVal < 0) {
          // 小於零要調整為該單位最大值，但下一個單位不動
          newVal = (this.tUnits[tUnit].max + 1) - this.tUnits[tUnit].inc;
        }
      }

      input.value = newVal.toString().padStart(2, '0');
      switch (tUnit) {
        case 'd':
          this.days = input.value;
          break;
        case 'h':
          this.hours = input.value;
          break;
        case 'm':
          this.minutes = input.value;
          break;
        case 's':
          this.seconds = input.value;
          break;
      };
      if (selectIt) input.select();
      this.calculateTotalSeconds();
    },
    /**
     * 設定 dhms 的數值
     * @param {number} totalSeconds
     * @param {string} size
     */
    secondToDate(totalSeconds, size) {
      totalSeconds = parseInt(totalSeconds);
      if(!isNaN(totalSeconds)) {
        this.seconds = totalSeconds % 60;
        this.minutes = (Math.floor(totalSeconds - this.seconds) / 60) % 60;
        this.hours = (Math.floor(totalSeconds / 3600)) % 24;
        this.days = Math.floor(totalSeconds / (3600 * 24));

        if(size === 'max') this.maxDays = Math.floor(totalSeconds / (3600 * 24));
        else if(size === 'min') this.minDays = Math.floor(totalSeconds / (3600 * 24));
      };
    },
    /**
     * 計算總秒數
     */
    calculateTotalSeconds() {
      let totalSeconds = 0;

      for (const unit in this.tUnits) {
        const val = parseInt(this.tUnits[unit].val, 10);
        if (!isNaN(val)) {
          totalSeconds += val * this.tUnits[unit].rate;
        }
      }

      if(totalSeconds >= this.maxTotal){ // 大於最大值時要等於最大值
        totalSeconds = this.maxTotal;
        this.secondToDate(this.maxTotal, 'max');
        this.totalSeconds = totalSeconds;
      } else if (totalSeconds <= this.minTotal) { // 小於最小值時要等於最小值
        totalSeconds = this.minTotal;
        this.secondToDate(this.minTotal, 'min');
        this.totalSeconds = totalSeconds;
      } else {
        this.totalSeconds = totalSeconds;
      };
      this.$emit('total-seconds', totalSeconds);
    },
    /**
     * 初始化
     */
    async createData() {
      let size = this.size;
      if (this.maxTotal !== await null && this.minTotal !== await null) {
        switch (size) {
          case 'max':
            this.secondToDate(this.minTotal, 'min');
            this.secondToDate(this.maxTotal, 'max');
            this.totalSeconds =  this.maxTotal;
            break;
          case 'min':
            this.secondToDate(this.maxTotal, 'max');
            this.secondToDate(this.minTotal, 'min');
            this.totalSeconds =  this.minTotal;
            break;
          default:
            break;
        }
        // this.$emit('total-seconds', this.totalSeconds);
      }
    },
  },
  mounted() {
    this.inputTypes = this.display.split('');
  },
  directives: {
    'closable': {
      mounted(el, {value}) {
        let handleOutsideClick = function(e) {
          let target = e.target;
          while (target && target.id !== value.id) {
            target = target.parentElement;
          };
          const isClickOutside = target?.id !== value.id && !el.contains(e.target)
          if (isClickOutside) value.handler();
          e.stopPropagation();
        }
        document.addEventListener('click', handleOutsideClick);
        return () => {
          document.removeEventListener('click', handleOutsideClick);
        };
      },
    }
  },

};
</script>
<style scoped>
.duration-container {
  margin: 4px;
  border-radius: 4px;
  background: var(--10, #FFF);
  box-shadow: 0px 0px 4px 0px rgba(0, 0, 0, 0.25);
  height: 36px;
  width: 221px;
}
.duration-box {
    float:left;
    overflow: auto;
    height: var(--main-input-height);
    padding: 4px;
}
.duration-box > .duration {
    border: 1px solid var(--main-bg-light);
    border-right: 0;
    border-left: 0;
    background-color:transparent;
    color: var(--main-bg-light);
}
.duration-box > .duration:nth-child(1) {
    border-left: 1px solid var(--main-bg-light);
    border-top-left-radius: var(--main-input-br);
    border-bottom-left-radius: var(--main-input-br);
}
.duration-box > .duration:nth-last-child(1) {
    border-right: 1px solid var(--main-bg-light);
    border-top-right-radius: var(--main-input-br);
    border-bottom-right-radius: var(--main-input-br);
}
.duration {
    float:left;
    display: block;
    overflow: auto;
    height: var(--main-input-height);
    outline: none;
    font-size: 14px;
    margin: 0px 2px;
}
.duration-box > label.duration {
    line-height: 28px;
    width: 12px;
    overflow: hidden;
}
.duration-box > input[type="text"].duration {
    text-align: right;
    width: 26px;
    padding: 3px 2px 0px 0px;
}
.duration-box > input[type="button"].duration {
    width: 60px;
    cursor: pointer;
}
</style>
