import Brick from "../core/brick.js";
import { snackbar } from "../user-interface/common/eden-snackbar.js";
import EdenModal from "../user-interface/common/eden-modal.js";
import t from "../i18n/index.js";
import typeOf from "../services/type-of.js";
import { put } from "../services/put.js";
import { htmlStringToElements } from "../services/html.js";
import Text from "../bricks/Text.js";
import RichText from "../bricks/RichText.js";
import Picture from "../bricks/Picture.js";
import Link from "../bricks/Link.js";
import Icon from "../bricks/Icon.js";
import Slideshow from "../bricks/Slideshow.js";
import Table from "../bricks/Table.js";
import Video from "../bricks/Video.js";
import Iframe from "../bricks/Iframe.js";
import GoogleMaps from "../bricks/GoogleMaps.js";
import YoutubePlaylist from "../bricks/YoutubePlaylist.js";
import Spotify from "../bricks/Spotify.js";
const BRICK_TEMPLATES = {
    Text,
    RichText,
    Picture,
    Link,
    Icon,
    Slideshow,
    Table,
    Video,
    Iframe,
    GoogleMaps,
    YoutubePlaylist,
    Spotify,
};
const recursCreateElement = (parent, node, parentSelector) => {
    const element = parentSelector.length === 0 ? parent : parent.querySelector(parentSelector);
    if (!element) {
        snackbar(t("snackbars.bricks-init-error"), "error");
        return;
    }
    const nodeAsObject = node;
    for (const templateName in nodeAsObject) {
        const templateDescriptor = nodeAsObject[templateName];
        const brickType = typeOf(templateDescriptor?.type);
        const markupType = typeOf(templateDescriptor?.markup);
        const tmp = put(element, templateName);
        if (!tmp)
            continue;
        const isPlainObject = markupType === "object" ||
            (markupType === "undefined" && brickType === "undefined");
        const nextMarkup = markupType === "object" ? templateDescriptor?.markup : templateDescriptor;
        if (isPlainObject) {
            recursCreateElement(element, nextMarkup, templateName);
        }
        else if (markupType === "string") {
            htmlStringToElements(templateDescriptor?.markup).forEach((el) => tmp.append(el));
        }
    }
};
const initBricksForItem = async (block, element, markup, parentSelector = "", parentBricks = [], shouldActivate = false) => {
    if (!block)
        return;
    const markupAsObject = markup;
    const selectorCount = {};
    await Promise.all(Object.entries(markupAsObject).map(async ([templateName, template]) => {
        let selector = parentSelector + templateName;
        const selectorIndex = selectorCount[selector] ?? 0;
        selectorCount[selector] = selectorIndex + 1;
        if (selectorIndex > 0) {
            selector += `:nth-child(${selectorIndex})`;
        }
        const childElement = element.querySelector(selector);
        if (!childElement)
            return;
        let parents = parentBricks;
        const templateObj = template;
        const brickType = templateObj.type;
        if (brickType !== undefined) {
            try {
                const BrickTemplate = BRICK_TEMPLATES[brickType];
                if (!BrickTemplate)
                    return;
                const tableParams = brickType === "Table" ? { rows: templateObj.markup } : {};
                const brick = new BrickTemplate({
                    block,
                    element: childElement,
                    parentBricks: parents,
                    options: templateObj.options,
                    markup: templateObj.markup,
                    isCreation: true,
                    ...tableParams,
                });
                block.instances = [...(block.instances ?? []), brick];
                parents = [...parents, brick];
                if (typeof brick.init === "function") {
                    await brick.init();
                }
                if (shouldActivate && typeof brick.activate === "function") {
                    brick.activate();
                }
            }
            catch {
            }
        }
        const markupType = typeOf(templateObj.markup);
        const isNestedObject = markupType === "object" ||
            (markupType === "undefined" && brickType === undefined);
        if (isNestedObject) {
            const nextMarkup = markupType === "object" ? templateObj.markup : templateObj;
            await initBricksForItem(block, childElement, nextMarkup, `${selector} > `, parents, shouldActivate);
        }
    }));
};
export default class Recursive extends Brick {
    constructor({ block, element, parentBricks, templates }) {
        super({ block, element, parentBricks });
        this.addItem = async (template) => {
            const itemContainer = document.createElement("div");
            itemContainer.dataset.recursiveId = template.id;
            if (template.markup) {
                recursCreateElement(itemContainer, template.markup, "");
            }
            const selectedItem = this.getSelectedItem();
            if (selectedItem) {
                selectedItem.insertAdjacentElement("afterend", itemContainer);
            }
            else {
                this.container?.appendChild(itemContainer);
            }
            if (this.block && template.markup) {
                await initBricksForItem(this.block, itemContainer, template.markup, "", [...(this.parentBricks ?? []), this], true);
            }
        };
        this.duplicateItem = async () => {
            const selectedItem = this.getSelectedItem();
            if (!selectedItem) {
                snackbar(t("common.no-selection"), "information");
                return;
            }
            const clone = selectedItem.cloneNode(true);
            clone
                .querySelectorAll("[contenteditable]")
                .forEach((el) => el.removeAttribute("contenteditable"));
            selectedItem.insertAdjacentElement("afterend", clone);
            const itemId = clone.dataset.recursiveId;
            const template = this.templates.find((t) => t.id === itemId);
            if (template && this.block) {
                await initBricksForItem(this.block, clone, template.markup, "", [...(this.parentBricks ?? []), this], true);
            }
        };
        this.moveItem = (direction) => {
            const selectedItem = this.getSelectedItem();
            if (!selectedItem) {
                snackbar(t("common.no-selection"), "information");
                return;
            }
            const sibling = direction === -1
                ? selectedItem.previousElementSibling
                : selectedItem.nextElementSibling;
            if (!sibling) {
                snackbar(direction === -1
                    ? t("bricks.recursive.move-up")
                    : t("bricks.recursive.move-down"), "warning");
                return;
            }
            if (direction === -1) {
                sibling.insertAdjacentElement("beforebegin", selectedItem);
            }
            else {
                sibling.insertAdjacentElement("afterend", selectedItem);
            }
        };
        this.removeItem = () => {
            const selectedItem = this.getSelectedItem();
            if (!selectedItem) {
                snackbar(t("common.no-selection"), "information");
                return;
            }
            const allItems = this.container?.querySelectorAll("[data-recursive-id]");
            if (allItems && allItems.length <= 1) {
                snackbar(t("bricks.recursive.cannot-remove-last-item"), "warning");
                return;
            }
            const modal = new EdenModal({
                icon: "delete",
                title: t("bricks.recursive.remove-item"),
                content: t("bricks.recursive.remove-item-confirm"),
                buttons: [
                    {
                        value: t("common.cancel"),
                        cssClass: "cancel",
                    },
                    {
                        value: t("common.remove"),
                        onClick: () => {
                            selectedItem.remove();
                            snackbar(t("common.removed"), "success");
                        },
                        cssClass: "confirm",
                        autofocus: true,
                    },
                ],
                closeButton: false,
            });
            document.body.appendChild(modal);
        };
        this.getSelectedItem = () => {
            const selection = window.getSelection();
            if (!selection || selection.rangeCount === 0) {
                return null;
            }
            const range = selection.getRangeAt(0);
            let node = range.commonAncestorContainer;
            while (node && node !== this.container) {
                if (node.nodeType === Node.ELEMENT_NODE) {
                    const element = node;
                    if (element.dataset.recursiveId) {
                        return element;
                    }
                }
                node = node.parentNode;
            }
            return null;
        };
        if (!templates?.length) {
            throw new Error("No templates specified for Recursive brick");
        }
        this.templates = templates;
        this.container = element;
        this.actions = [
            {
                icon: "plus",
                tooltip: t("bricks.recursive.add-item"),
                action: this.templates.map((template) => ({
                    name: template.name,
                    action: async () => {
                        await this.addItem(template);
                    },
                })),
            },
            {
                tooltip: t("common.duplicate"),
                icon: "duplicate",
                action: () => this.duplicateItem(),
            },
            {
                tooltip: t("bricks.recursive.move-up"),
                icon: "chevron_up",
                action: () => this.moveItem(-1),
            },
            {
                tooltip: t("bricks.recursive.move-down"),
                icon: "chevron_down",
                action: () => this.moveItem(1),
            },
            {
                tooltip: t("common.remove"),
                icon: "delete",
                action: () => this.removeItem(),
            },
        ];
    }
    async init() {
        const existingItems = this.container?.querySelectorAll("[data-recursive-id]");
        if (existingItems && existingItems.length > 0) {
            for (const itemElement of existingItems) {
                const itemId = itemElement.dataset.recursiveId;
                const template = this.templates.find((t) => t.id === itemId);
                if (template && this.block) {
                    await initBricksForItem(this.block, itemElement, template.markup, "", [...(this.parentBricks ?? []), this], false);
                }
            }
        }
        else if (this.templates.length > 0) {
            await this.addItem(this.templates[0]);
        }
    }
    activate() {
        if (this.container) {
            this.container.addEventListener("click", this.handleClick);
        }
    }
    desactivate() {
        if (this.container) {
            this.container.removeEventListener("click", this.handleClick);
        }
    }
}
