/* Essentials YOOtheme Pro 2.2.16 build 0813.1608; ZOOlanders https://www.zoolanders.com; Copyright (C) Joolanders, SL; http://www.gnu.org/licenses/gpl.html GNU/GPL */

import Vue from 'vue';
import { $, addClass, on } from 'uikit-util';
import { EditorState } from '@codemirror/state';
import WidgetType from '../WidgetType';
import {
    composed,
    // widgetHoverIn,
    // widgetHoverOut,
} from '../state';
import { Decoration, EditorView, MatchDecorator, ViewPlugin } from '@codemirror/view';
import ConditionWidgetComponent from './ConditionWidget.vue';
import ConditionWidgetDropdown from './ConditionWidgetDropdown.vue';

let activeGroup;

const widgets = {};

class ConditionWidget extends WidgetType {
    constructor({ group, type, range }) {
        super({ range });

        this.id = `${type}.${group}`;
        this.type = type;
        this.group = group;
        this.literal = `{{ ${type} conditions.${group} }}`;
        this.isCondition = true;

        widgets[this.id] = this;
    }
    toDOM(view) {
        const wrap = this.createWrapperDom(view);
        const { vm, conditions } = view.state.field(composed);

        addClass(wrap, 'uk-button-primary');

        this.vm = new Vue({
            parent: vm,
            el: wrap.appendChild($('<span/>')),
            extends: ConditionWidgetComponent,
            propsData: { type: this.type, value: conditions[this.group] },
        });

        return (this.dom = wrap);
    }
    showdrop() {
        const { vm, conditions } = this.view.state.field(composed);

        this.drop = vm.$dropdown(ConditionWidgetDropdown, {
            values: conditions[this.group],
        });

        const off = on(this.drop.$el, 'hide', () => {
            if (activeGroup === this.group) {
                this.blur();
                activeGroup = null;
            }

            off();
        });

        const target = vm.$el;

        this.drop.show(target, {
            classes: 'yo-dropdown',
            boundaryX: target.closest('.yo-sidebar-fields > *') || target,
        });
    }
    focus() {
        const groupWidgets = Object.values(widgets).filter((w) => w.group === this.group);

        groupWidgets.forEach((w) => {
            addClass(w.dom, 'uk-active');
        });

        if (!activeGroup) {
            this.showdrop();
            activeGroup = this.group;
        }
    }
    remove() {
        const groupWidgets = Object.values(widgets).filter((w) => w.group === this.group);

        this.view.dispatch({
            changes: groupWidgets.map((w) => ({ ...w.range, insert: '' })),
            selection: { anchor: groupWidgets[0].range.from },
        });

        this.view.focus();
    }
    destroy() {
        super.destroy();
        this.vm.$destroy();

        delete widgets[this.id];
    }
}

const IfMatcher = new MatchDecorator({
    regexp: /\{\{ (\/?if|else) conditions\.(\w{4}) \}\}/g,
    decoration: (match, view, pos) =>
        Decoration.replace({
            widget: new ConditionWidget({
                type: match[1],
                group: match[2],
                range: {
                    from: pos,
                    to: pos + match[0].length,
                },
            }),
        }),
});

// cancel transition if widget is droped in an invalid position
const validateWidgetsPositions = EditorState.transactionFilter.of((tr) => {
    const { conditions } = tr.state.field(composed);
    const doc = tr.newDoc.toString();

    for (const id in conditions) {
        const pos = getWidgetsPositions(id, doc);

        if (
            (pos.if && pos['/if'] && pos.if.from > pos['/if'].from) ||
            (pos.else && pos.if.from > pos.else.from) ||
            (pos.else && pos['/if'].from < pos.else.from)
        ) {
            return false;
        }
    }

    return [tr];
});

// const higlightActiveGroup = EditorState.transactionFilter.of((tr) => {
//     const doc = tr.newDoc.toString();
//     const active = tr.state.field(activeWidget);

//     if (active) {
//         const pos = getWidgetsPositions(active.group, doc);

//         return [
//             tr,
//             {
//                 effects: [addHighlight.of({ from: pos.if.from, to: pos['/if'].to })],
//                 sequential: true,
//             },
//         ];
//     } else {
//         return [
//             tr,
//             {
//                 effects: removeHighlight.of({ from: 0, to: doc.toString().length }),
//                 sequential: true,
//             },
//         ];
//     }
// });

// const handleWidgetState = EditorState.transactionFilter.of((tr) => {
//     const widgetHoveredIn = tr.effects.find((e) => e.is(widgetHoverIn))?.value;
//     const widgetHoveredOut = tr.effects.find((e) => e.is(widgetHoverOut))?.value;
//     const removed = tr.effects.find((e) => e.is(removeWidget))?.value;

//     const active = tr.startState.field(activeWidget);
//     const activated = tr.effects.find((e) => e.is(setActiveWidget))?.value;

//     // if (widgetHoveredIn) {
//     //     const groupWidgets = Object.values(widgets).filter(
//     //         (w) => w.group === widgetHoveredIn.group
//     //     );

//     //     groupWidgets.forEach((w) => {
//     //         addClass(w.dom, 'uk-active');
//     //     });
//     // }

//     // if (widgetHoveredOut && widgetHoveredOut.group !== active?.group) {
//     //     const groupWidgets = Object.values(widgets).filter(
//     //         (w) => w.group === widgetHoveredOut.group
//     //     );

//     //     groupWidgets.forEach((w) => {
//     //         removeClass(w.dom, 'uk-active');
//     //     });
//     // }

//     return [tr];
// });

export default ViewPlugin.fromClass(
    class {
        drop;
        decorations;
        constructor(view) {
            this.decorations = IfMatcher.createDeco(view);
        }
        update(update) {
            this.decorations = IfMatcher.updateDeco(update, this.decorations);
        }
    },
    {
        decorations: (v) => v.decorations,
        provide: (plugin) => [
            EditorView.atomicRanges.of((view) => {
                return view.plugin(plugin)?.decorations || Decoration.none;
            }),
            validateWidgetsPositions,
            // higlightActiveGroup,
            // cancelCursorDraw,
        ],
    }
);

function getWidgetsPositions(id, doc) {
    const pos = {};
    const types = ['if', 'else', '/if'];

    types.forEach((type) => {
        const literal = `{{ ${type} conditions.${id} }}`;
        const fromIndex = doc.indexOf(literal);

        if (fromIndex !== -1) {
            pos[type] = {
                from: fromIndex,
                to: fromIndex + literal.length,
            };
        }
    });

    return pos;
}
