<template>
  <div class="el-input-validation-code">
    <char-input
      v-for="(char, index) in code"
      v-model="code[index]"

      ref="codeInput"
      class="el-input-validation-code__input"

      :key="`validation-code-${index}`"
      :valid-keys="validKeys"
      :inputmode="useNumericKeyboard ? 'numeric' : 'text'"
      :disabled="disabled"

      @paste.native="onPaste"

      @keydown.left.native="changeFocus(index - 1)"
      @previous="changeFocus(index - 1)"
      @keydown.right.native="changeFocus(index + 1)"
      @next="changeFocus(index + 1)"

      @keypress.native="$emit('keypress', $event)"
    />
  </div>
</template>

<script>
import { delay } from 'element-ui/src/utils/util';
import CharInput from './char-input.vue';

const numericKeys = '1234567890'.split('');

export default {
  name: 'ElInputValidationCode',
  props: {
    codeLength: {
      type: Number,
      required: true
    },
    validKeys: {
      type: Array,
      default: () => [...numericKeys]
    },
    value: {
      type: String,
      default: ''
    },
    disabled: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      code: this.value ? this.value.split('') : Array(this.codeLength).fill('')
    };
  },
  computed: {
    useNumericKeyboard() {
      return this.validKeys.every(key => numericKeys.includes(key));
    }
  },
  methods: {
    emitCodeChange() {
      const codeString = this.code.join('');
      this.$emit('input', codeString);
      if (codeString.length === this.codeLength) {
        this.$emit('filled');
      }
    },
    onPaste(evt) {
      if (!evt.clipboardData || !evt.clipboardData.getData) return;
      evt.preventDefault();

      let pastedText = evt.clipboardData.getData('text/plain');
      let pastedCode = pastedText.split('');
      let pastedCodeValid = pastedCode.every(code => this.validKeys.includes(code));

      if (pastedCode.length === this.codeLength && pastedCodeValid) {
        this.code = pastedText.split('');
        this.emitCodeChange();
      }
    },
    async changeFocus(newFocusIndex) {
      if (newFocusIndex < this.codeLength && newFocusIndex >= 0) {
        const el = this.$refs.codeInput[newFocusIndex].$el;
        el.focus();
        await delay(50); // https://bugs.chromium.org/p/chromium/issues/detail?id=32865 (marked fixed, but it isn't)
        el.setSelectionRange(0, this.code[newFocusIndex].length);
      }
    }
  },
  watch: {
    code() {
      this.emitCodeChange();
    }
  },
  components: {
    CharInput
  }
};
</script>
