<template>
    <el-row v-drag-stop-propagation
            class="drag-box"
            v-if="isInit"
            v-loading="loading_verify"
            element-loading-text="数据校验中"
    >
        <el-col class="drag-templateList" style="width: 300px">
            <el-divider>组件列表</el-divider>
            <draggable
                v-if="templateList.length"
                :list="templateList"
                :sort="false"
                :options="{animation: 200}"
                :group="{ name: 'contents', pull: repeat ? 'clone' : null, put: false }"
                :clone="cloneDog"
                @end="onContentEnd"
            >
                <transition-group>
                    <el-button v-for="item in templateList"
                               :key="item.type"
                               class="templateTypeItem"
                               icon="el-icon-rank"
                               :data-type="item.type"
                               :data-count="item.count || 0">
                        <span>{{ item.name }}</span>
                    </el-button>
                </transition-group>
            </draggable>
            <div v-if="templateList.length === 0" style="text-align: center">暂无可用模板</div>
            <el-divider style="margin: 12px 0;"></el-divider>
            <p style="color: #AAAAAA;text-align: center;">拖拽组件至中间使用</p>
        </el-col>

        <el-col class="drag-right" style="width:375px">
            <div v-if="$slots.tplTop" class="fix-top-content">
                <slot name="tplTop"></slot>
            </div>
            <draggable
                :list="contents"
                :sort="true"
                group="contents"
                class="drag-content"
                v-if="contents.length===0"
            >
                <div class="drag-empty">
                    <slot name="contentEmpty" v-if="$slots.contentEmpty"></slot>
                    <comp-empty v-else></comp-empty>
                </div>
            </draggable>
            <draggable
                :list="contents"
                :sort="true"
                :options="{animation: 200}"
                group="contents"
                filter=".ignore-elements"
                class="drag-content"
                @end="onContentEnd"
                v-else
            >
                <su-content-highlight-tip
                    ref="seContentHighlightTip"
                    :delay="0"
                    :glitter="false"
                    :block="true"
                    :class="{'ignore-elements':item.fixTop||item.fixBottom}"
                    v-for="(item, index) in contents"
                    :key="item.id"
                    :id="item.id"
                >
                    <div class="content-item"
                         @click="clickViewItem(item)">
                        <div
                            v-loading="item.show.mask"
                            element-loading-spinner="aaaa"
                            element-loading-background="rgba(0, 0, 0, 0.0)">
                            <component
                                :is="item.component.view"
                                width="100%"
                                :ref="'content' + item.id"
                                :options="item.options"
                                v-bind="item.attrs||{}"
                                @onEvent="(data)=>{onViewEvent(item,data)}"
                                v-on="item.listeners||{}"
                            />
                        </div>
                        <div class="right-button-wrap" v-if="!loading_verify">
                            <el-button
                                type="danger"
                                icon="el-icon-delete"
                                class="right-button"
                                circle
                                v-if="item.show.delete"
                                @click="(e)=>{delContent(e,item,index)}"
                                title="删除"
                            />
                            <el-button
                                icon="el-icon-arrow-up"
                                class="right-button"
                                circle
                                v-if="item.show.up && !item.fixTop && !item.fixBottom"
                                v-show="index > 0"
                                @click="(e)=>{movePrev(e,index)}"
                                title="上移"
                            />
                            <el-button
                                icon="el-icon-arrow-down"
                                class="right-button"
                                circle
                                v-if="item.show.down && !item.fixTop && !item.fixBottom"
                                v-show="index < contents.length - 1"
                                @click="(e)=>{moveNext(e,index)}"
                                title="下移"
                            />
                            <el-button
                                icon="el-icon-document-copy"
                                class="right-button"
                                circle
                                v-if="item.show.copy && !item.fixTop && !item.fixBottom"
                                @click="(e)=>{cloneRight(e,item, index)}"
                                title="复制"
                            />
                            <!-- @click="cloneRight(item, index)" -->
                        </div>
                    </div>
                </su-content-highlight-tip>
            </draggable>
            <div v-if="$slots.tplBottom" class="fix-bottom-content">
                <slot name="tplBottom"></slot>
            </div>

        </el-col>

        <el-col class="drag-edit" style="width: calc(100% - 675px);">
            <edit-item ref="editTabs" :tabs="tabs" :left-tab-name="(currentItem||{name:'组件属性'}).name"
                       :justActiveShow="justActiveShow">
                <component :is="currentItem.component.edit" :key="currentItem.id" :options="currentItem.options" @change="syncEditData" v-on="currentItem.listeners||{}"
                           ref="compEdit" slot="left"
                           v-if="currentItem"></component>
            </edit-item>
        </el-col>

    </el-row>
