/* ===================== AUTOGENERATED SOURCE IMPORT ===================== */

import Template from "/emcJS/util/html/template/HTMLTemplate.js";

const TPL = new Template(`
    <slot id="logic-container">
        <button id="droptarget" class="placeholder" title="Add element">...</button>
    </slot>
    <emc-form-row class="footer" align="end">
        <emc-button id="optimize" text="Optimize logic"></emc-button>
        <emc-button id="json" text="JSON"></emc-button>
    </emc-form-row>
    
`);

import GlobalStyle from "/emcJS/util/html/template/CSSTemplate.js";

const STYLE = new GlobalStyle(`
    * {
        position: relative;
        box-sizing: border-box;
    }
    
    #field {
        flex-direction: column;
        min-height: 200px;
        max-height: 60dvh;
        background-color: var(--input-back-color, #ffffff);
        background-image: var(--input-back-image, none);
        border-style: solid;
        border-width: var(--input-border-width, 2px);
        border-color: var(--input-border-color, #222222);
        border-radius: var(--input-border-radius, 6px);
        user-select: none;
        overflow: hidden;
    }
    
    :host(:disabled) #field {
        color: var(--input-disabled-text-color, #757575) !important;
        background-color: var(--input-disabled-back-color, #999999) !important;
        background-image: var(--input-disabled-back-image, none) !important;
        border-color: var(--input-disabled-border-color, #6a6a6a) !important;
        cursor: default !important;
        opacity: 1 !important;
    }
    
    :host(:focus) #field,
    :host(:focus-within) #field {
        outline: none;
    }
    
    :host(:invalid) #field {
        color: var(--input-invalid-text-color, #000000);
        background-color: var(--input-invalid-back-color, #ffebeb);
        background-image: var(--input-invalid-back-image, none);
        border-color: var(--input-invalid-border-color, #ff4444);
    }
    
    .placeholder {
        display: table;
        margin: 5px;
        padding: 5px 20px;
        color: var(--button-text-color, #000000);
        background-color: var(--button-back-color, #cccccc);
        background-image: var(--button-back-image, none);
        border-style: solid;
        border-width: var(--input-border-width, 2px);
        border-color: var(--input-border-color, #222222);
        border-radius: var(--input-border-radius, 6px);
        font-weight: bold;
        cursor: pointer;
    }
    
    .placeholder:hover {
        color: var(--button-hover-text-color, #ffffff);
        background-color: var(--button-hover-back-color, #000000);
        background-image: var(--button-back-image, none);
    }
    
    .placeholder:disabled {
        color: var(--input-disabled-text-color, #757575);
        background-color: var(--button-disabled-back-color, #999999);
        background-image: var(--button-disabled-image, none);
        pointer-events: none;
    }
    
    .placeholder:focus {
        box-shadow: 0 0 2px 2px var(--button-focus-color, #06b5ff);
        outline: none;
    }
    
    #logic-container {
        display: block;
        flex: 1;
        padding: 5px;
        overflow-y: auto;
        overflow-x: hidden;
        font-size: 12px;
    }
    
    :host(:disabled) ::slotted(*) {
        opacity: 0.3;
    }
    
    .footer {
        display: flex;
        padding: 5px;
        border-top: solid var(--form-border-width, 2px) var(--form-border-color, #000000);
    }
    
    :host(:invalid) .footer {
        border-top-color: var(--input-invalid-border-color, #ff4444);
    }
    
    :host(:disabled) .footer {
        border-top-color: var(--input-disabled-border-color, #6a6a6a) !important;
    }
    
    #optimize,
    #json {
        min-width: 100px;
        margin: 0px 0px 0px 10px;
    }
    
    :host([readonly]:not([readonly="false"])) #optimize {
        display: none;
    }
    
`);

/* ======================================================================= */

