<template>
    <el-autocomplete
        class="app-picker-microservice"
        :disabled="disabled"
        v-model="curvalue"
        size="small"
        :readonly="readonly"
        :placeholder="placeholder"
        :trigger-on-focus="true"
        :popper-class="popperClass"
        :fetch-suggestions="onSearch"
        @select="onSelect"
    >
        <template v-slot:suffix>
            <i v-if="curvalue && !disabled" class="el-icon-circle-close" @click="onClear"></i>
            <i class="el-icon-arrow-down"></i>
        </template>
        <template slot-scope="{ item }">
            <template v-if="Object.is(mode, 'tree')">
                <el-tree
                    ref="tree"
                    :data="treeData"
                    :show-checkbox="multiple"
                    :node-key="showValue"
                    :props="defaultProps"
                    :check-strictly="true"
                    :default-checked-keys="defaultKeys"
                    :filter-node-method="filterNode"
                    :check-on-click-node="true"
                    @check="onTreeSelect"
                ></el-tree>
            </template>
            <template v-else>
                <span>{{ item.label }}</span>
            </template>
        </template>
    </el-autocomplete>
</template>

<script lang="ts">
import { Util } from 'ibiz-core';
import { Subject, Subscription } from 'rxjs';
import { Vue, Component, Prop, Watch } from 'vue-property-decorator';

@Component({})
export default class AppPickerMicroservice extends Vue {
    /**
     * 视图上下文
     *
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop() public context!: any;

    /**
     * 视图参数
     *
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop() public viewparams!: any;

    /**
     * 表单服务
     *
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop() public service?: any;

    /**
     * 应用实体主信息属性名称
     *
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: 'srfmajortext' }) public deMajorField!: string;

    /**
     * 应用实体主键属性名称
     *
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: 'srfkey' }) public deKeyField!: string;

    /**
     * 表单数据
     *
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop() public data!: any;

    /**
     * 属性项名称
     *
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop() public name!: string;

    /**
     * 是否启用
     *
     * @type {boolean}
     * @memberof AppPickerMicroservice
     */
    @Prop() public disabled?: boolean;

    /**
     * 只读模式
     * @type {boolean}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: false }) public readonly?: boolean;

    /**
     * 局部上下文导航参数
     *
     * @type {any}
     * @memberof AppPickerMicroservice
     */
    @Prop() public localContext!: any;

    /**
     * 局部导航参数
     *
     * @type {any}
     * @memberof AppPickerMicroservice
     */
    @Prop() public localParam!: any;

    /**
     * 值项名称
     *
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop() public valueitem!: string;

    /**
     * 排序
     *
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop() public sort?: string;

    /**
     * 行为组
     *
     * @type {Array<any>}
     * @memberof AppPickerMicroservice
     */
    @Prop() public actionDetails?: Array<any>;

    /**
     * 值
     *
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop() public value?: any;

    /**
     * 占位提示
     *
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop() public placeholder?: string;

    /**
     * 值分割符
     *
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: ',' }) public valueSeparator!: string;

    /**
     * @description 数据展示模式
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: 'list' }) public mode!: string;

    /**
     * @description 是否多选
     * @type {boolean}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: false }) public multiple!: boolean;

    /**
     * @description 数据查询地址
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop() public url?: string;

    /**
     * @description 字节的过滤键
     * @type {string}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: 'pvalue' }) public leafFilterKey!: string;

    /**
     * @description 是否搜索查询
     * @type {boolean}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: false }) public enableSearch!: boolean;

    /**
     * @description 是否只允许选中子节点
     * @type {boolean}
     * @memberof AppPickerMicroservice
     */
    @Prop({ default: false }) public onlyLeaf!: boolean;

    /**
     * @description 重置项名称
     * @type {boolean}
     * @memberof AppPickerMicroservice
     */
    @Prop() public resetItemName?: string;

    /**
     * @description 填充对象
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    @Prop() public fillMap?: any;

    /**
     * 表单状态对象
     *
     * @type {Subject<any>}
     * @memberof AppEmbedPicker
     */
    @Prop() public formState!: Subject<any>

    /**
     * 订阅对象
     *
     * @protected
     * @type {(Subscription | undefined)}
     * @memberof SelectType
     */
    protected formStateEvent: Subscription | undefined;

    /**
     * @description 显示值label
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    showLabel: string = 'label';

    /**
     * @description 显示值value
     * @type {*}
     * @memberof AppPickerMicroservice
     */
    showValue: string = 'id';

