<template>
  <div
    class="vux-x-input weui_cell"
    :class="{'weui_cell_warn': !valid}"
  >
    <div class="weui_cell_hd">
      <div
        v-if="hasRestrictedLabel"
        :style="labelStyles"
      >
        <slot name="restricted-label" />
      </div>
      <slot name="label">
        <label
          v-if="title"
          class="weui_label"
          :style="{ textAlign: $parent.labelAlign, marginRight: $parent.labelMarginRight}"
        >
          {{ title }}
        </label>
        <inline-desc v-if="inlineDesc">
          {{ inlineDesc }}
        </inline-desc>
      </slot>
    </div>
    <div class="weui_cell_bd weui_cell_primary">
      <input
        v-if="!type || type === 'text'"
        ref="input"
        v-model="currentValue"
        class="weui_input"
        :maxlength="max"
        :autocomplete="autocomplete"
        :autocapitalize="autocapitalize"
        :autocorrect="autocorrect"
        :spellcheck="spellcheck"
        :style="inputStyle"
        type="text"
        :name="name"
        :pattern="pattern"
        :placeholder="placeholder"
        :readonly="readonly"
        :disabled="disabled"
        @focus="focusHandler"
        @blur="blur"
      >
      <input
        v-if="type === 'number'"
        ref="input"
        v-model="currentValue"
        class="weui_input"
        :maxlength="max"
        :autocomplete="autocomplete"
        :autocapitalize="autocapitalize"
        :autocorrect="autocorrect"
        :spellcheck="spellcheck"
        :style="inputStyle"
        type="number"
        :name="name"
        :pattern="pattern"
        :placeholder="placeholder"
        :readonly="readonly"
        :disabled="disabled"
        @focus="focusHandler"
        @blur="blur"
      >
      <input
        v-if="type === 'email'"
        ref="input"
        v-model="currentValue"
        class="weui_input"
        :maxlength="max"
        :autocomplete="autocomplete"
        :autocapitalize="autocapitalize"
        :autocorrect="autocorrect"
        :spellcheck="spellcheck"
        :style="inputStyle"
        type="email"
        :name="name"
        :pattern="pattern"
        :placeholder="placeholder"
        :readonly="readonly"
        :disabled="disabled"
        @focus="focusHandler"
        @blur="blur"
      >
      <input
        v-if="type === 'password'"
        ref="input"
        v-model="currentValue"
        class="weui_input"
        :maxlength="max"
        :autocomplete="autocomplete"
        :autocapitalize="autocapitalize"
        :autocorrect="autocorrect"
        :spellcheck="spellcheck"
        :style="inputStyle"
        type="password"
        :name="name"
        :pattern="pattern"
        :placeholder="placeholder"
        :readonly="readonly"
        :disabled="disabled"
        @focus="focusHandler"
        @blur="blur"
      >
      <input
        v-if="type === 'tel'"
        ref="input"
        v-model="currentValue"
        class="weui_input"
        :maxlength="max"
        :autocomplete="autocomplete"
        :autocapitalize="autocapitalize"
        :autocorrect="autocorrect"
        :spellcheck="spellcheck"
        :style="inputStyle"
        type="tel"
        :name="name"
        :pattern="pattern"
        :placeholder="placeholder"
        :readonly="readonly"
        :disabled="disabled"
        @focus="focusHandler"
        @blur="blur"
      >
    </div>
    <div
      class="weui_cell_ft"
      :class="{'with_arrow': isLink}"
    >
      <icon
        v-show="isFocus && !equalWith && showClear && currentValue && !readonly && !disabled"
        type="clear"
        @click.native="clear"
      />

      <icon
        v-show="!novalidate && !equalWith && ((touched && !valid && firstError) || (forceShowError && !valid && firstError))"
        class="vux-input-icon"
        type="warn"
        :title="!valid ? firstError : ''"
      />
      <icon
        v-if="!novalidate && hasLengthEqual && dirty && equalWith && !valid"
        class="vux-input-icon"
        type="warn"
      />
      <icon
        v-show="!novalidate && equalWith && equalWith === currentValue && valid"
        type="success"
      />

      <icon
        v-show="novalidate && iconType === 'success'"
        type="success"
        class="vux-input-icon"
      />
      <icon
        v-show="novalidate && iconType === 'error'"
        type="warn"
        class="vux-input-icon"
      />

      <slot name="right" />
    </div>
  </div>
