import AutoNumeric from 'autonumeric/src/main';

CurrencyDirective.$inject = ['autogrowInputService'];

export default function CurrencyDirective(autogrowInputService) {
  const { keyTypeForEventIs, setInputWidth } = autogrowInputService;

  return {
    require: '?ngModel',
    restrict: 'A',
    scope: {
      wsCurrency: '=',
    },
    compile: () => link,
  };

  function link(scope, element, attr, ngModelCtrl) {
    scope.options = scope.wsCurrency || {};

    addWrapper(element, scope);
    addStyling(element, attr);

    const autoNumericInstance = initAutoNumericElement(scope, element);

    if (scope.options.autogrow) {
      initAutogrow(scope, element, autoNumericInstance, attr, ngModelCtrl);
    }

    if (scope.options.clearOnInitialFocus) {
      element.one('focus', () => {
        autoNumericInstance.set('');
      });
    }

    setUpAngularCurrency(scope, element, autoNumericInstance, attr, ngModelCtrl);

    if (ngModelCtrl) {
      ngModelCtrl.$parsers.push(parseFloat);
    }
  }

  function addStyling(element, attr) {
    element.addClass('form-input-text size-sm');

    if (attr.ngDisabled) {
      element.addClass('disabled');
    }
  }

  // Wrap in div with currency symbol
  function addWrapper(element, scope) {
    const symbol = scope.options.symbol || '$';
    const wrapperDiv = angular.element('<div id="currency-wrapper"></div>').addClass('form-input-currency');
    const symbolSpan = angular.element(`<span>${symbol}</span>`).addClass('symbol');

    element.after(wrapperDiv);
    scope.wrapperDiv = wrapperDiv;
    wrapperDiv.prepend(element);
    wrapperDiv.prepend(symbolSpan);
  }

  function clampInputValue(scope, _value) {
    const value = isNaN(_value) ? 0 : _value;

    return Math.min(
      Math.max(value, scope.autoNumericOptions.minimumValue || -Infinity),
      scope.autoNumericOptions.maximumValue || Infinity,
    );
  }

  function initAutoNumericElement(scope, element) {
    scope.autoNumericOptions = scope.options.integer ?
      { decimalPlaces: 0 } :
      { decimalPlaces: 2, roundingMethod: 'D' };
    scope.autoNumericOptions.modifyValueOnWheel = false;

    if (!isNaN(scope.options.min)) {
      scope.autoNumericOptions.minimumValue = scope.options.min;
    }
    if (!isNaN(scope.options.max)) {
      scope.autoNumericOptions.maximumValue = scope.options.max;
    }

    element.value = clampInputValue(scope, element.value);
    return new AutoNumeric(element[0], scope.autoNumericOptions)
      .set(element.value);
  }

  /* angular-currency v1.0.6
    * (c) 2015-2016 Brandon Krueger <brandon.c.krueger@gmail.com>
    * License: MIT
    * https://github.com/BuffCoder/angular-currency
    */
  function setUpAngularCurrency(scope, element, autoNumericInstance, attr, ngModelCtrl) {
    if (!element.is('input:text')) { return; }

    const updateElement = (newVal) => {
      const clampedValue = clampInputValue(scope, newVal);
      if (isFinite(clampedValue)) {
        autoNumericInstance.set(clampedValue);
      }
    };

    const updateViewValue = () => {
      scope.$applyAsync(() => {
        ngModelCtrl.$setViewValue(autoNumericInstance.get());
      });
    };

    if (ngModelCtrl) {
      scope.$watch(attr.ngModel, () => {
        ngModelCtrl.$render();
      });

      ngModelCtrl.$render = () => {
        updateElement(ngModelCtrl.$viewValue);
      };

      element.on('keyup', updateViewValue);
      element.on('change', updateViewValue);
    } else {
      attr.$observe('value', updateElement);
    }
  }

  function initAutogrow(scope, element, autoNumericInstance, attr, ngModelCtrl) {
    scope.wrapperDiv.addClass('autogrow');

    if (!scope.options.integer && scope.options.autogrow) {
      throw new Error('Decimal and Autogrow options are not currently compatible');
    }

    if (ngModelCtrl) {
      scope.$watch(() => ngModelCtrl.$modelValue, () => {
        const inputValue = autoNumericInstance.getFormatted();
        setInputWidth(inputValue, element);
      });
    }

    element.on('keydown', (e) => {
      if (keyTypeForEventIs('backspace', e) || keyTypeForEventIs('number', e)) {
        setInputWidth(autoNumericInstance.getFormatted(), element);
      }
    });
  }
}
