layui.define(['globalTree'], function (exports) {
    class Cache extends Map {

        setComponent(component) {
            super.set(component.id, component);
        }

        getData(entityId, entityType) {
            let dataArr = [];
            for (let component of super.values()) {
                let {fixedLabelId, fixedTitlePath, fieldTitle, newLabel} = component, labelId = fixedLabelId,
                    label = fixedTitlePath;
                if (newLabel) {
                    labelId = newLabel.id;
                    label = newLabel.titlePathWithSelf;
                }
                if (label && label !== '/') {
                    label = label.endsWith("/") ? label.substring(0, label.length - 1) : label;
                    let temp = {
                        entityId,
                        entityType,
                        fieldTitle: component.isOther() ? '其他标签' : fieldTitle,
                        labelId,
                        label
                    }
                    dataArr.push(temp);
                }
            }
            return dataArr;
        }
    }

    class Component {
        constructor(cid, $elem) {
            this.id = cid;
            this.$elem = $elem;
            this.label = $elem.data();
            this.fieldTitle = this.label.fieldTitle || '';
            this.fixedLabelId = this.label.labelId;
            this.labelIdPath = this.label.labelIdPath;
            this.labelTitle = this.label.labelTitle || '';
            this.labelTitlePath = this.label.labelTitlePath || '';
            this.fixedTitlePath = this.labelTitlePath + this.labelTitle;
            this.fixedLabels = [];
            this.newLabel = null;
            this.newLabels = [];
        }

        isOther() {
            return this.$elem.hasClass('other-label');
        }

        isReadOnly() {
            return this.$elem.parent().hasClass('read-only') || this.$elem.hasClass('read-only');
        }

        render() {
            renderLabelElement(this);
        }

        setData(data) {
            if (data) {
                let path = data.label.replace(this.fixedTitlePath, '');
                if (path !== '/') {
                    this.newLabel = {id: data.labelId, titlePathWithSelf: path}
                }
                this.render();
            }
        }

        clear() {
            this.newLabel = null;
            this.newLabels = [];
            this.render();
        }

        delete() {
            this.$elem.remove();
        }
    }

    const _KEY = 'INDEX_', _CACHE = new Cache(), _ARROW = '<label class="arrow">></label>';

    /**
     * 渲染标签元素
     * @param component
     */
    function renderLabelElement(component) {
        let {$elem, label, newLabel, fixedLabelId, fixedTitlePath, fixedLabels, newLabels, labelIdPath} = component;
        let _html, labels, isFirst = !newLabel && fixedLabels.length === 0, data = newLabel || label,
            titlePath = newLabel ? data.titlePathWithSelf.replace(fixedTitlePath, '') : fixedTitlePath;
        newLabels = [];
        titlePath.split('/').forEach(function (item) {
            if (item) {
                newLabels.push(`<a class="label-type ${newLabel && !component.isReadOnly() ? 'new-data' : ''}">${item}</a>`)
            }
        });

        if (isFirst) {
            component.fixedLabels.push(...newLabels);
            newLabels = [];
        } else if (newLabel) {
            component.newLabels = newLabels;
        }
        labels = component.fixedLabels.concat(component.newLabels);
        if (!component.isReadOnly() && component.newLabels.length === 0) {
            labels.push('<a class="label-type" style="color: #d0d0d0;border-color: #d0d0d0">请选择标签</a>')
        }
        _html = (labels.length > 0 ? labels.join(_ARROW) : '')
        if (!component.isReadOnly()) {
            let clearBtnText = $elem.hasClass('other-label') ? '删除' : '重置';
            _html += `<a class="label-type choose-data" data-label-id="${fixedLabelId}">选择</a><a class="label-type clear-data" data-label-id="${fixedLabelId}">${clearBtnText}</a>`;
        }
        $elem.html('');
        $elem.append(_html)
        addEventListen()

        function addEventListen() {
            $elem.find('.choose-data').on('click', function () {
                let labelId = $(this).data('labelId') || 0;
                chooseLabelData(labelId, labelIdPath).then(data => {
                    component.newLabel = data;
                    renderLabelElement(component);
                });
            });
            $elem.find('.clear-data').on('click', function () {
                if (component.isOther()) {
                    component.delete();
                    _CACHE.delete(component.id)
                } else {
                    component.clear()
                    _CACHE.setComponent(component)
                }
            });
        }
    }

    /**
     * 显示置标标签选择窗口
     * @param labelId {String} 上级置标标签ID，为空则查询所有
     * @param idPath {String} 上级标签的id路径，用于默认勾选和设置为不可选
     * @param chooseIds {String | String[]} 默认选中的ID集合，逗号拼接的数组，或者字符数组
     * @param multiple {Boolean} 多选
     * @returns {Promise<Object>}
     */
    function chooseLabelData(labelId, idPath, chooseIds, multiple) {
        if (!labelId || labelId === 'undefined') {
            labelId = 0;
        }
        return new Promise(resolve => {
            layer.open({
                type: 1,
                title: '选择标签',
                content: `<div class="label-layer" style="width: 500px; height: 480px">
                        <div class="" style="padding: 5px 20px;">
                            <input type="text" id="labelFilterInput" class="layui-input" placeholder="输入关键词进行筛选" style="width: 400px">
                            <button type="button" class="layui-btn layui-btn-sm">筛选</button>
                        </div>
                        <div class="label-tree" id="label-tree" style="overflow: auto;"></div>
                        <div class="label-btns">
                            <button type="button" id="layerOk" class="layui-btn layui-btn-sm layui-btn-normal">确 定</button>
                            <button type="button" id="layerCancel" class="layui-btn layui-btn-sm layui-btn-primary">取 消</button>
                        </div>
                    </div>`,
                success: function (layerObj, index) {
                    let disableIds = !!idPath ? idPath.split('/').filter(id => id !== '') : [];
                    let treeObj = layui.globalTree.init({
                        id: 'label-tree',
                        url: `${ctx}/data-label/manager/api/tree/choose?typeId=${labelId}`,
                        all: true,
                        cache: true,
                        checkbar: true,
                        checkbarType: multiple ? 'self' : 'only',
                        scroll: '#label-tree',
                        done: function () {
                            let _chooseIds = [];
                            if (disableIds.length > 0) {
                                _chooseIds.concat(disableIds);
                                treeObj.setDisabledNodes(disableIds.join(','));
                            }
                            if (chooseIds) {
                                _chooseIds.concat(Array.isArray(chooseIds) ? chooseIds : chooseIds.split(','));
                            }
                            treeObj.chooseDataInit(disableIds.join(','));
                            $('#layerCancel').on('click', () => layer.close(index));
                            $('#layerOk').on('click', () => {
                                const nodes = treeObj.chooseNodes;
                                if (nodes && nodes.length > 0) {
                                    let return_data = nodes.map(node => node.basicData);
                                    if (!multiple) {
                                        resolve(return_data[0]);
                                    }
                                    resolve(return_data);
                                    layer.close(index);
                                } else {
                                    showErrorMsg('请选择一条数据')
                                }
                            })
                        },
                        checkbarFun: {
                            activeNode: null,
                            chooseBefore: function ($i, node) {
                                this.activeNode = node;
                                this.activeNode['checked'] = !$i.hasClass('dtree-theme-choose');
                                return true;
                            },
                            chooseDone: function (nodes) {
                                if (disableIds.length > 0) {
                                    treeObj.chooseDataInit(disableIds.join(','));
                                }
                                if (!multiple) {
                                    treeObj.chooseNodes = nodes;
                                } else {
                                    const {id, parentId, checked} = this.activeNode;
                                    if (checked) {
                                        // 判断父级节点，如果是选中状态，则模拟复选框单击事件，取消选中
                                        if (isChecked(parentId)) {
                                            treeObj.dtreeObj.clickNodeCheckbar(parentId);
                                        }
                                        // 获取下级节点集合，并遍历集合，如果是选中状态，则模拟复选框单击事件，取消选中
                                        const children = layui.globalTree.getChildParam(treeObj, id);
                                        for (const child of children) {
                                            if (isChecked(child.id)) {
                                                treeObj.dtreeObj.clickNodeCheckbar(child.id);
                                            }
                                        }
                                    }

                                    treeObj.chooseNodes = layui.globalTree.getCheckbarNodesParam("label-tree");
                                }

                                function isChecked(id) {
                                    return $(`.dtree-nav-checkbox-div[data-id="${id}"] i`).hasClass('dtree-theme-choose')
                                }
                            }
                        }
                    });
                    let $filterInput = $('#labelFilterInput');
                    $filterInput.on('keyup', function () {
                        let _this = this;
                        listenEnterKey(_this).then(() => {
                            treeObj.fuzzySearch($(_this).val());
                        })
                    })
                }
            });
        });
    }

    /**
     * 渲染置标分类标签组件
     */
    function renderLabelSetComponent() {
        $('.label-set-component').each(function (index) {
            let cid = _KEY + index,
                $elem = $(this),
                component = new Component(cid, $elem);

            component.render();
            _CACHE.setComponent(component);
        });
        $('#addOtherLabelBtn').on('click', function () {
            addOtherLabel()
        });
    }

    function addOtherLabel(value, readonly) {
        let template = `<div class="label-set-component other-label ${readonly ? 'read-only' : ''}" th:data-field-title="其他标签"></div>`;
        $('.other-label-item.layui-input-block').append(template);
        let cid = _KEY + _CACHE.size,
            component = new Component(cid, $('.label-set-component.other-label:last'));

        component.render();
        if (value) {
            component.setData(value);
            // 如果缓存中的组件没有值，则删除掉
            for (let item of _CACHE.values()) {
                if (item.isOther() && item.newLabel === null) {
                    item.delete();
                    _CACHE.delete(item.id);
                }
            }
        }
        _CACHE.setComponent(component);

    }

    function setData(dataArr = []) {
        for (let data of dataArr) {
            let find = false, readonly = false;
            for (let component of _CACHE.values()) {
                readonly = component.isReadOnly();
                if (data.fieldTitle !== '其他标签' && data.fieldTitle === component.fieldTitle) {
                    component.setData(data);
                    find = true;
                }
            }
            if (!find) {
                addOtherLabel(data, readonly);
            }
        }
    }


    renderLabelSetComponent();
    const _exports = {
        getData: (entityId, entityType) => _CACHE.getData(entityId, entityType),
        setData,
        openChooseDialog: chooseLabelData
    };
    exports('datalabel', _exports)
})
