<template>
    <div v-clickoutside="handleClose"
         :class="selectClass"
         @click.stop="toggleMenu">
        <jdd-input v-if="mode=='single'"
                   ref="ipt"
                   v-model="inputValue"
                   :mode="mode"
                   :clearable="clearable"
                   :placeholder="selectedLabel||placeholder"
                   :size="size"
                   :readonly="readonly"
                   :disabled="selectDisabled"
                   :iconSuffix="dropIcon"
                   @clear="handleClear"
                   @input="handleInput"
                   @blur="handleBlur"
                   @focus="handleFocus"
                   @remove="handleRemove">
        </jdd-input>
        <jdd-tags v-else
                  ref="ipt"
                  v-model="tagsValue"
                  :placeholder="placeholder"
                  :disabled="selectDisabled"
                  :iconSuffix="dropIcon"
                  @clear="handleClear"
                  @remove="handleRemove">
        </jdd-tags>
        <transition name="ani-slide"
                    @after-leave="doDestroy">
            <div v-if="visible"
                 ref="popper"
                 :class="popperClass"
                 :style="popperStyle">
                <ul :class="`${prefix}-select-option-group`">
                    <li v-if="filterable && remote && loading"
                        :class="loadingClass"
                        @click.stop>
                        <slot name="loading">加载中。。。</slot>
                    </li>
                    <li v-if="!(filterable && remote && loading) && !filterOptions.length"
                        :class="emptyClass"
                        @click.stop>
                        <slot name="empty">无数据</slot>
                    </li>
                    <li v-for="(item) in filterOptions"
                        :key="item[keyLabel]"
                        :class="[...optionClass,{'active': item===selectedValue||item.selected},{'is-disabled':item.disabled}]"
                        @click.stop="handleSelect(item)">
                        <slot v-bind="item">
                            <span v-if="mode=='single'">{{item[keyLabel]}}</span>
                            <p v-else><span>{{item[keyLabel]}}</span><i v-if="item.selected"
                                   class="jdd-icon-success-s"></i></p>
                        </slot>
                    </li>
                    <li v-if="$slots.append">
                        <slot name="append"></slot>
                    </li>
                </ul>
            </div>
        </transition>
    </div>
</template>

