<template>
    <div :class="inputClass"
         @mouseover="showIcon=true"
         @mouseleave="showIcon=false"
         role="text">
        <div v-if="iconPrefix || $slots.prefix"
             :class="prefixClass"
             :style="prefixStyle">
            <slot name="prefix">
                <i :class="[`${prefix}-input__icon`,iconPrefix]"></i>
            </slot>
        </div>
        <div v-if="$slots.prepend"
             :class="`${prefix}-input__prepend`">
            <slot name="prepend"></slot>
        </div>
        <input v-if="mode==='single' && !$slots.default"
               ref="input"
               :type="showPassword ? (passwordVisible ? 'text': 'password') : type"
               :disabled="inputDisabled"
               :readonly="readonly"
               :aria-readonly="readonly"
               v-bind="$attrs"
               @input="handleInput"
               @click="handleClick"
               @change="handleChange"
               @blur="handleBlur"
               @focus="handleFocus"
               @compositionstart="handleCompositionStart"
               @compositionupdate="handleCompositionUpdate"
               @compositionend="handleCompositionEnd"
               :class="originClass">
        <div v-if="mode==='range'"
             :class="`${prefix}-input__range`">
            <input ref="inputStart"
                   :disabled="inputDisabled"
                   :readonly="readonly"
                   :aria-readonly="readonly"
                   v-bind="$attrs"
                   :placeholder="placeholders[0]"
                   @input="handleInputStart"
                   @click="handleClick"
                   @blur="handleBlur"
                   @focus="handleFocus"
                   @change="handleChangeStart"
                   @compositionstart="handleCompositionStart"
                   @compositionupdate="handleCompositionUpdate"
                   @compositionend="handleCompositionEnd"
                   :class="[...originClass,``]">
            <slot name="rangeSeperator"></slot>
            <input ref="inputEnd"
                   :disabled="inputDisabled"
                   :readonly="readonly"
                   :aria-readonly="readonly"
                   v-bind="$attrs"
                   :placeholder="placeholders[1]"
                   @input="handleInputEnd"
                   @click="handleClick"
                   @blur="handleBlur"
                   @focus="handleFocus"
                   @change="handleChangeEnd"
                   @compositionstart="handleCompositionStart"
                   @compositionupdate="handleCompositionUpdate"
                   @compositionend="handleCompositionEnd"
                   :class="[...originClass,``]">
        </div>
        <textarea v-if="mode==='textarea'"
                  :class="originClass"
                  @compositionstart="handleCompositionStart"
                  @compositionupdate="handleCompositionUpdate"
                  @compositionend="handleCompositionEnd"
                  @input="handleInput"
                  ref="input"
                  v-bind="$attrs"
                  :disabled="inputDisabled"
                  :readonly="readonly"
                  :style="textareaStyle"
                  @focus="handleFocus"
                  @blur="handleBlur"
                  @change="handleChange"></textarea>
        <div :class="suffixClass"
             :style="suffixStyle"
             v-if="$slots.suffix||iconSuffix||showClear||showPwd">
            <slot name="suffix"
                  v-if="!showClear && !showPwd">
                <i v-if="iconSuffix"
                   :class="[`${prefix}-input__icon`,iconSuffix]"></i>
            </slot>
            <i v-if="showClear"
               :class="clearClass"
               @click.stop="clear"></i>
            <i v-if="showPwd"
               :class="passClass"
               @click.stop="handlePasswordVisible"></i>
        </div>
        <div v-if="$slots.append"
             :class="`${prefix}-input__append`">
            <slot name="append"></slot>
        </div>
    </div>
</template>

