import Vue from 'vue/dist/vue'
import EventBus from '../util/EventBus';
import EventTypes from '../util/EventTypes';
import BuilderClient from '../api/BuilderClient';

// import DrawerComponent from '../components/drawer';
// var DrawerComponentClass = Vue.extend(DrawerComponent)

import TreeHandler from '../util/TreeHandler';
import {triggerFlashNotification} from "../../flashbag_notification";

Vue.component('brick-builder', {
    props: [
        'rootBrick',
        'context',
    ],
    data: function () {
        return {
            hoveredPath: [],
            // drawerComponent: new DrawerComponentClass(),
            // drawerComponent: new DrawerComponentClass(),
            // drawerComponent: 'brick-drawer',
            treeHandler: TreeHandler,
            drawerState: {
                title: '',
                html: '',
                errors: [],
                loading: true,
                visible: false,
            },
            selectedTabIndex: 0,
        };
    },
    methods: {
        handleMouseEnter(brickComp) {
            this.hoveredPath.map(el => el.isHovered = false);
            this.hoveredPath.push(brickComp);
            brickComp.isHovered = true;
        },
        handleMouseLeave(brickComp) {
            this.hoveredPath.map(el => el.isHovered = false);
            var found = this.hoveredPath.find((el) => el.brick.id === brickComp.brick.id);
            var foundIndex = this.hoveredPath.indexOf(found);
            if (foundIndex !== -1) {
                this.hoveredPath.splice(foundIndex, 1);
            }
            if (this.hoveredPath.length) {
                this.hoveredPath[this.hoveredPath.length - 1].isHovered = true;
            }
        },
        handleAdd(brickComp) {
            brickComp.beginLoading();
            BuilderClient
                .addBrick(brickComp.brick.id, brickComp.selectedBrickType, brickComp.selectedLayout)
                .then((json) => {
                    if (json.status === true && json.brick) {
                        var found = this.treeHandler.findBrick(brickComp.brick, this.rootBrick)
                        if (found === false) {
                            return false;
                        }

                        var preparedBrick = TreeHandler.prepareTree(json.brick);
                        found.children.push(preparedBrick);

                        brickComp.finishLoading();
                        brickComp.hide();

                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }
                });
        },
        handleDelete(brickComp) {
            brickComp.beginLoading();
            BuilderClient
                .deleteBrick(brickComp.brick.id)
                .then((json) => {
                    if (json.status === true) {
                        var parentBrick = this.treeHandler.findBrickParent(brickComp.brick, this.rootBrick);
                        if (parent) {
                            this.treeHandler.removeBrickChild(parentBrick, brickComp.brick)
                        }
                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }

                    brickComp.finishLoading();
                });
        },
        handleUpdate(brickComp) {
            EventBus.emitEvent(EventTypes.DRAWER_LOADING_START);
            EventBus.emitEvent(EventTypes.DRAWER_TOGGLE, brickComp.brick.vueComponent.$el.getBoundingClientRect().top);

            BuilderClient
                .updateBrickForm(brickComp.brick.id)
                .then((json) => {
                    EventBus.emitEvent(EventTypes.DRAWER_LOADING_FINISH);

                    EventBus.emitEvent(EventTypes.DRAWER_SET_DATA, {
                        title: json.title,
                        html: json.html,
                        errors: json.errors,// TODO: pass errors / messages to front
                        operation: 'update',
                        extra: {
                            brick: brickComp.brick,
                        },
                    });
                });
        },
        handleDuplicate(brickComp) {
            brickComp.beginLoading();

            BuilderClient
                .duplicateBrick(brickComp.brick.id)
                .then((json) => {
                    if (json.status === true) {
                        var found = this.treeHandler.findBrickParent(brickComp.brick, this.rootBrick)
                        if (found === false) {
                            return false;
                        }

                        var preparedBrick = TreeHandler.prepareTree(json.brick);
                        found.children.push(preparedBrick);

                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }

                    brickComp.finishLoading();
                });
        },
        handleDragStart(brickComp, event) {
            var fromParentComp = event.from.__vue__.$parent;
            var brick = fromParentComp.brick.children[event.oldIndex];

            // enable drop zones
            TreeHandler
                .filter(this.rootBrick, (b) => {
                    return b.allowedChildren.indexOf(brick.type) !== -1;
                })
                .map((brick) => {
                    brick.canReceiveCurrentDrag = true;
                })
            ;
        },
        handleDragEnd(brickComp, event) {
            var toParentComp = event.to.__vue__.$parent;
            var fromParentComp = event.from.__vue__.$parent;
            var brick = toParentComp.brick.children[event.newIndex];

            // disable drop zones
            TreeHandler
                .filter(this.rootBrick, (b) => {
                    return b.canReceiveCurrentDrag === true
                })
                .map((brick) => {
                    brick.canReceiveCurrentDrag = false;
                });

            var eventType = event.type;
            // 'update' for sorting, 'add' for dragging across lists
            if (toParentComp.brick.id === fromParentComp.brick.id) {
                eventType = 'sorting';
            } else {
                eventType = 'moving';
            }

            var promise = BuilderClient
                .dragBrick(brick.id, toParentComp.brick.id, eventType, event.newIndex)
                .then((json) => {
                    if (json.status === true) {
                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }
                });
        },
        handleDragMove(brickComp, event) {
            // could be used to cancel dragging - snapping. if returned false, drag 'move' is canceled
            // https://github.com/SortableJS/Vue.Draggable
        },
        getBrick(id) {
            console.log(this.rootBrick)
            var matched = this.treeHandler.filter(this.rootBrick, (b) => {
                return b.id == id;
            });
            if (matched) {
                return matched[0];
            }
        },
        visualizeInTree(btnComp) {
            var brick = btnComp.brick;
            EventBus.emitEvent(EventTypes.SELECT_TAB, 0);
            brick.vueComponent.flash();
        },
        handleTemplateCreate(brickComp) {
            var templateName = prompt("Nom de votre template");
            if (!templateName) {
                brickComp.$el.innerHTML = '<i class="far fa-floppy-disk"></i>';
                return;
            }

            var data = new FormData();
            data.append('name', templateName);

            brickComp.beginLoading();
            BuilderClient
                .templateBrick(brickComp.brick.id, data)
                .then((json) => {
                    if (json.status === true) {
                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }

                    brickComp.finishLoading();
                });
        },
        handleNotification(type, message) {
            triggerFlashNotification(type, message);
        },
        handleTemplateAdd(brickComp) {
            brickComp.beginLoading();
            BuilderClient
                .duplicateBrick(brickComp.selectedTemplate, [
                    {
                        key: 'rootBrickId',
                        value: brickComp.builder.rootBrick.id,
                    }
                ])
                .then((json) => {
                    if (json.status) {
                        var preparedBrick = TreeHandler.prepareTree(json.brick);
                        brickComp.builder.rootBrick.children.push(preparedBrick);

                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }

                    brickComp.finishLoading();
                    brickComp.hide();
                });
        },
        handleLayoutUpdate(brickComp) {
            brickComp.beginLoading();
            var data = new FormData();
            data.append('layout', brickComp.selectedLayout);

            BuilderClient
                .updateLayoutBrick(brickComp.brick.id, data)
                .then((json) => {
                    if (json.status === true) {
                        var oldBrick = TreeHandler.findBrick(brickComp.brick, brickComp.builder.rootBrick);
                        if (oldBrick === false) {
                            return false;
                        }
                        oldBrick.children.push(TreeHandler.prepareTree(json.brick));
                        TreeHandler.removeBrickChild(oldBrick, json.brick)

                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }

                    brickComp.finishLoading();
                    brickComp.hide();
                });
        },
        handleTemplateDelete(brickComp) {
            brickComp.beginLoading();
            BuilderClient
                .deleteBrick(brickComp.selectedTemplate)
                .then((json) => {
                    if (json.status) {
                        this.handleNotification('success', json.message);
                    } else {
                        this.handleNotification('error', json.message);
                    }

                    brickComp.finishLoading();
                    brickComp.hide();
                });
        },
    },
    mounted() {
        // brick hover
        EventBus.$on(EventTypes.BRICK_MOUSEENTER, this.handleMouseEnter);
        EventBus.$on(EventTypes.BRICK_MOUSELEAVE, this.handleMouseLeave);

        // brick actions
        EventBus.$on(EventTypes.BRICK_ADD, this.handleAdd);
        EventBus.$on(EventTypes.BRICK_DELETE, this.handleDelete);
        EventBus.$on(EventTypes.BRICK_UPDATE, this.handleUpdate);
        EventBus.$on(EventTypes.BRICK_DUPLICATE, this.handleDuplicate);
        EventBus.$on(EventTypes.BRICK_VISUALIZE_IN_TREE, this.visualizeInTree);
        EventBus.$on(EventTypes.BRICK_TEMPLATE_CREATE, this.handleTemplateCreate);
        EventBus.$on(EventTypes.BRICK_TEMPLATE_ADD, this.handleTemplateAdd);
        EventBus.$on(EventTypes.BRICK_LAYOUT_UPDATE, this.handleLayoutUpdate);
        EventBus.$on(EventTypes.BRICK_TEMPLATE_DELETE, this.handleTemplateDelete);

        // drag & drop
        EventBus.$on(EventTypes.BRICK_DRAG_START, this.handleDragStart);
        EventBus.$on(EventTypes.BRICK_DRAG_MOVE, this.handleDragMove);
        EventBus.$on(EventTypes.BRICK_DRAG_END, this.handleDragEnd);
    },
    template: `
      <div class="d-flex flex-column align-items-center">
        <brick-tree
            :root-brick='rootBrick'
            :builder='this'
        ></brick-tree>
        <brick-drawer
            :state='drawerState'
            :builder='this'
        ></brick-drawer>
        <brick-layout-update
            :builder='this'
        ></brick-layout-update>
      </div>
    `,
});