    /**
     * @description 数据
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public items: any[] = [];

    /**
     * @description 树结构数据
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public treeData: any[] = [];

    /**
     * @description 树结构默认参数
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public defaultProps: any = { label: 'label' };

    /**
     * @description 树默认选中数据
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public defaultKeys: string[] = [];

    /**
     * @description 选中数据map
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public selectionMap: Map<string, any> = new Map();

    /**
     * @description 显示文本
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public text: string = '';

    /**
     * @description 下拉类名
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public popperClass: string = 'app-picker-microservice--popper';

    /**
     * @description 唯一标识
     * @type {any[]}
     * @memberof AppPickerMicroservice
     */
    public uuid: string = Util.createUUID();

    get curvalue() {
        if (this.value && this.valueitem) {
            return this.value;
        }
        return this.text;
    }

    set curvalue(value: string) {
        if (this.enableSearch && this.value) {
            this.handleEmit('', '');
        }
        this.text = value;
    }

    @Watch('data',{deep: true})
    onDataChange(newData: any, oldData: any) {
        if (newData && oldData && this.resetItemName && Object.is(newData[this.resetItemName], oldData[this.resetItemName])) {
            this.items = [];
        }
    }

    /**
     * @description 生命周期
     * @memberof AppPickerMicroservice
     */
    async created() {
        if(this.formState) {
            this.formStateEvent = this.formState.subscribe(({ type, data }) => {
                if (Object.is('load', type) && !this.valueitem) {
                    this.load();
                    if (this.items.length > 0) {
                        const item = this.items.find(item => Object.is(item[this.showValue], this.value));
                        if (item) {
                            this.text = item[this.showLabel];
                        }
                    }
                }
            });
        }
    }

    /**
     * @description 生命周期
     * @memberof AppPickerMicroservice
     */
    mounted() {
        if (this.fillMap) {
            this.showLabel = this.fillMap.label;
            this.showValue = this.fillMap.id;
            this.defaultProps.label = this.fillMap.label;
        }
        this.popperClass += ` app-picker-microservice--popper-${this.uuid}`;
    }

    /**
     * @description 组件销毁
     * @memberof AppPickerMicroservice
     */
    destroyed() {
        if (this.formStateEvent) {
            this.formStateEvent.unsubscribe();
        }
    }

    /**
     * @description 搜索数据
     * @memberof AppPickerMicroservice
     */
    async onSearch(query: string, callback: Function) {
        await this.load();
        if (Object.is(this.mode, 'tree')) {
            callback(this.treeData);
        } else {
            callback(this.items);
        }
        this.$nextTick(() => {
            this.filter(query, callback);
        })
        this.togglePopper(true);
    }

    /**
     * @description 数据加载
     * @memberof AppPickerMicroservice
     */
    async load() {
        if (this.url && this.items.length == 0) {
            let queryParam: any = {};
            if (this.localParam && Object.keys(this.localParam).length > 0) {
                queryParam = this.$util.computedNavData(this.data, this.context, this.viewparams, this.localParam);
            }
            try {
                const response = await this.$http.post(this.url, queryParam);
                if (response && response.status !== 200) {
                    this.$throw('数据加载失败', 'onSearch');
                }
                if (Object.is(this.mode, 'tree')) {
                    if (response.data && response.data.length > 1) {
                        this.items = response.data || [];
                        this.handleLevelCodeList(this.items);
                    } else {
                        this.treeData = response.data || [];
                        this.items = [];
                        this.transformTreeData(this.treeData);
                    }
                } else {
                    this.items = response.data || [];
                }
                this.setDefaultSelect();
            } catch (error) {
                this.$throw(error, 'onSearch');
            }
        }
    }

    /**
     * @description 数据过滤
     * @memberof AppPickerMicroservice
     */
    filter(query: string, callback: Function) {
        if (this.enableSearch && !this.multiple) {
            if (Object.is(this.mode, 'tree')) {
                const tree: any = this.$refs.tree;
                if (tree) {
                    tree.filter(query);
                    callback(this.treeData);
                }
            } else {
                const results = query
                    ? this.items.filter(restaurant => {
                          return restaurant[this.showLabel].toLowerCase().indexOf(query.toLowerCase()) === 0;
                      })
                    : this.items;
                callback(results);
            }
        }
    }

    /**
     * @description 数据选中
     * @memberof AppPickerMicroservice
     */
    onSelect(item: any) {
        if (this.multiple) {
            if (this.selectionMap.has(item[this.showValue])) {
                this.selectionMap.delete(item[this.showValue]);
            } else {
                this.selectionMap.set(item[this.showValue], item);
            }
            this.valueChang();
        } else {
            this.handleEmit(item[this.showLabel], item[this.showValue]);
        }
    }

