export default class WsMultipleInputController {
  static $inject = ['$window', '$timeout'];

  KEY_CODES = {
    BACK_SPACE: 8,
    NINE: 57,
    NINE_NUM_PAD: 105,
    NUM_LOCK: 144,
    SPACE: 32,
    TAB: 9,
    ZERO: 48,
    ZERO_NUM_PAD: 96,
  };

  constructor($window, $timeout) {
    this.$window = $window;
    this.$timeout = $timeout;
  }

  $onInit() {
    this.inputCount = parseInt(this.numberOfInputs, 10);
    this.inputs = this.inputs || [];
    this.singleInput = this.value;
    this.singleInputMode = /Mobi/.test(this.$window.navigator.userAgent) || this.forceSingleInput;
  }

  $postLink() {
    this.$timeout(() => {
      if (!this.autoFocus) {
        return;
      }

      if (this.singleInputMode) {
        WsMultipleInputController._focusElement('.ws-multiple-input-single');
      } else {
        WsMultipleInputController._focusElement('.ws-multiple-input');
      }
    }, 0);
  }

  static _focusElement(cssSelector) {
    if (angular.element.find(cssSelector).length) {
      angular.element.find(cssSelector)[0].focus();
    }
  }

  $onChanges(changesObj) {
    if (changesObj.value && angular.isString(changesObj.value.currentValue)) {
      // Update internal representation when value is updated on the parent
      const newInputsValue = changesObj.value.currentValue.split('').map(Number);
      this.inputs = newInputsValue;

      // Focus on next element
      const positionToFocus = newInputsValue.length;
      if (angular.isDefined(angular.element.find('.ws-multiple-input')[positionToFocus])) {
        angular.element.find('.ws-multiple-input')[positionToFocus].focus();
      }
    }
  }

  range = n => new Array(n);

  onKeyPress = ($event) => {
    if (this.isReadonly) {
      return Promise.resolve();
    }

    return this.$timeout(() => {
      // When maximum length is reached for current input, not counting movements
      if ($event.target.value.length === $event.target.maxLength && !($event.key === 'ArrowLeft' || $event.key === 'ArrowRight')) {
        const inputs = this.inputs;
        const populated = inputs.filter(input => (angular.isString(input) && input.length > 0)
                                                 || angular.isNumber(input));
        // If all inputs have been populated, calls onCompleted
        // Otherwise, move to next input
        if (populated.length === this.inputCount) {
          const finalInput = inputs.join('');
          this.onCompleted({ result: finalInput });
        } else if ($event.target.nextElementSibling !== null) {
          $event.target.nextElementSibling.focus();
        }
      }
    }, 25);
  };

  onKeyDown = ($event) => {
    if (this.isReadonly) {
      return;
    }

    // Browsers have a hard time limiting input for <input type="number">
    const isNumberKey = ($event.keyCode >= this.KEY_CODES.ZERO &&
      $event.keyCode <= this.KEY_CODES.NINE) ||
      ($event.keyCode >= this.KEY_CODES.ZERO_NUM_PAD &&
      $event.keyCode <= this.KEY_CODES.NINE_NUM_PAD);

    if (($event.keyCode === this.KEY_CODES.SPACE || !isNumberKey) &&
        $event.keyCode !== this.KEY_CODES.TAB &&
        $event.keyCode !== this.KEY_CODES.BACK_SPACE &&
        !$event.altKey && !$event.ctrlKey && !$event.metaKey) {
      $event.preventDefault();
    }

    // When trying to delete from an empty input, delete from the previous one
    if (($event.target.value.length === 0) && ($event.key === 'Backspace')) {
      if ($event.target.previousElementSibling !== null) {
        $event.preventDefault();
        $event.target.previousElementSibling.focus();
        $event.target.previousElementSibling.value = '';
      }
    }
    if ($event.key === 'ArrowLeft') {
      if ($event.target.previousElementSibling !== null) {
        $event.preventDefault();
        $event.target.previousElementSibling.focus();
      }
    }
    if ($event.key === 'ArrowRight') {
      if ($event.target.nextElementSibling !== null) {
        $event.preventDefault();
        $event.target.nextElementSibling.focus();
      }
    }
  };

  onPaste = ($event) => {
    $event.preventDefault();

    // jQuery's doesn't expose Clipboard API
    const clipboardData = ($event.originalEvent.clipboardData || this.$window.clipboardData);
    const pasteData = clipboardData.getData('Text');

    const splitData = pasteData.slice(0, this.inputCount).split('');
    this.inputs = splitData;

    // Because the paste filled all inputs we fire onCompleted
    if (splitData.length === this.inputCount) {
      this.onCompleted({ result: this.inputs.join('') });
    }
  };

  submit = () => {
    this.onCompleted({ result: this.singleInput });
  };
}