import AbstractFormElement from "../../AbstractFormElement.js";
import FormElementRegistry from "../../../../../data/registry/form/FormElementRegistry.js";
import DragDropMemory from "../../../../../data/DragDropMemory.js";
import ContextMenuManagerMixin from "../../../../mixin/ContextMenuManagerMixin.js";
import {mix} from "../../../../../util/Mixin.js";
import {reduceLogic} from "../../../../../util/logic/LogicReducer.js";
import {registerFocusable} from "../../../../../util/helper/html/ElementFocusHelper.js";
import LogicEditorContextMenuElement from "./components/contexmenu/LogicEditorContextMenuElement.js";
import LogicElementModal from "./components/modal/LogicElementModal.js";
import LogicJSONModal from "./components/modal/LogicJSONModal.js";
import LogicAbstractElement from "../../../../logic/abstract/AbstractElement.js";
import "../../../FormRow.js";
import "../../../button/Button.js";
import "../../../../logic/DefaultElementsLoader.js";

// TODO add import/export (button opens dialog to copy/paste logic)
// TODO add optimize button (optimize logic e.g. merge contained AND with parent AND)
// TODO add negate function to contextmenu (add optional negation readonly property to logic elements)
// TODO detect valid logic (no empty elements that expect children)

const MUTATION_CONFIG = {
    childList: true,
    subtree: true
};

const mutationObserver = new MutationObserver((mutationsList) => {
    for (const mutation of mutationsList) {
        if (mutation.type == "childList") {
            const target = mutation.target.closest("emc-input-logic");
            const el = target.children[0];
            if (el) {
                target.value = el.toJSON();
            } else {
                target.value = null;
            }
        }
    }
});

const BaseClass = mix(
    AbstractFormElement
).with(
    ContextMenuManagerMixin
);

// TODO use modal handler
export default class LogicInput extends BaseClass {

    static get changeDebounceTime() {
        return 0;
    }

    #optimizeButtonEl;

    #jsonButtonEl;

    #placeholderEl;

    #logicElementModal = new LogicElementModal();

    #logicJSONModal = new LogicJSONModal();