    /**
     * @description 树数据选中
     * @memberof AppPickerMicroservice
     */
    onTreeSelect(item: any, node: any) {
        if (this.onlyLeaf && item.children) {
            return;
        }
        if (this.multiple) {
            if (this.selectionMap.has(item[this.showValue])) {
                this.selectionMap.delete(item[this.showValue]);
            } else {
                this.selectionMap.set(item[this.showValue], item);
            }
            this.valueChang();
        } else {
            this.handleEmit(item[this.showLabel], item[this.showValue]);
        }
        this.togglePopper();
    }

    /**
     * @description 切换下拉显示状态
     * @memberof AppPickerMicroservice
     */
    togglePopper(show: boolean = false) {
        const popper: any = document.querySelector(`.app-picker-microservice--popper-${this.uuid}`);
        if (popper) {
            popper.style.display = show ? 'block' : 'none';
        }
    }

    /**
     * @description 清空
     * @memberof AppPickerMicroservice
     */
    onClear() {
        this.handleEmit('', '');
        this.text = '';
        const tree: any = this.$refs.tree;
        if (tree) {
            tree.filter('');
        }
    }

    /**
     * @description 设置默认选中
     * @memberof AppPickerMicroservice
     */
    setDefaultSelect() {
        if (this.items.length > 0 && this.value) {
            const keys: string[] = this.value.split(this.valueSeparator);
            keys.forEach((key: string) => {
                const data = this.items.find(item => Object.is(item[this.showValue], key));
                if (data) {
                    this.selectionMap.set(key, data);
                }
            });
            this.defaultKeys = keys;
        }
    }

    /**
     * @description 树过滤节点
     * @memberof AppPickerMicroservice
     */
    filterNode(value: string, data: any) {
        if (!value) return true;
        return data.label.indexOf(value) !== -1;
    }

    /**
     * @description 数据变更
     * @memberof AppPickerMicroservice
     */
    valueChang() {
        let value = '';
        let label = '';
        this.selectionMap.forEach((item: any) => {
            value += this.valueSeparator + item[this.showValue];
            label += this.valueSeparator + item[this.showLabel];
        });
        if (value.length > 0) {
            value = value.slice(1);
            label = label.slice(1);
        }
        this.handleEmit(label.slice(1), value.slice(1));
    }

    /**
     * @description 处理抛值
     * @memberof AppPickerMicroservice
     */
    handleEmit(label: string, value: string) {
        this.text = label;
        if (this.valueitem) {
            this.$emit('formitemvaluechange', {
                name: this.name,
                value: label,
            });
            this.$emit('formitemvaluechange', {
                name: this.valueitem,
                value: value,
            });
        } else {
            this.$emit('formitemvaluechange', {
                name: this.name,
                value: value,
            });
        }
    }

    /**
     * 转换树数据为平铺数据
     *
     * @param {*} items
     * @memberof AppPickerMicroservice
     */
    transformTreeData(treeData: any[]) {
        if (treeData.length > 0) {
            treeData.forEach((node: any) => {
                this.items.push(node);
                if (node.children && node.children.length > 0) {
                    this.transformTreeData(node.children);
                }
            });
        }
    }

    /**
     * 处理层级代码表
     *
     * @param {*} items
     * @memberof AppPickerMicroservice
     */
    public handleLevelCodeList(items: Array<any>) {
        if (items && items.length > 0) {
            const hasChildren = items.some((item: any) => {
                return item[this.leafFilterKey];
            });
            if (hasChildren) {
                let list: Array<any> = [];
                items.forEach((codeItem: any) => {
                    if (!codeItem[this.leafFilterKey]) {
                        let valueField: string = codeItem[this.showValue];
                        this.setChildCodeItems(valueField, items, codeItem);
                        list.push(codeItem);
                    }
                });
                this.treeData = list;
            }
        }
    }

    /**
     * 计算子类代码表
     *
     * @param {*} items
     * @memberof AppPickerMicroservice
     */
    public setChildCodeItems(pValue: string, result: Array<any>, codeItem: any) {
        result.forEach((item: any) => {
            if (item[this.leafFilterKey] && item[this.leafFilterKey] == pValue) {
                let valueField: string = item[this.showValue];
                this.setChildCodeItems(valueField, result, item);
                if (!codeItem.children) {
                    codeItem.children = [];
                }
                codeItem.children.push(item);
            }
        });
    }
}
</script>

<style lang="less">
@import './app-picker-microservice.less';
</style>