</template>

<script>
import Base from '../../libs/base'
import Icon from '../icon'
import InlineDesc from '../inline-desc'
import isEmail from 'validator/lib/isEmail'
import isMobilePhone from 'validator/lib/isMobilePhone'
import Debounce from '../../tools/debounce'
const validators = {
  'email': {
    fn: isEmail,
    msg: '邮箱格式'
  },
  'china-mobile': {
    fn (str) {
      return isMobilePhone(str, 'zh-CN')
    },
    msg: '手机号码'
  },
  'china-name': {
    fn (str) {
      return str.length >= 2 && str.length <= 6
    },
    msg: '中文姓名'
  }
}
export default {
  components: {
    Icon,
    InlineDesc
  },
  mixins: [Base],
  props: {
    required: {
      type: Boolean,
      default: false
    },
    title: {
      type: String,
      default: ''
    },
    type: {
      type: String,
      default: 'text'
    },
    placeholder: String,
    value: [String, Number],
    name: String,
    readonly: Boolean,
    disabled: Boolean,
    isLink: Boolean,
    keyboard: String,
    inlineDesc: String,
    isType: [String, Function],
    min: Number,
    max: Number,
    showClear: {
      type: Boolean,
      default: true
    },
    equalWith: String,
    textAlign: String,
    // https://github.com/yisibl/blog/issues/3
    autocomplete: {
      type: String,
      default: 'off'
    },
    autocapitalize: {
      type: String,
      default: 'off'
    },
    autocorrect: {
      type: String,
      default: 'off'
    },
    spellcheck: {
      type: String,
      default: 'false'
    },
    novalidate: {
      type: Boolean,
      default: false
    },
    iconType: String,
    debounce: Number
  },
  data () {
    let data = {
      hasRestrictedLabel: false,
      firstError: '',
      forceShowError: false,
      hasLengthEqual: false,
      valid: true,
      currentValue: '',
      isFocus: false,
      timeId: '' // 清除icon的时间id
    }
    return data
  },
  computed: {
    labelStyles () {
      return {
        width: this.$parent.labelWidth || (this.labelWidth + 'em'),
        textAlign: this.$parent.labelAlign,
        marginRight: this.$parent.labelMarginRight
      }
    },
    pattern () {
      if (this.keyboard === 'number' || this.isType === 'china-mobile') {
        return '[0-9]*'
      }
      return null
    },
    labelWidth () {
      return this.title.replace(/[^x00-xff]/g, '00').length / 2 + 1
    },
    hasErrors () {
      return Object.keys(this.errors).length > 0
    },
    inputStyle () {
      if (this.textAlign) {
        return {
          textAlign: this.textAlign
        }
      }
      return null
    }
  },
  watch: {
    valid (val) {
      // if (!val) {
      //   this.getError()
      // }
    },
    value (val) {
      this.currentValue = val
    },
    equalWith (newVal) {
      if (newVal && this.equalWith) {
        if (newVal.length === this.equalWith.length) {
          this.hasLengthEqual = true
        }
        this.validateEqual()
      } else {
        this.validate()
      }
    },
    currentValue (newVal) {
      if (newVal) {
        this.isFocus = true
      }
      if (!this.equalWith && newVal) {
        this.validateEqual()
      }
      if (newVal && this.equalWith) {
        if (newVal.length === this.equalWith.length) {
          this.hasLengthEqual = true
        }
        this.validateEqual()
      } else {
        this.validate()
        this.getError()
      }
      this.$emit('input', newVal)
      if (this._debounce) {
        this._debounce()
      } else {
        this.$emit('on-change', newVal)
      }
    }
  },
  created () {
    this.currentValue = this.value || ''
    if (!this.title && !this.placeholder && !this.currentValue) {
      console.warn('no title and no placeholder?')
    }
    if (this.required && !this.currentValue) {
      this.valid = false
      this.validate()
    }
    this.handleChangeEvent = true
    if (this.debounce) {
      this._debounce = Debounce(() => {
        this.$emit('on-change', this.currentValue)
      }, this.debounce)
    }
  },
  mounted () {
    if (this.$slots && this.$slots['restricted-label']) {
      this.hasRestrictedLabel = true
    }
  },
  beforeDestroy () {
    if (this._debounce) {
      this._debounce.cancel()
    }
  },
  destroyed() {
    clearTimeout(this.timeId)
  },
  methods: {
    clear () {
      this.currentValue = ''
      this.focus()
      this.$emit('on-click-clear-icon')
    },
    focus () {
      this.$refs.input.focus()
    },
    focusHandler () {
      this.isFocus = true
      this.$emit('on-focus', this.currentValue)
    },
    blur () {
      this.timeId = setTimeout(() => {
        this.isFocus = false
        this.setTouched()
      }, 100)
      this.validate()
      this.$emit('on-blur', this.currentValue)
    },
    getError () {
      let key = Object.keys(this.errors)[0]
      this.firstError = this.errors[key]
      this.$emit('on-vali', this.errors, this.valid, this.uuid)
    },
    validate () {
      if (typeof this.equalWith !== 'undefined') {
        this.validateEqual()
        this.getError()
        return
      }
      this.errors = {}
      if (!this.currentValue && !this.required) {
        this.valid = true
        this.getError()
        return
      }
      if (!this.currentValue && this.required) {
        this.valid = false
        this.errors.required = this.title + '必填'
        this.getError()
        return
      }

      if (typeof this.isType === 'string') {
        const validator = validators[this.isType]
        if (validator) {
          this.valid = validator[ 'fn' ](this.currentValue)
          if (!this.valid) {
            this.errors.format = validator[ 'msg' ] + '格式不对哦~'
            this.getError()
            return
          } else {
            delete this.errors.format
            this.getError()
          }
        }
      }
      if (typeof this.isType === 'function') {
        const validStatus = this.isType(this.currentValue, this.name)
        this.valid = validStatus.valid
        if (!this.valid) {
          this.errors.format = validStatus.msg
          this.forceShowError = true
          this.getError()
          // if (!this.firstError) {
          //   this.getError()
          // }
          return
        } else {
          delete this.errors.format
          this.getError()
        }
      }
      if (this.min) {
        if (this.currentValue.length < this.min) {
          this.errors.min = `最少应该输入${this.min}个字符哦`
          this.valid = false
          this.getError()
          // if (!this.firstError) {
          //   this.getError()
          // }
          return
        } else {
          delete this.errors.min
          this.getError()
        }
      }
      if (this.max) {
        if (this.currentValue.length > this.max) {
          this.errors.max = `最多可以输入${this.max}个字符哦`
          this.valid = false
          this.forceShowError = true
          this.getError()
          return
        } else {
          this.forceShowError = false
          delete this.errors.max
          this.getError()
        }
      }
      this.valid = true
    },
    validateEqual () {
      if (!this.equalWith && this.currentValue) {
        this.valid = false
        this.errors.equal = '输入不一致'
        return
      }
      let willCheck = this.dirty || this.currentValue.length >= this.equalWith.length
      // 只在长度符合时显示正确与否
      if (willCheck && this.currentValue !== this.equalWith) {
        this.valid = false
        this.errors.equal = '输入不一致'
      } else {
        if (!this.currentValue && this.required) {
          this.valid = false
        } else {
          this.valid = true
          delete this.errors.equal
        }
      }
    }
  }
}
</script>