    constructor() {
        super();
        this.shadowRoot.getElementById("field").append(TPL.generate());
        STYLE.apply(this.shadowRoot);
        /* --- */
        this.setContextMenu("element", LogicEditorContextMenuElement);
        this.addContextMenuHandler("element", "remove", (event) => {
            const {id} = event.props[0];
            this.#removeElement(id);
        });
        this.addEventListener("menu", (event) => {
            const {id} = event;
            this.showContextMenu("element", event, {id});
            event.stopPropagation();
        });
        /* --- */
        mutationObserver.observe(this, MUTATION_CONFIG);
        this.#optimizeButtonEl = this.shadowRoot.getElementById("optimize");
        this.#jsonButtonEl = this.shadowRoot.getElementById("json");
        this.#placeholderEl = this.shadowRoot.getElementById("droptarget");
        this.#placeholderEl.ondragover = (event) => {
            event.preventDefault();
            event.stopPropagation();
            return false;
        };
        this.#placeholderEl.ondrop = (event) => {
            const els = DragDropMemory.get();
            if (els.length) {
                const el = els[0];
                if (el) {
                    const ne = event.target.getRootNode().host.append(el.getElement(event.ctrlKey));
                    if (ne) {
                        ne.removeAttribute("slot");
                    }
                }
            }
            event.preventDefault();
            event.stopPropagation();
            return false;
        };
        this.#placeholderEl.addEventListener("click", (event) => {
            const e = new Event("placeholderclicked");
            this.dispatchEvent(e);
            event.stopPropagation();
        });
        this.#optimizeButtonEl.addEventListener("click", (event) => {
            this.value = reduceLogic(this.value);
            event.stopPropagation();
        });
        this.#jsonButtonEl.addEventListener("click", (event) => {
            this.#logicJSONModal.value = this.value;
            this.#logicJSONModal.show(this.readonly);
            event.stopPropagation();
        });
        this.#logicJSONModal.addEventListener("submit", () => {
            this.value = this.#logicJSONModal.value;
        });
        this.addEventListener("click", (event) => {
            event.stopImmediatePropagation();
            event.preventDefault();
            const targetEl = event.target;
            setTimeout(() => {
                if (targetEl instanceof LogicAbstractElement) {
                    targetEl.focus();
                } else {
                    const firstEl = this.children[0] ?? this.#placeholderEl;
                    firstEl.focus();
                }
            }, 0);
        });
        /* --- */
        this.addEventListener("placeholderclicked", (event) => {
            if (this.#logicElementModal != null) {
                const targetEl = event.target;
                const slotName = event.name;
                this.#logicElementModal.onsubmit = (event) => {
                    const resultEl = event.element;
                    if (slotName) {
                        resultEl.setAttribute("slot", slotName);
                    }
                    targetEl.append(resultEl);
                    resultEl.focus();
                };
                this.#logicElementModal.show();
            }
        });
        this.addEventListener("valuechange", (event) => {
            event.stopPropagation();
            const el = this.children[0];
            if (el) {
                this.value = el.toJSON();
            } else {
                this.value = null;
            }
        });
    }

    formDisabledCallback(disabled) {
        super.formDisabledCallback(disabled);
        this.#optimizeButtonEl.disabled = disabled;
        this.#jsonButtonEl.disabled = disabled;
        this.#placeholderEl.disabled = disabled;
        const el = this.children[0];
        if (el) {
            return el.disabled = disabled;
        }
    }

    focus(options) {
        const el = this.children[0];
        if (el) {
            el.focus(options);
        } else {
            this.#placeholderEl.focus(options);
        }
    }

    addOperatorGroup(...groupList) {
        this.#logicElementModal?.addOperatorGroup(...groupList);
    }

    removeOperatorGroup(...groupList) {
        this.#logicElementModal?.removeOperatorGroup(...groupList);
    }

    set defaultValue(value) {
        this.setJSONAttribute("value", value);
    }

    get defaultValue() {
        return this.getJSONAttribute("value");
    }

    set value(value) {
        if (value == null || typeof value === "object" && !Array.isArray(value)) {
            super.value = value;
        }
    }

    get value() {
        return super.value;
    }

    static get observedAttributes() {
        return [...super.observedAttributes, "name"];
    }

    attributeChangedCallback(name, oldValue, newValue) {
        super.attributeChangedCallback(name, oldValue, newValue);
        switch (name) {
            case "name": {
                if (oldValue != newValue) {
                    this.#logicElementModal = LogicElementModal.getModalByName(newValue);
                    this.#logicElementModal.name = newValue;
                }
            } break;
            case "readonly": {
                if (oldValue != newValue) {
                    const el = this.children[0];
                    const value = newValue != null && newValue != "false";
                    if (el != null) {
                        el.readonly = value;
                    }
                }
            } break;
        }
    }

    append(el) {
        const isActive = (!this.readonly || this.readonly === "false") && (!this.disabled || this.disabled === "false");
        if (el instanceof LogicAbstractElement && isActive) {
            return super.append(el);
        }
    }

    checkValid() {
        const el = this.children[0];
        if (el != null && !el.checkValidity()) {
            return "Not a valid logic";
        }
        return super.checkValid();
    }

    renderValue(value) {
        if (value == null) {
            this.innerHTML = "";
        } else {
            this.#buildLogic(value);
        }
    }

    #removeElement(id) {
        const el = this.querySelector(`#${id}`);
        if (el != null && (typeof el.template != "string" || el.template == "false")) {
            const parentEl = el.parentElement;
            parentEl.removeChild(el);
            parentEl.focus();
        }
    }

    #buildLogic(data) {
        this.innerHTML = "";
        if ("type" in data) {
            const logicEl = LogicAbstractElement.buildLogic(data);
            logicEl.readonly = this.readonly;
            super.append(logicEl);
        }
    }

}

FormElementRegistry.register("LogicInput", LogicInput);
customElements.define("emc-input-logic", LogicInput);
registerFocusable("emc-input-logic");
