import { setEditable, unsetEditable } from "../core/brick.js";
import { generateShortcut } from "../services/keys.js";
import html from "../services/html.js";
import t from "../i18n/index.js";
import Text from "./Text.js";
var STYLES_FROM_CONFIG_PROPERTIES;
(function (STYLES_FROM_CONFIG_PROPERTIES) {
    STYLES_FROM_CONFIG_PROPERTIES["color"] = "color";
    STYLES_FROM_CONFIG_PROPERTIES["background"] = "background";
    STYLES_FROM_CONFIG_PROPERTIES["size"] = "font-size";
    STYLES_FROM_CONFIG_PROPERTIES["family"] = "font-family";
    STYLES_FROM_CONFIG_PROPERTIES["weight"] = "font-weight";
})(STYLES_FROM_CONFIG_PROPERTIES || (STYLES_FROM_CONFIG_PROPERTIES = {}));
const LAST_LEVEL_CHILDREN = ["SUB", "EM", "B", "STRONG", "I"];
export default class RichText extends Text {
    constructor({ block, element, parentBricks, options }) {
        super({ block, element, parentBricks });
        this.updateSource = (html) => {
            this.element.innerHTML = html;
        };
        this.updateLink = (url = "", title, target) => {
            const { protocol, host } = window.location;
            const domain = protocol.concat(host);
            let patchedUrl = url.replace(domain, "");
            const mustAddProtocol = patchedUrl.startsWith("www.");
            if (mustAddProtocol) {
                patchedUrl = `https://${patchedUrl}`;
            }
            restoreSelection();
            document.execCommand("createlink", false, patchedUrl);
            const anchor = findParentFromSelection("a");
            if (!anchor)
                return;
            if (patchedUrl !== "") {
                anchor.setAttribute("href", patchedUrl);
            }
            else {
                anchor.removeAttribute("href");
            }
            if (title && title !== "") {
                anchor.setAttribute("title", title);
            }
            else {
                anchor.removeAttribute("title");
            }
            if (target) {
                anchor.setAttribute("target", "_blank");
                anchor.setAttribute("rel", "noopener");
            }
            else {
                anchor.removeAttribute("target");
                anchor.removeAttribute("rel");
            }
        };
        this.cleanupEmptyWithBr = () => {
            if (!this.element)
                return;
            const isEmpty = this.element.innerText.trim().length === 0;
            if (!isEmpty)
                return;
            const brs = Array.from(this.element.querySelectorAll("br"));
            if (brs.length > 1)
                return;
            brs.forEach((br) => br.remove());
        };
        this.options = options;
        this.watchSelectionChange = true;
        const actions = [
            {
                code: "bold",
                tooltip: `${t("bricks.rich-text.bold")} ${generateShortcut("ctrl", "b")}`,
                icon: "bold",
                command: "bold",
                action: () => {
                    document.execCommand("bold");
                },
            },
            {
                code: "italic",
                tooltip: `${t("bricks.rich-text.italic")} ${generateShortcut("ctrl", "i")}`,
                icon: "italic",
                command: "italic",
                action: () => {
                    document.execCommand("italic");
                },
            },
            {
                code: "list",
                tooltip: t("bricks.rich-text.bullet-list"),
                icon: "list",
                command: "InsertUnorderedList",
                action: () => {
                    document.execCommand("InsertUnorderedList");
                },
            },
            {
                code: "orderedList",
                tooltip: t("bricks.rich-text.numbered-list"),
                icon: "ordered_list",
                command: "InsertOrderedList",
                action: () => {
                    document.execCommand("InsertOrderedList");
                },
            },
            {
                code: "left",
                tooltip: t("bricks.rich-text.align-left"),
                icon: "align_left",
                command: "justifyleft",
                action: () => {
                    this.element.focus();
                    document.execCommand("justifyleft");
                },
            },
            {
                code: "center",
                tooltip: t("bricks.rich-text.align-center"),
                icon: "align_center",
                command: "justifycenter",
                action: () => {
                    this.element.focus();
                    document.execCommand("justifycenter");
                },
            },
            {
                code: "right",
                tooltip: t("bricks.rich-text.align-right"),
                icon: "align_right",
                command: "justifyright",
                action: () => {
                    this.element.focus();
                    document.execCommand("justifyright");
                },
            },
            {
                code: "justify",
                tooltip: t("bricks.rich-text.justify"),
                icon: "align_justify",
                command: "justifyfull",
                action: () => {
                    this.element.focus();
                    document.execCommand("justifyfull");
                },
            },
            {
                code: "indent",
                tooltip: t("bricks.rich-text.increase-indent"),
                icon: "indent_right",
                command: "indent",
                action: () => {
                    this.element.focus();
                    document.execCommand("indent");
                },
            },
            {
                code: "outdent",
                tooltip: t("bricks.rich-text.decrease-indent"),
                icon: "indent_left",
                command: "outdent",
                action: () => {
                    this.element.focus();
                    document.execCommand("outdent");
                },
            },
            {
                code: "link",
                tooltip: t("bricks.rich-text.insert-link"),
                icon: "link",
                command: "link",
                action: async () => {
                    saveSelection();
                    const anchor = findParentFromSelection("a");
                    const { default: LinkModal } = await import("../user-interface/plugin/link-modal.js");
                    if (anchor) {
                        const { title } = anchor;
                        const target = anchor.hasAttribute("target");
                        const href = anchor.getAttribute("href");
                        new LinkModal(this.updateLink, href !== null ? href : "", title, target).init();
                    }
                    else {
                        new LinkModal(this.updateLink).init();
                    }
                },
            },
            {
                code: "unlink",
                tooltip: t("bricks.rich-text.remove-link"),
                icon: "unlink",
                action: () => {
                    saveSelection();
                    const anchor = findParentFromSelection("a");
                    if (anchor) {
                        document.execCommand("unlink", false, "false");
                    }
                },
            },
            {
                code: "cleanup",
                tooltip: t("bricks.rich-text.remove-formatting"),
                icon: "remove_formatting",
                action: () => {
                    this.element.focus();
                    document.execCommand("removeFormat");
                },
            },
        ];
        defineStylesFromConfig(actions, "color", t("bricks.rich-text.text-color"));
        defineStylesFromConfig(actions, "background", t("bricks.rich-text.background-color"));
        defineStylesFromConfig(actions, "family", t("bricks.rich-text.font-family"));
        defineStylesFromConfig(actions, "size", t("bricks.rich-text.text-size"));
        defineStylesFromConfig(actions, "weight", t("bricks.rich-text.text-weight"));
        this.actions =
            options !== undefined && options.commands !== undefined
                ? actions.filter((action) => options?.commands?.includes(action.code))
                : actions;
        this.hasTextLengthOption = this.options?.textLength?.max;
        this.enforceTextLength = Boolean(this.options?.textLength?.force);
        this.textLengthHelper = undefined;
        this.emailPresenceHelper = undefined;
        if (options?.allowHtmlEdit) {
            this.actions.push({
                code: "source",
                tooltip: t("bricks.rich-text.source"),
                icon: "source",
                action: async () => {
                    const { default: SourceModal } = await import("../user-interface/plugin/source-modal.js");
                    new SourceModal(this.updateSource, this.element.innerHTML).init();
                },
            });
        }
    }
    activate() {
        if (this.element) {
            setEditable(this.element);
            this.element.addEventListener("click", this.handleClick);
            if (this.hasTextLengthOption) {
                this.element.addEventListener("input", this.updateTextLengthHelper);
                this.element.addEventListener("keydown", this.updateTextLengthHelper);
                this.element.addEventListener("click", this.updateTextLengthHelper);
                this.element.addEventListener("focus", this.spawnTextLengthHelper);
                this.element.addEventListener("blur", this.removeTextLengthHelper);
            }
            this.element.addEventListener("input", this.spawnOrUpdateEmailPresenceHelper);
            this.element.addEventListener("keydown", this.spawnOrUpdateEmailPresenceHelper);
            this.element.addEventListener("click", this.spawnOrUpdateEmailPresenceHelper);
            this.element.addEventListener("focus", this.spawnOrUpdateEmailPresenceHelper);
            this.element.addEventListener("blur", this.removeEmailPresenceHelper);
            if (this.options?.allowHtmlEdit) {
                this.element.style.setProperty("padding", "10px 0");
            }
        }
    }
    desactivate() {
        if (this.element) {
            this.cleanupEmptyWithBr();
            unsetEditable(this.element);
            this.element.removeEventListener("click", this.handleClick);
            this.element.removeEventListener("blur", this.removeEmailPresenceHelper);
            this.element.removeEventListener("focus", this.spawnOrUpdateEmailPresenceHelper);
            this.element.removeEventListener("click", this.spawnOrUpdateEmailPresenceHelper);
            this.element.removeEventListener("keydown", this.spawnOrUpdateEmailPresenceHelper);
            this.element.removeEventListener("input", this.spawnOrUpdateEmailPresenceHelper);
            if (this.hasTextLengthOption) {
                this.element.removeEventListener("blur", this.removeTextLengthHelper);
                this.element.removeEventListener("focus", this.spawnTextLengthHelper);
                this.element.removeEventListener("click", this.updateTextLengthHelper);
                this.element.removeEventListener("keydown", this.updateTextLengthHelper);
                this.element.removeEventListener("input", this.updateTextLengthHelper);
            }
            if (this.options?.allowHtmlEdit) {
                this.element.removeAttribute("style");
            }
        }
    }
}
let savedRange = null;
function saveSelection() {
    savedRange = document.getSelection()?.getRangeAt(0).cloneRange() || null;
}
function restoreSelection() {
    const selection = document.getSelection();
    if (!savedRange || !selection)
        return;
    selection.removeAllRanges();
    selection.addRange(savedRange);
}
export function findParentFromSelection(selector) {
    const selection = document.getSelection();
    if (!selection?.focusNode)
        return null;
    const range = selection.getRangeAt(0);
    const ancestor = range.commonAncestorContainer;
    const { nodeType, parentNode } = ancestor;
    const commonAncestor = (nodeType === Node.TEXT_NODE ? parentNode : ancestor);
    return commonAncestor.closest(`${selector}:not([contenteditable="true"])`);
}
function defineStylesFromConfig(actions, key, tooltip) {
    const styles = window.EdenConfig.styles?.[key];
    if (!styles)
        return;
    const normalizedStyles = styles.map((style) => {
        if (typeof style === "string") {
            return {
                name: style,
                value: style,
            };
        }
        return style;
    });
    actions.push({
        tooltip,
        code: key,
        icon: key,
        action: normalizedStyles.map((style) => {
            const property = STYLES_FROM_CONFIG_PROPERTIES[key];
            const isColor = key === "color" || key === "background";
            const { name, value } = style;
            const action = () => {
                wrapWith("span", property, value);
            };
            const formatter = (option) => {
                return html `
          <div class="option__pill" style="background: ${value}"></div>
          ${option.text}
        `;
            };
            return {
                property,
                name,
                value,
                action,
                formatter: isColor ? formatter : undefined,
            };
        }),
    });
}
function wrapWith(tag, property, value) {
    const bareSelection = document.getSelection();
    if (!bareSelection)
        return;
    const selectionContent = bareSelection.getRangeAt(0).cloneContents();
    const tmpContainer = document.createElement("div");
    tmpContainer.appendChild(selectionContent);
    const selection = tmpContainer.innerHTML;
    if (!selection.trim())
        return;
    const { startContainer } = bareSelection.getRangeAt(0);
    const bareElement = (startContainer.nodeType === Node.TEXT_NODE
        ? startContainer.parentNode
        : startContainer);
    const isAlreadyFormated = LAST_LEVEL_CHILDREN.includes(bareElement.nodeName);
    const element = isAlreadyFormated ? bareElement.parentElement : bareElement;
    if (!element)
        return;
    if (element.nodeName === tag.toUpperCase() &&
        element.contentEditable !== "true") {
        if (value) {
            if (element.style.getPropertyValue(property) === value) {
                element.style.removeProperty(property);
            }
            else {
                element.style.setProperty(property, value);
            }
            if (element.getAttribute("style")?.length === 0) {
                element.outerHTML = element.innerHTML;
            }
        }
    }
    else {
        const attribute = `style="${property}: ${value}"`;
        const nodeName = bareElement.nodeName.toLowerCase();
        const innerHTML = isAlreadyFormated
            ? `<${nodeName}>${selection}</${nodeName}>`
            : selection;
        document.execCommand("insertHTML", false, `<${tag} ${attribute}>${innerHTML}</${tag}>`);
    }
}
