import { defineVxeComponent } from '../../ui/src/comp';
import XEUtils from 'xe-utils';
import { getConfig, getI18n, createEvent, globalMixins } from '../../ui';
import { getFuncText } from '../../ui/src/utils';
import { createComponentLog } from '../../ui/src/log';
const { warnLog } = createComponentLog('textarea');
let autoTxtElem;
export default {
    name: 'VxeTextarea',
    model: {
        prop: 'value',
        event: 'modelValue'
    },
    mixins: [
        globalMixins.sizeMixin
    ],
    props: {
        value: [String, Number],
        className: String,
        immediate: {
            type: Boolean,
            default: true
        },
        name: String,
        readonly: {
            type: Boolean,
            default: null
        },
        editable: {
            type: Boolean,
            default: true
        },
        disabled: {
            type: Boolean,
            default: null
        },
        placeholder: String,
        maxLength: [String, Number],
        trim: {
            type: Boolean,
            default: () => getConfig().textarea.trim
        },
        rows: {
            type: [String, Number],
            default: null
        },
        cols: {
            type: [String, Number],
            default: null
        },
        showWordCount: Boolean,
        countMethod: Function,
        /**
         * 已废弃，被 auto-size 替换
         * @deprecated
         */
        autosize: {
            type: [Boolean, Object],
            default: null
        },
        autoSize: {
            type: [Boolean, Object],
            default: null
        },
        form: String,
        resize: {
            type: String,
            default: () => getConfig().textarea.resize
        },
        size: {
            type: String,
            default: () => getConfig().textarea.size || getConfig().size
        },
        // 已废弃
        maxlength: [String, Number]
    },
    inject: {
        $xeForm: {
            default: null
        },
        formItemInfo: {
            from: 'xeFormItemInfo',
            default: null
        }
    },
    data() {
        const reactData = {
            inputValue: ''
        };
        return {
            xID: XEUtils.uniqueId(),
            reactData,
            reFlag: 0
        };
    },
    computed: Object.assign(Object.assign({}, {}), { computeFormReadonly() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const $xeForm = $xeTextarea.$xeForm;
            const { readonly } = props;
            if (readonly === null) {
                if ($xeForm) {
                    return $xeForm.readonly;
                }
                return false;
            }
            return readonly;
        },
        computeIsDisabled() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const $xeForm = $xeTextarea.$xeForm;
            const { disabled } = props;
            if (disabled === null) {
                if ($xeForm) {
                    return $xeForm.disabled;
                }
                return false;
            }
            return disabled;
        },
        computeInputReadonly() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const { editable, readonly } = props;
            return readonly || !editable;
        },
        computeInpPlaceholder() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const { placeholder } = props;
            if (placeholder) {
                return getFuncText(placeholder);
            }
            const globalPlaceholder = getConfig().textarea.placeholder;
            if (globalPlaceholder) {
                return getFuncText(globalPlaceholder);
            }
            return getI18n('vxe.base.pleaseInput');
        },
        computeInpMaxLength() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const { maxLength, maxlength } = props;
            return maxLength || maxlength;
        },
        computeInputCount() {
            const $xeTextarea = this;
            const reactData = $xeTextarea.reactData;
            return XEUtils.getSize(reactData.inputValue);
        },
        computeIsCountError() {
            const $xeTextarea = this;
            const inputCount = $xeTextarea.computeInputCount;
            const inpMaxLength = $xeTextarea.computeInpMaxLength;
            return inpMaxLength && inputCount > XEUtils.toNumber(inpMaxLength);
        },
        computeSizeOpts() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const { autosize, autoSize } = props;
            if (autosize || getConfig().textarea.autosize) {
                return Object.assign({ minRows: 1, maxRows: 10 }, getConfig().textarea.autosize, autosize);
            }
            return Object.assign({ minRows: 1, maxRows: 10 }, getConfig().textarea.autoSize, autoSize);
        } }),
    methods: {
        //
        // Method
        //
        dispatchEvent(type, params, evnt) {
            const $xeTextarea = this;
            $xeTextarea.$emit(type, createEvent(evnt, { $textarea: $xeTextarea }, params));
        },
        emitModel(value) {
            const $xeTextarea = this;
            const { _events } = $xeTextarea;
            if (_events && _events.modelValue) {
                $xeTextarea.$emit('modelValue', value);
            }
            else {
                $xeTextarea.$emit('model-value', value);
            }
        },
        focus() {
            const $xeTextarea = this;
            const textElem = $xeTextarea.$refs.refTextarea;
            textElem.focus();
            return $xeTextarea.$nextTick();
        },
        blur() {
            const $xeTextarea = this;
            const textElem = $xeTextarea.$refs.refTextarea;
            textElem.blur();
            return $xeTextarea.$nextTick();
        },
        updateAutoTxt() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const reactData = $xeTextarea.reactData;
            const { size, autosize, autoSize } = props;
            const { inputValue } = reactData;
            if (autosize || autoSize) {
                const formReadonly = $xeTextarea.computeFormReadonly;
                if (!autoTxtElem) {
                    autoTxtElem = document.createElement('div');
                }
                if (!autoTxtElem.parentNode) {
                    document.body.appendChild(autoTxtElem);
                }
                const taElem = $xeTextarea.$refs.refTextarea;
                const ctElem = $xeTextarea.$refs.refContent;
                const textElem = formReadonly ? ctElem : taElem;
                if (!textElem) {
                    return;
                }
                if (!textElem) {
                    return;
                }
                const textStyle = getComputedStyle(textElem);
                autoTxtElem.className = ['vxe-textarea--autosize', size ? `size--${size}` : ''].join(' ');
                autoTxtElem.style.width = `${textElem.clientWidth}px`;
                autoTxtElem.style.padding = textStyle.padding;
                autoTxtElem.innerText = ('' + (inputValue || '　')).replace(/\n$/, '\n　');
            }
        },
        handleResize() {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const { autosize, autoSize } = props;
            if (autosize || autoSize) {
                $xeTextarea.$nextTick(() => {
                    const sizeOpts = $xeTextarea.computeSizeOpts;
                    const formReadonly = $xeTextarea.computeFormReadonly;
                    const { minRows, maxRows } = sizeOpts;
                    const taElem = $xeTextarea.$refs.refTextarea;
                    const ctElem = $xeTextarea.$refs.refContent;
                    const textElem = formReadonly ? ctElem : taElem;
                    if (!textElem) {
                        return;
                    }
                    const sizeHeight = autoTxtElem.clientHeight;
                    const textStyle = getComputedStyle(textElem);
                    const lineHeight = XEUtils.toNumber(textStyle.lineHeight);
                    const paddingTop = XEUtils.toNumber(textStyle.paddingTop);
                    const paddingBottom = XEUtils.toNumber(textStyle.paddingBottom);
                    const borderTopWidth = XEUtils.toNumber(textStyle.borderTopWidth);
                    const borderBottomWidth = XEUtils.toNumber(textStyle.borderBottomWidth);
                    const intervalHeight = paddingTop + paddingBottom + borderTopWidth + borderBottomWidth;
                    const rowNum = (sizeHeight - intervalHeight) / lineHeight;
                    const textRows = rowNum && /[0-9]/.test('' + rowNum) ? rowNum : Math.floor(rowNum) + 1;
                    let vaildRows = textRows;
                    if (textRows < minRows) {
                        vaildRows = minRows;
                    }
                    else if (textRows > maxRows) {
                        vaildRows = maxRows;
                    }
                    textElem.style.height = `${(vaildRows * lineHeight) + intervalHeight}px`;
                });
            }
        },
        triggerEvent(evnt) {
            const $xeTextarea = this;
            const reactData = $xeTextarea.reactData;
            const value = reactData.inputValue;
            $xeTextarea.dispatchEvent(evnt.type, { value }, evnt);
        },
        handleChange(value, evnt) {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const reactData = $xeTextarea.reactData;
            const $xeForm = $xeTextarea.$xeForm;
            const formItemInfo = $xeTextarea.formItemInfo;
            if (props.trim) {
                value = `${value || ''}`.trim();
            }
            reactData.inputValue = value;
            $xeTextarea.emitModel(value);
            if (XEUtils.toValueString(props.value) !== value) {
                $xeTextarea.dispatchEvent('change', { value }, evnt);
                // 自动更新校验状态
                if ($xeForm && formItemInfo) {
                    $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, value);
                }
            }
        },
        inputEvent(evnt) {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const reactData = $xeTextarea.reactData;
            const { immediate } = props;
            const textElem = evnt.target;
            const value = textElem.value;
            reactData.inputValue = value;
            if (immediate) {
                $xeTextarea.handleChange(value, evnt);
            }
            $xeTextarea.dispatchEvent('input', { value }, evnt);
            $xeTextarea.handleResize();
        },
        changeEvent(evnt) {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const reactData = $xeTextarea.reactData;
            const { immediate } = props;
            if (immediate) {
                $xeTextarea.triggerEvent(evnt);
            }
            else {
                $xeTextarea.handleChange(reactData.inputValue, evnt);
            }
            $xeTextarea.dispatchEvent('lazy-change', { value: reactData.inputValue }, evnt);
        },
        blurEvent(evnt) {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const reactData = $xeTextarea.reactData;
            const { immediate } = props;
            const { inputValue } = reactData;
            if (!immediate) {
                $xeTextarea.handleChange(inputValue, evnt);
            }
            $xeTextarea.dispatchEvent('blur', { value: inputValue }, evnt);
        },
        //
        // Render
        //
        renderVN(h) {
            const $xeTextarea = this;
            const props = $xeTextarea;
            const reactData = $xeTextarea.reactData;
            const { className, resize, autosize, autoSize, showWordCount, countMethod, rows, cols } = props;
            const { inputValue } = reactData;
            const vSize = $xeTextarea.computeSize;
            const isDisabled = $xeTextarea.computeIsDisabled;
            const isCountError = $xeTextarea.computeIsCountError;
            const inputCount = $xeTextarea.computeInputCount;
            const inputReadonly = $xeTextarea.computeInputReadonly;
            const formReadonly = $xeTextarea.computeFormReadonly;
            const inpPlaceholder = $xeTextarea.computeInpPlaceholder;
            const inpMaxLength = $xeTextarea.computeInpMaxLength;
            if (formReadonly) {
                return h('div', {
                    ref: 'refElem',
                    class: ['vxe-textarea--readonly', className]
                }, [
                    h('div', {
                        ref: 'refContent',
                        class: 'vxe-textarea--content'
                    }, inputValue)
                ]);
            }
            return h('div', {
                ref: 'refElem',
                class: ['vxe-textarea', className, {
                        [`size--${vSize}`]: vSize,
                        'is--autosize': autosize || autoSize,
                        'is--count': showWordCount,
                        'is--disabled': isDisabled,
                        'is--rows': !XEUtils.eqNull(rows),
                        'is--cols': !XEUtils.eqNull(cols)
                    }],
                attrs: {
                    spellcheck: false
                }
            }, [
                h('textarea', {
                    ref: 'refTextarea',
                    class: 'vxe-textarea--inner',
                    domProps: {
                        value: inputValue
                    },
                    attrs: {
                        name: props.name,
                        placeholder: inpPlaceholder,
                        maxlength: inpMaxLength,
                        readonly: inputReadonly,
                        disabled: isDisabled,
                        rows,
                        cols
                    },
                    style: resize
                        ? {
                            resize
                        }
                        : {},
                    on: {
                        input: $xeTextarea.inputEvent,
                        change: $xeTextarea.changeEvent,
                        keydown: $xeTextarea.triggerEvent,
                        keyup: $xeTextarea.triggerEvent,
                        click: $xeTextarea.triggerEvent,
                        focus: $xeTextarea.triggerEvent,
                        blur: $xeTextarea.blurEvent
                    }
                }),
                showWordCount
                    ? h('span', {
                        class: ['vxe-textarea--count', {
                                'is--error': isCountError
                            }]
                    }, countMethod ? `${countMethod({ value: inputValue })}` : `${inputCount}${inpMaxLength ? `/${inpMaxLength}` : ''}`)
                    : null
            ]);
        }
    },
    watch: {
        value(val) {
            const $xeTextarea = this;
            const reactData = $xeTextarea.reactData;
            reactData.inputValue = val;
            $xeTextarea.updateAutoTxt();
        },
        computeFormReadonly() {
            const $xeTextarea = this;
            $xeTextarea.reFlag++;
        },
        computeSizeOpts() {
            const $xeTextarea = this;
            $xeTextarea.reFlag++;
        },
        autoSize() {
            const $xeTextarea = this;
            $xeTextarea.reFlag++;
        },
        autosize() {
            const $xeTextarea = this;
            $xeTextarea.reFlag++;
        },
        reFlag() {
            const $xeTextarea = this;
            $xeTextarea.updateAutoTxt();
            $xeTextarea.handleResize();
        }
    },
    created() {
        const $xeTextarea = this;
        const props = $xeTextarea;
        const reactData = $xeTextarea.reactData;
        reactData.inputValue = props.value;
        $xeTextarea.$nextTick(() => {
            const { autosize, autoSize } = props;
            if (autosize) {
                warnLog('vxe.error.delProp', ['autosize', 'auto-size']);
            }
            if (autosize || autoSize) {
                $xeTextarea.updateAutoTxt();
                $xeTextarea.handleResize();
            }
        });
    },
    render(h) {
        return this.renderVN(h);
    }
};
