import { Mark, mergeAttributes } from '../../externals.js';
// eslint-disable-next-line jsdoc/require-jsdoc
function parseStyles(style) {
    const items = {};
    (style ?? '')
        .split(';')
        .map((x) => x.trim())
        .filter((x) => x)
        .forEach((rule) => {
        const [key, value] = rule.split(':');
        if (key && value) {
            items[key.trim()] = value.trim();
        }
    });
    return items;
}
// eslint-disable-next-line jsdoc/require-jsdoc
function serializeStyles(items) {
    return (Object.entries(items)
        .map(([key, value]) => `${key}: ${value}`)
        .join(';') + ';');
}
export const Span = Mark.create({
    name: 'span',
    priority: 50,
    addOptions() {
        return { HTMLAttributes: {} };
    },
    parseHTML() {
        return [{ tag: this.name }];
    },
    renderHTML({ HTMLAttributes }) {
        return [this.name, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
    },
    addCommands() {
        return {
            setSpanStyle: (styles) => ({ commands, editor }) => {
                if (!styles)
                    return false;
                const existing = editor.getAttributes(this.name)?.style;
                if (!existing && !editor.isActive(this.name)) {
                    return commands.setMark(this.name, { style: styles });
                }
                const items = {
                    ...parseStyles(existing),
                    ...parseStyles(styles),
                };
                const style = serializeStyles(items);
                if (style === ';')
                    return false;
                return commands.updateAttributes(this.name, { style });
            },
            toggleSpanStyle: (styles) => ({ commands, editor }) => {
                if (!styles)
                    return false;
                const existing = editor.getAttributes(this.name)?.style;
                return existing?.includes(styles) === true ? commands.unsetSpanStyle(styles) : commands.setSpanStyle(styles);
            },
            unsetSpanStyle: (styles) => ({ commands, editor }) => {
                if (!styles)
                    return false;
                parseStyles(styles);
                const toBeRemoved = new Set();
                styles
                    .split(';')
                    .map((x) => x.trim())
                    .filter((x) => x)
                    .forEach((rule) => {
                    const [key] = rule.split(':');
                    if (key)
                        toBeRemoved.add(key.trim());
                });
                if (toBeRemoved.size === 0)
                    return false;
                const existing = editor.getAttributes(this.name)?.style;
                const items = parseStyles(existing);
                // Remove keys
                for (const key of toBeRemoved) {
                    delete items[key];
                }
                const style = serializeStyles(items);
                return style === ';'
                    ? commands.resetAttributes(this.name, 'style')
                    : commands.updateAttributes(this.name, { style });
            },
        };
    },
});