<script>
import Input from 'jdd-design/components/input';
import Tags from '../tag/tags';
import poperMixins from 'jdd-design/utils/mixins/popper';
import {
    prefix,
    prefixMixins,
    guid,
    on,
    off,
    getZIndex,
    getValue
} from 'jdd-design/utils';
import transfer from 'jdd-design/utils/directives/transfer-dom';
import clickoutside from 'jdd-design/utils/directives/clickoutside';
import { debounce } from 'throttle-debounce';
export default {
    name: `${prefix}-select`,
    mixins: [prefixMixins, poperMixins],
    directives: { transfer, clickoutside },
    components: {
        jddInput: Input,
        jddTags: Tags
    },
    inject: {
        jddForm: {
            default: null
        },
        jddFormItem: {
            default: null
        }
    },
    provide() {
        return {
            jddSelect: this
        };
    },
    props: {
        size: String,
        keyLabel: String,
        valueLabel: String,
        value: [String, Number, Array],
        options: Array,
        clearable: Boolean,
        filterable: Boolean,
        remote: Function,
        placeholder: String,
        disabled: Boolean,
        mode: {
            type: String,
            default: 'single'
        }
    },
    data() {
        return {
            visible: false,
            selectedValue: null,
            tagsValue: null,
            model: null,
            popperStyle: {},
            inputValue: null,
            remoteOptions: [],
            focus: false,
            loading: false
        };
    },
    watch: {
        visible: function(val) {
            this.$nextTick(() => {
                if (val) {
                    this.initPopper();
                    this.getPosition();
                    this.updatePopper();
                    let actived = this.$refs.popper.querySelector('.active');
                    actived &&
                        this.$nextTick(() => {
                            let cy = actived.getBoundingClientRect().y;
                            let container = actived.parentNode.parentNode;
                            let py = container.getBoundingClientRect().y;
                            container.scrollTop = cy - py;
                        });
                }
            });
        },
        value: function(val) {
            this.initData(val);
        }
    },
    computed: {
        realSize() {
            return this.size || (this.jddForm && this.jddForm.size) || 'medium';
        },
        selectClass() {
            let clsNames = [`${prefix}-select`];
            this.jddFormItem &&
                this.jddFormItem.errorState &&
                clsNames.push(`is-${this.jddFormItem.errorState}`);
            return clsNames;
        },
        popperClass() {
            let clsNames = [`${prefix}-select-popper`];
            this.realSize &&
                clsNames.push(`${prefix}-select-popper--${this.realSize}`);
            return clsNames;
        },
        optionClass() {
            let clsNames = [`${prefix}-select-option`];
            return clsNames;
        },
        loadingClass() {
            let clsNames = [`${prefix}-select-option--loading`];
            return clsNames;
        },
        emptyClass() {
            let clsNames = [`${prefix}-select-option--empty`];
            return clsNames;
        },
        dropIcon() {
            if (this.visible) {
                return 'jdd-icon-arrow-down up';
            }
            return 'jdd-icon-arrow-down';
        },
        selectedIndex() {
            if (!this.selectedValue) return -1;
            return this.filterOptions.indexOf(this.selectedValue);
        },
        selectedLabel() {
            if (!this.selectedValue) return '';
            return this.selectedValue[this.keyLabel];
        },
        readonly() {
            return !this.filterable;
        },
        filterOptions() {
            if (this.filterable) {
                if (this.remote) {
                    return this.remoteOptions;
                } else {
                    if (this.inputValue) {
                        return this.options.filter(m =>
                            m[this.keyLabel].startsWith(this.inputValue)
                        );
                    }
                }
            }
            return this.options;
        },
        selectDisabled() {
            return this.disabled || (this.jddForm && this.jddForm.disabled);
        }
    },
    methods: {
        handleBlur() {
            this.jddFormItem && this.jddFormItem.$emit('form.blur');
        },
        handleFocus() {
            if (this.filterable) {
                this.inputValue = '';
            }
        },
        handleInput(v) {
            this.inputValue = v;
            if (this.remote) {
                this.loading = true;
                this.remoteOptions = [];
                debounce(200, () =>
                    this.remote(v, list => {
                        this.remoteOptions = list;
                        this.loading = false;
                    })
                )();
            }
        },
        handleClear() {
            if (this.mode == 'single') {
                this.model = '';
                this.selectedValue = null;
            } else {
                this.tagsValue = this.model = [];
                this.filterOptions.forEach(m => {
                    delete m.selected;
                });
            }
            this.$emit('input', this.model);
            this.$emit('change', this.model);
            this.handleClose();
        },
        handleClose() {
            this.visible = false;
        },
        handleRemove(item) {
            //多选模式删除一个
            this.tagsValue = this.tagsValue.filter(m => m != item);
            this.model = this.tagsValue.map(m => m.value);
            this.filterOptions.forEach(m => {
                if (m[this.valueLabel] == item.value) {
                    delete m.selected;
                }
            });
            this.$emit('input', this.model);
            this.$emit('change', this.model);
        },
        toggleMenu() {
            if (this.selectDisabled) return;
            this.visible = !this.visible;
            if (this.visible) {
                this.$refs.ipt.focus();
            }
        },
        getPosition() {
            let rect = this.$refs.ipt.$el.getBoundingClientRect();
            this.popperStyle = {
                minWidth: `${rect.width}px`
            };
        },
        handleSelect(item) {
            if (item.disabled) return;
            if (this.mode == 'single') {
                if (item[this.valueLabel] !== this.model) {
                    this.$emit('input', item[this.valueLabel]);
                    this.$emit('change', item);
                }
                this.selectedValue = item;
                this.inputValue = this.selectedLabel;
                this.handleClose();
            } else {
                item.selected = !item.selected;
                let modelObj = this.filterOptions.filter(m => m.selected);
                this.tagsValue = modelObj.map(m => {
                    return {
                        label: m[this.keyLabel],
                        value: m[this.valueLabel],
                        selected: m.selected
                    };
                });
                this.model = this.tagsValue.map(m => m.value);
                this.$emit('input', this.model);
                this.$emit('change', this.model);
            }

            this.jddFormItem && this.jddFormItem.clearValidate();
            this.jddFormItem && this.jddFormItem.$emit('form.change');
        },
        initPopper() {
            this.referenceElm = this.$refs.ipt.$el;
            this.popperElm = this.$refs.popper;
            this.currentPlacement = 'bottom-start';
        },
        initData(val) {
            if (this.mode == 'single') {
                this.selectedValue = this.filterOptions.find(
                    m => m[this.valueLabel] === val
                );
                if (this.selectedValue) {
                    this.model = val;
                    this.inputValue = this.selectedLabel;
                } else {
                    this.model = null;
                    this.inputValue = null;
                }
            } else {
                let modelObj = this.filterOptions.filter(m => {
                    let r = val.indexOf(m[this.valueLabel]) > -1;
                    if (r) {
                        m.selected = true;
                    } else {
                        m.selected = false;
                    }
                    return r;
                });

                this.tagsValue = modelObj.map(m => {
                    return {
                        label: m[this.keyLabel],
                        value: m[this.valueLabel]
                    };
                });
                this.model = this.tagsValue.map(m => m.value);
            }
        }
    },
    mounted() {
        this.initData(this.value);
        this.initPopper();
        on(window, 'wheel', this.mouseWheel);
    },
    beforeDestory() {
        off(window, 'wheel', this.mouseWheel);
    }
};
</script>