</template>

<script>
import DateUtil from "../../../util/pattern/date";
import * as ObjUtil from "../../../util/pattern/object";
import draggable from "vuedraggable";
import editItem from "./edit-item";
import seContentHighlightTip from "../../widget/su-content-highlight-tip";
import compEmpty from "./comp-empty"
import mixin from "../../mixin"
import LoggerUtil from "../../../util/monitor/logger";

let logger = LoggerUtil.getLogger("seDragTemplate02")
export default {
    name: "veDragTemplate",
    mixins: [mixin],
    components: {
        draggable,
        seContentHighlightTip,
        editItem,
        compEmpty,
    },
    directives: {
        "DragStopPropagation": {
            bind: function (el, binding, vnode) {
                el.ondrop = function (event) {
                    event.preventDefault();
                    event.stopPropagation();
                }
            }
        }
    },

    data() {
        return {
            isInit: false,
            loading_verify: false,
            // loading_mask: true,
            templateList: [],//原始模板数组
            contents: [],//拖拽后模板数组
            typeFrome: '',
            templates_bak: [],
            currentItem: null
        };
    },
    props: {
        templates: {
            type: Array,
            default() {
                return []
            }
        },
        repeat: {
            type: Boolean,
            default: true
        },
        contentWidth:{
            type:Number,
            width:375
        },
        tabs: {
            type: Array,
            default() {
                return []
            }
        },
        justActiveShow: {
            type: Boolean,
            default: false,
        },
        show: {
            type: Object,
            default() {
                return {delete: true, up: true, down: true, copy: true}
            }
        }
    },
    async created() {
        this.templates_bak = [...this.templates];
        await this.ready();
        this.typeTemplateMap = this.getTypeTemplate();
    },
    mounted() {
    },
    methods: {
        async ready() {
            return this.readyPromise = this.readyPromise || this._ready();
        },
        async _ready() {
            for (let i = 0; i < this.templates.length; i++) {
                let template = this.templates[i];
                this.templateList.push(await this.getTemplateItem(template));
            }
            this.isInit = true;
        },
        /**
         * @description: 右侧操作区带数据复制
         */
        async cloneRight(e, item, index) {
            e.stopPropagation();
            if (!this._checkClone(item)) {
                return;
            }
            await this.syncEditData();
            let itemData = await this.getItemViewData(item);
            let copyItem = this.getTemplateItemSync(item);
            this.contents.splice(index + 1, 0, copyItem);
            await this.setItemViewData(copyItem, itemData)
        },
        /**
         * 初始化数据
         */
        async initData(data) {
            await this.ready();
            data = ObjUtil.copy(data || {});
            let {templates = []} = data;
            let editTabRef = await this.getEditTabRef();
            await editTabRef.initTabsData(data);

            let contents = [];
            for (let i = 0; i < templates.length; i++) {
                let item = templates[i];
                contents.push(this.getTemplateItemSync(this.typeTemplateMap[item.type]));
            }
            this.contents = contents;
            for (let i = 0; i < contents.length; i++) {
                let item = contents[i];
                this.removeTemplate(item.type);
                await this.setItemViewData(item, templates[i].data)
            }
        },

        removeTemplate(type) {
            if (!this.repeat)
                for (let i = 0; i < this.templateList.length; i++) {
                    if (this.templateList[i].type == type) {
                        this.templateList.splice(i, 1);
                        return;
                    }
                }
        },
        addTemplate(type) {
            if (!this.repeat)
                for (let i = 0; i < this.templates_bak.length; i++) {
                    let item = this.templates_bak[i];
                    if (item.type == type) {
                        this.templateList.push(item);
                        return;
                    }
                }
        },
        getTypeTemplate() {
            let map = {};
            for (let i = 0; i < this.templateList.length; i++) {
                let item = this.templateList[i];
                map[item.type] = item;
            }
            return map;
        },
        // 检查是否可以复制
        _checkClone(item) {
            let hasItemSize = this.contents.filter(function (m) {
                return item.type === m.type;
            }).length;
            let max = item.max || 999;
            if (max > hasItemSize) {
                return true;
            } else {
                this.$message.error(`该组件最多只能添加${max}个`);
                return false;
            }
        },
        cloneDog(item) {
            this.typeFrome = item.type;
            if (this._checkClone(item)) {
                let newItem = this.getTemplateItemSync(item);
                return newItem;
            }
            // console.log(newItem,newItem.id)
        },
        // moveDog (e) {
        //   let size = e.draggedContext.element.size
        //   let num = this.contents.filter(item => {
        //     return item.type === e.draggedContext.element.type
        //   }).length
        //   if (num >= size) {
        //     // this.$message.error('该组件只能添加一次')
        //     return false
        //   }
        // },
        // onEnd(e) {
        //     let item = this.templateList.filter(item => {
        //                 return item.type === e.item.dataset.type
        //               })[0];
        //     if(item.fixTop && this.contents.length>1){//置顶
        //         console.log("已强制置顶！");
        //         this.contents.unshift(this.contents.splice(e.newDraggableIndex, 1)[0]);
        //     }
        //     if(item.fixBottom && this.contents.length>1){//置底
        //         console.log("已强制置底！");
        //         this.contents.push(this.contents.splice(e.newDraggableIndex, 1)[0]);
        //     }
        // },
        onContentEnd(e) {
            let fixTopIndex = -1;
            let fixBottomIndex = -1;
            this.contents.forEach(function (item, index) {
                if (item.fixTop) {
                    fixTopIndex = index;
                }
                if (item.fixBottom) {
                    fixBottomIndex = index;
                }
            })
            if (fixTopIndex > -1) {
                console.log("已强制置顶！");
                this.contents.unshift(this.contents.splice(fixTopIndex, 1)[0]);
            }
            if (fixBottomIndex > -1) {
                console.log("已强制置底！");
                this.contents.push(this.contents.splice(fixBottomIndex, 1)[0]);
            }
        },
        async delContent(e, item, index) {
            e.stopPropagation();
            if (this.currentItem === item) {
                this.currentItem = null;
                let ref = await this.getEditTabRef();
                ref.showRight();
            }
            this.addTemplate(item.type);
            this.contents.splice(index, 1);
        },
        movePrev(e, index) {
            e.stopPropagation();
            if (index > 0 && this.contents[index - 1].fixTop) {
                this.$message.warning('无法上移,上层组件已置顶！');
                return;
            }
            this.contents.splice(index - 1, 0, ...this.contents.splice(index, 1))
        },
        moveNext(e, index) {
            e.stopPropagation();
            if (this.contents[index + 1].fixBottom) {
                this.$message.warning('无法下移,下层组件已置底！');
                return;
            }
            this.contents.splice(index + 1, 0, ...this.contents.splice(index, 1))
        },
        /**
         * verfiy({templates:false,tabs:true})
         * verfiy({templates:false,templatesMode:'current|all',tabs:true})
         * verfiy({templates:true,tabs:false})
         * verfiy({templates:false,tabs:{home:true}})
         */
        async verify(ops) {
            let {templates = true, tabs = true, templatesMode = "all"} = ops || {};
            this.loading_verify = true;
            await this.syncEditData();
            if (templates) {
                if(templatesMode==='current' && this.currentItem){
                    let ref = await this.getEditRef();
                    let bool = await ref.verify();
                    if (!bool) {
                        this.loading_verify = false;
                        return false;
                    }
                }
                if(templatesMode === 'all'){
                    for (let i = 0; i < this.contents.length; i++) {
                        let item = this.contents[i];
                        await this.clickViewItem(item);
                        let ref = await this.getEditRef();
                        let bool = await ref.verify();
                        if (!bool) {
                            this.loading_verify = false;
                            return false;
                        }
                    }
                }
            }
            if (tabs === false) {
                return true;
            }
            if (tabs === true) {
                tabs = null;
            }
            let editTabRef = await this.getEditTabRef();
            let bool = await editTabRef.verifyTabs(tabs);
            this.loading_verify = false;
            return bool;
        },
        /**
         * 获取模板数据
         */
        async getData(ops) {
            let {templates = true, tabs = true} = ops || {};
            await this.syncEditData();
            let data={};
            if(templates){
                let templatesData = [];
                for (let i = 0; i < this.contents.length; i++) {
                    let item = this.contents[i];
                    templatesData.push({
                        type: item.type,
                        data: await this.getItemViewData(item)
                    });
                }
                data.templates = templatesData;
            }
            if(tabs){
                let editTabRef = await this.getEditTabRef();
                let tabData = await editTabRef.getTabsData();
               // logger.log(`获取tab区域编辑数据`, tabData);
                Object.assign(data,tabData);
            }
            return data;
        },

        async getTemplateItem(item) {
            async function getComponent(item) {
                if (typeof item.component === 'function') {
                    let comp = await item.component();
                    return comp.default || comp;
                }
                return item.component;
            }

            return {
                ...this.getTemplateItemSync(item),
                component: await getComponent(item)
            }
        },
        getTemplateItemSync(item) {
            item.show = item.show || {};
            if (item.fixTop || item.fixBottom) {
                item.max = 1;
            }
            return {
                ...item,
                show: {
                    delete: this.show.delete !== false && item.show.delete !== false,
                    up: this.show.delete !== false && item.show.up !== false,
                    down: this.show.delete !== false && item.show.down !== false,
                    copy: this.show.delete !== false && item.show.copy !== false,
                    mask: this.show.mask !== false && item.show.mask !== false,
                },
                isSelect: false,
                id: DateUtil.getUUID(),
            }
        },
        async getItemViewData(item) {
            let ref = await this.getItemRef(item);
            let data = ObjUtil.copy(await ref.getData());
            // logger.log(`获取[${item.name}-${item.type}-${item.id}] > view数据`, data);
            return data;
        },
        async setItemViewData(item, data) {
            let ref = await this.getItemRef(item);
            ref.initData(data);
        },
        async syncEditData() {
            if (this.currentItem) {
                let compEdit = await this.getEditRef();
                let data = ObjUtil.copy(await compEdit.getData());
                let ref = await this.getItemRef(this.currentItem);
                ref.initData(data);
               //  logger.log(`同步[${this.currentItem.name}-${this.currentItem.type}-${this.currentItem.id}] > edit到view`, data);
            }
        },
        async getItemRef(item) {
            return await this.getRef('content' + item.id);
        },
        async getEditRef() {
            return await this.getRef('compEdit');
        },
        async getEditTabRef() {
            return await this.getRef('editTabs');
        },
        async showTab(tabName) {
            let ref = await this.getEditTabRef();
            ref.showRight(tabName);
            return await ref.getTabRef(tabName);
        },
        /**
         * 点击某个视图模板组件
         * @param item
         * @returns {Promise<void>}
         */
        async clickViewItem(item) {
            if (this.currentItem === item) {
                let ref = await this.getEditTabRef();
                ref.showLeft();
                return;
            }
            if (this.currentItem) {
                this.currentItem.isSelect = false;
                await this.syncEditData();
                this.getSeContentHighlightTipRef(this.currentItem).stopTip();
            }
            this.currentItem = item;
            this.currentItem.isSelect = true;
            this.getSeContentHighlightTipRef(this.currentItem).startTip();
            let data = await this.getItemViewData(item);
            let compEdit = await this.getEditRef();
            await compEdit.initData(data);
            // logger.log(`设置[${item.name}-${item.type}-${item.id}] > edit数据`, data);
            compEdit._isInitDataDone = true;
            let ref = await this.getEditTabRef();
            ref.showLeft();
        },
        /**
         * 某个视图模板组件 向外派发事件
         * @param item
         * @param data
         * @returns {Promise<void>}
         */
        async onViewEvent(item, data) {
            let compEdit = await this.getEditRef();
            let timer = setInterval(function () {
                if (compEdit._isInitDataDone) {
                    clearInterval(timer);
                    compEdit.onEvent && compEdit.onEvent(data);
                }
            }, 50);
        },
        getSeContentHighlightTipRef(item) {
            for (let i = 0; i < this.$refs.seContentHighlightTip.length; i++) {
                let ref = this.$refs.seContentHighlightTip[i];
                if (ref.$attrs.id === item.id) {
                    return ref;
                }
            }
        }
    }
};

</script>

<style lang="less" scoped>
/deep/
.el-loading-mask {
    z-index: 1000;
}

@import "./style.less";
</style>