<script>
import { prefix, prefixMixins } from 'jdd-design/utils';
import getComputedStyle from './calc';
export default {
    name: `${prefix}-input`,
    mixins: [prefixMixins],
    data() {
        return {
            model: '',
            textareaStyle: {},
            hovering: false,
            showIcon: false,
            isComposing: false,
            passwordVisible: false,
            prefixStyle: {},
            suffixStyle: {}
        };
    },
    props: {
        disabled: Boolean,
        size: String,
        value: String | Number | Array,
        type: String,
        iconPrefix: String,
        iconSuffix: String,
        clearable: Boolean,
        readonly: Boolean,
        showPassword: Boolean,
        placeholders: Array,
        rows: Number,
        mode: {
            type: String,
            default: 'single'
        },
        regex: RegExp
    },
    inject: {
        jddForm: {
            default: null
        },
        jddFormItem: {
            default: null
        }
    },
    watch: {
        value: function(val) {
            this.model = val;
        },
        model: function(val) {
            this.setInputValue();
        }
    },
    computed: {
        inputClass() {
            let clsNames = [`${prefix}-input`];
            this.realSize && clsNames.push(`${prefix}-input--${this.realSize}`);
            (this.$slots.prepend || this.$slots.append) &&
                clsNames.push(`${prefix}-input--group`);
            this.jddFormItem &&
                this.jddFormItem.errorState &&
                clsNames.push(`is-${this.jddFormItem.errorState}`);
            this.inputDisabled && clsNames.push('is-disabled');
            this.iconPrefix &&
                !this.$slots.prepend &&
                clsNames.push(`${prefix}-input--prefix`);
            (this.iconSuffix || this.clearable || this.showPassword) &&
                !this.$slots.append &&
                clsNames.push(`${prefix}-input--suffix`);
            return clsNames;
        },
        originClass() {
            let clsNames = [`${prefix}-input__origin`];
            this.$slots.prepend &&
                clsNames.push(`${prefix}-input__origin--prepend`);
            this.$slots.append &&
                clsNames.push(`${prefix}-input__origin--append`);
            return clsNames;
        },
        prefixClass() {
            let clsNames = [`${prefix}-input__prefix`];
            return clsNames;
        },
        suffixClass() {
            let clsNames = [`${prefix}-input__suffix`];
            return clsNames;
        },
        clearClass() {
            let clsNames = [`${prefix}-input__icon`, `${prefix}-input__action`];
            clsNames.push(`${prefix}-icon-error`);
            return clsNames;
        },
        passClass() {
            let clsNames = [
                `${prefix}-input__icon`,
                `${prefix}-input__action`,
                `${
                    this.passwordVisible
                        ? `${prefix}-icon-eye-open`
                        : `${prefix}-icon-eye-close`
                }`
            ];
            return clsNames;
        },
        inputDisabled() {
            return this.disabled || (this.jddForm && this.jddForm.disabled);
        },
        realSize() {
            return this.size || (this.jddForm && this.jddForm.size) || 'medium';
        },
        showClear() {
            return (
                this.clearable &&
                this.showIcon &&
                !this.inputDisabled &&
                !this.showPassword &&
                this.model
            );
        },
        showPwd() {
            return (
                this.type === 'password' &&
                this.showPassword &&
                this.showIcon &&
                !this.inputDisabled &&
                this.model
            );
        }
    },
    methods: {
        handleClick(event) {
            this.$emit('click');
        },
        handleBlur(event) {
            this.$emit('blur', event);
            this.jddFormItem && this.jddFormItem.$emit('form.blur');
        },
        handleFocus(event) {
            this.showIcon = true;
            this.$emit('focus', event);
        },
        handleCompositionStart() {
            this.isComposing = true;
        },
        handleCompositionEnd(event) {
            this.isComposing = false;
            this.handleInput(event);
        },
        handleCompositionUpdate() {},
        handleInputCommon(action) {
            if (this.isComposing) return; //中文拼写状态

            if (action && action()) {
                this.$nextTick(this.setInputValue);

                this.jddFormItem && this.jddFormItem.clearValidate();
            }
        },
        handleInput(event) {
            this.handleInputCommon(() => {
                if (event.target.value === this.model) return false;

                this.$emit('input', event.target.value);

                return true;
            });
        },
        handleInputStart(event) {
            this.handleInputCommon(() => {
                if (event.target.value === this.model[0]) return false;

                this.$emit('input', [event.target.value, this.model[1]]);

                return true;
            });
        },
        handleInputEnd(event) {
            this.handleInputCommon(() => {
                if (event.target.value === this.model[1]) return false;

                this.$emit('input', [this.model[0], event.target.value]);

                return true;
            });
        },
        handleChange(event) {
            this.$emit('change', event.target.value);
            this.jddFormItem && this.jddFormItem.$emit('form.change');
        },
        handleChangeStart(event) {
            this.$emit('change', [event.target.value, this.model[1]]);
            this.jddFormItem && this.jddFormItem.$emit('form.change');
        },
        handleChangeEnd(event) {
            this.$emit('change', [this.model[0], event.target.value]);
            this.jddFormItem && this.jddFormItem.$emit('form.change');
        },
        handlePasswordVisible() {
            this.passwordVisible = !this.passwordVisible;
        },
        setInputValue() {
            if (this.mode == 'range') {
                const inputStart = this.$refs.inputStart;
                const inputEnd = this.$refs.inputEnd;
                if (!inputStart || !inputEnd) return;
                if (
                    inputStart.value === this.model[0] &&
                    inputEnd.value === this.model[1]
                )
                    return;
                inputStart.value = this.model[0];
                inputEnd.value = this.model[1];
            } else {
                const input = this.$refs.input;
                if (!input) return;
                if (input.value === this.model) return;
                input.value = this.model;
            }
        },
        setLayout() {
            if (this.$slots.prepend) {
                this.prefixStyle = {
                    'margin-left': `${
                        this.$el.querySelector(`.${prefix}-input__prepend`)
                            .clientWidth
                    }px`
                };
            }
            if (this.$slots.append) {
                this.suffixStyle = {
                    'margin-right': `${
                        this.$el.querySelector(`.${prefix}-input__append`)
                            .clientWidth
                    }px`
                };
            }
        },
        clear() {
            if (this.mode === 'single') {
                this.$emit('input', '');
                this.$emit('change', '');
            } else {
                this.$emit('input', ['', '']);
                this.$emit('change', ['', '']);
            }
            this.$emit('clear');

            this.$refs.input && this.$refs.input.focus();
            this.$refs.inputStart && this.$refs.inputStart.focus();
            this.jddFormItem && this.jddFormItem.clearValidate();
        },
        focus() {
            this.$refs.input && this.$refs.input.focus();
            this.$refs.inputStart && this.$refs.inputStart.focus();
        },
        blur() {
            this.$refs.input && this.$refs.input.blur();
            this.$refs.inputStart && this.$refs.inputStart.focus();
        }
    },
    mounted() {
        if (this.mode === 'range') {
            this.model =
                this.value === null || this.value === undefined
                    ? ['', '']
                    : this.value.map(m => String(m));
        } else {
            this.model =
                this.value === null || this.value === undefined
                    ? ''
                    : String(this.value);
        }
        this.$nextTick(() => {
            this.setLayout();
            if (this.mode === 'range') {
                let style = window.getComputedStyle(this.$el);
                let paddingRight = style.getPropertyValue('padding-right');
                let width = this.$el.clientWidth - parseFloat(paddingRight);
                let elm =
                    this.$slots.rangeSeperator[0] &&
                    this.$slots.rangeSeperator[0].elm;
                let inputWidth = (width - ((elm && elm.clientWidth) || 0)) / 2;
                this.$refs.inputStart.style.width = this.$refs.inputEnd.style.width = `${inputWidth}px`;
            }
        });
        if (this.mode === 'textarea') {
            let style = window.getComputedStyle(this.$refs.input);
            let lineHeight = style.getPropertyValue('line-height');
            let paddingTop = style.getPropertyValue('padding-top');
            let paddingBottom = style.getPropertyValue('padding-bottom');
            let height =
                this.rows * parseFloat(lineHeight) +
                parseFloat(paddingTop) +
                parseFloat(paddingBottom);
            this.textareaStyle = {
                resize: 'none',
                height: `${Math.ceil(height)}px`
            };
        }
    }
};
</script>
