import MaskedInput, { conformToMask } from 'vue-text-mask'
import inputValidations from '../lib/input_validations'
import { formatDollars } from '../lib/dollars'
import { emitFieldChange } from '../lib/emitters'

export default {
  name: 'textinput',

  components: {
    MaskedInput,
  },

  props: {
    name: String,
    validation: {
      type: String,
      default: () => 'anything',
    },
    initialValue: {
      type: String,
      default: () => '',
    },
    initialErrors: {
      type: Array,
      default: () => [],
    },
    paragraph: String,
    noMaxWidth: String,
    optional: Boolean,
  },

  data: function() {
    return {
      showError: (this.initialErrors && this.initialErrors.length) || false,
      showValid: false,
      mask: inputValidations[this.validation].mask,
      pipe: inputValidations[this.validation].pipe || undefined,
      keepCharPositions:
        inputValidations[this.validation].keepCharPositions || false,
      validationError:
        this.initialErrors.join(' ') ||
        inputValidations[this.validation].validationError,
      value: this.initialValue,
      modified: false,
    }
  },

  computed: {
    rawValue: function() {
      return this._rawValue(this.value)
    },

    valid: function() {
      return this._isValid(this.value)
    },
  },

  mounted: function() {
    if (this.value) {
      this._checkIfValid({
        value: this.value,
        invalidate: true,
        showValidationIcon: false,
      })

      if (this.mask && this.validation !== 'email') {
        const mask =
          typeof this.mask.mask !== 'function'
            ? this.mask
            : mask.mask(this.value).filter(val => val !== '[]')

        this.value = conformToMask(this.value, mask).conformedValue
      }
    }
  },

  methods: {
    // When user types a character
    onInput: function(e) {
      // When we use the native textarea element, we receive an event object
      // When we use the masked-input component, we receive the value directly
      const value = typeof e === 'object' ? e.target.value : e
      this.value = value
      this.modified = true
      this._checkIfValid({ value })
    },

    // When field is blurred (un-focused)
    onChange: function(e) {
      // Only invalidate the field when it blurs
      this._checkIfValid({ value: e.target.value, invalidate: true })
    },

    onBlur: function(e) {
      if (!(this.optional && e.target.value === '')) {
        this._checkIfValid({ value: e.target.value.trim(), invalidate: true })
      } else if (this.modified && !this.optional) {
        this._checkIfValid({ value: e.target.value.trim(), invalidate: true })
      }
      this.value = e.target.value.trim()

      if (this.validation === 'dollars') {
        let value = Number.isNaN(e.target.value) ? '0' : e.target.value
        this.value = formatDollars(this._rawValue(value))
      }
    },

    //
    _checkIfValid: function({
      value,
      invalidate = false,
      showValidationIcon = true,
    }) {
      const valid = this._isValid(value)
      if (this.modified) {
        this.validationError = inputValidations[this.validation].validationError
      }

      // Show error messages or not
      if (valid) {
        this.showError = false
      } else if (invalidate) {
        this.showError = true
      }

      if (showValidationIcon) {
        this.showValid = this.value != '' && valid
      }

      // Emit a change event
      emitFieldChange(this, {
        value: this._rawValue(value),
        name: this.name,
      })
    },

    _rawValue: function(value) {
      return inputValidations[this.validation].unmask.reduce(
        (currentValue, character) => {
          return currentValue.split(character).join('')
        },
        value
      )
    },

    _validate: function(value) {
      return inputValidations[this.validation].match.test(this._rawValue(value))
    },

    _isValid: function(value) {
      let valid = this._validate(value)
      if (!this.modified && this.initialErrors && this.initialErrors.length) {
        valid = false
      } else if (this.optional && value === '') {
        valid = true
      } else if (!this.optional && value === '') {
        valid = false
      }

      return valid
    },
  },
}
