import { getClientConfig, resolveRoutes } from "@byline/core";
import { addClassNamesToElement, isHTMLAnchorElement } from "@lexical/utils";
import { $applyNodeReplacement, $createTextNode, $getSelection, $isElementNode, $isRangeSelection, ElementNode, createCommand } from "lexical";
import { sanitizeUrl } from "../../utils/url.js";
function adminHref(attrs) {
    if (null == attrs || 'internal' !== attrs.linkType) return '#';
    const internal = attrs;
    const { admin } = resolveRoutes(getClientConfig().routes);
    return `${admin}/collections/${internal.targetCollectionPath}/${internal.targetDocumentId}`;
}
class LinkNode extends ElementNode {
    static getType() {
        return 'link';
    }
    static clone(node) {
        return new LinkNode({
            attributes: node.__attributes,
            key: node.__key
        });
    }
    createDOM(config) {
        const element = document.createElement('a');
        if (this.__attributes?.linkType === 'internal') element.href = adminHref(this.__attributes);
        else element.href = sanitizeUrl(this.__attributes?.url ?? '');
        if (this.__attributes?.newTab ?? false) element.target = '_blank';
        element.rel = '';
        if (this.__attributes?.newTab === true && this.__attributes?.linkType !== 'internal') {
            element.rel = manageRel(element.rel, 'add', 'noopener');
            element.rel = manageRel(element.rel, 'add', 'nofollow');
        }
        if (this.__attributes?.rel != null) element.rel += ` ${this.__attributes?.rel}`;
        addClassNamesToElement(element, config.theme.link);
        return element;
    }
    updateDOM(prevNode, anchor, _config) {
        const attrs = this.__attributes;
        const prevAttrs = prevNode.__attributes;
        const url = attrs?.linkType !== 'internal' ? attrs?.url : void 0;
        const prevUrl = prevAttrs?.linkType !== 'internal' ? prevAttrs?.url : void 0;
        const newTab = attrs?.newTab;
        const rel = attrs?.rel;
        if (null != url && url !== prevUrl && attrs?.linkType !== 'internal') anchor.href = url;
        const switchedToInternal = attrs?.linkType === 'internal' && prevAttrs?.linkType !== 'internal';
        const targetChanged = attrs?.linkType === 'internal' && prevAttrs?.linkType === 'internal' && attrs.targetDocumentId !== prevAttrs.targetDocumentId;
        if (switchedToInternal || targetChanged) anchor.href = adminHref(attrs);
        if (null == anchor.rel) anchor.rel = '';
        if (newTab !== prevAttrs?.newTab) if (null != newTab && true === newTab) {
            anchor.target = '_blank';
            if (attrs?.linkType !== 'internal') {
                anchor.rel = manageRel(anchor.rel, 'add', 'noopener');
                anchor.rel = manageRel(anchor.rel, 'add', 'nofollow');
            }
        } else {
            anchor.removeAttribute('target');
            anchor.rel = manageRel(anchor.rel, 'remove', 'noopener');
            anchor.rel = manageRel(anchor.rel, 'remove', 'nofollow');
        }
        if (rel !== prevAttrs?.rel) if (null != rel) anchor.rel += rel;
        else anchor.removeAttribute('rel');
        return false;
    }
    static importDOM() {
        return {
            a: (_node)=>({
                    conversion: convertAnchorElement,
                    priority: 1
                })
        };
    }
    static importJSON(serializedNode) {
        const node = $createLinkNode({
            attributes: serializedNode.attributes
        });
        node.setFormat(serializedNode.format);
        node.setIndent(serializedNode.indent);
        node.setDirection(serializedNode.direction);
        return node;
    }
    exportJSON() {
        return {
            ...super.exportJSON(),
            attributes: this.getAttributes(),
            type: 'link',
            version: 2
        };
    }
    getAttributes() {
        return this.getLatest().__attributes;
    }
    setAttributes(attributes) {
        const writable = this.getWritable();
        writable.__attributes = attributes;
    }
    insertNewAfter(selection, restoreSelection = true) {
        const element = this.getParentOrThrow().insertNewAfter(selection, restoreSelection);
        if ($isElementNode(element)) {
            const linkNode = $createLinkNode({
                attributes: this.__attributes
            });
            element.append(linkNode);
            return linkNode;
        }
        return null;
    }
    canInsertTextBefore() {
        return false;
    }
    canInsertTextAfter() {
        return false;
    }
    canBeEmpty() {
        return false;
    }
    isInline() {
        return true;
    }
    extractWithChild(_child, selection, _destination) {
        if (!$isRangeSelection(selection)) return false;
        const anchorNode = selection.anchor.getNode();
        const focusNode = selection.focus.getNode();
        return this.isParentOf(anchorNode) && this.isParentOf(focusNode) && selection.getTextContent().length > 0;
    }
    constructor({ attributes = {
        linkType: 'custom',
        url: void 0,
        newTab: false,
        rel: null
    }, key }){
        super(key);
        this.__attributes = attributes;
    }
}
function convertAnchorElement(domNode) {
    let node = null;
    if (isHTMLAnchorElement(domNode)) {
        const content = domNode.textContent;
        if (null !== content && '' !== content) node = $createLinkNode({
            attributes: {
                linkType: 'custom',
                url: domNode.getAttribute('href') ?? '',
                rel: domNode.getAttribute('rel'),
                newTab: '_blank' === domNode.getAttribute('target')
            }
        });
    }
    return {
        node
    };
}
function $createLinkNode({ attributes }) {
    const linkNode = new LinkNode({
        attributes
    });
    return $applyNodeReplacement(linkNode);
}
function $isLinkNode(node) {
    return node instanceof LinkNode;
}
const TOGGLE_LINK_COMMAND = createCommand('TOGGLE_LINK_COMMAND');
const OPEN_LINK_MODAL_COMMAND = createCommand('OPEN_LINK_MODAL_COMMAND');
function $toggleLink(linkAttributes) {
    const selection = $getSelection();
    if (!$isRangeSelection(selection)) return;
    const nodes = selection.extract();
    if (null === linkAttributes) nodes.forEach((node)=>{
        const parent = node.getParent();
        if ($isLinkNode(parent)) {
            const children = parent.getChildren();
            for(let i = 0; i < children.length; i += 1)parent.insertBefore(children[i]);
            parent.remove();
        }
    });
    else {
        if (1 === nodes.length) {
            const firstNode = nodes[0];
            const linkNode = $isLinkNode(firstNode) ? firstNode : $getLinkAncestor(firstNode);
            if (null !== linkNode) {
                linkNode.setAttributes(linkAttributes);
                if (null != linkAttributes.text && linkAttributes.text !== linkNode.getTextContent()) {
                    linkNode.append($createTextNode(linkAttributes.text));
                    linkNode.getChildren().forEach((child)=>{
                        if (child !== linkNode.getLastChild()) child.remove();
                    });
                }
                return;
            }
        }
        let prevParent = null;
        let linkNode = null;
        nodes.forEach((node)=>{
            const parent = node.getParent();
            if (parent === linkNode || null === parent || $isElementNode(node) && !node.isInline()) return;
            if ($isLinkNode(parent)) {
                linkNode = parent;
                parent.setAttributes(linkAttributes);
                if (null != linkAttributes.text && linkAttributes.text !== parent.getTextContent()) {
                    parent.append($createTextNode(linkAttributes.text));
                    parent.getChildren().forEach((child)=>{
                        if (child !== parent.getLastChild()) child.remove();
                    });
                }
                return;
            }
            if (false === parent.is(prevParent)) {
                prevParent = parent;
                linkNode = $createLinkNode({
                    attributes: linkAttributes
                });
                if ($isLinkNode(parent)) if (null === node.getPreviousSibling()) parent.insertBefore(linkNode);
                else parent.insertAfter(linkNode);
                else node.insertBefore(linkNode);
            }
            if ($isLinkNode(node)) {
                if (node.is(linkNode)) return;
                if (null !== linkNode) {
                    const children = node.getChildren();
                    for(let i = 0; i < children.length; i += 1)linkNode.append(children[i]);
                }
                node.remove();
                return;
            }
            if (null !== linkNode) linkNode.append(node);
        });
    }
}
function $getLinkAncestor(node) {
    return $getAncestor(node, (ancestor)=>$isLinkNode(ancestor));
}
function $getAncestor(node, predicate) {
    let parent = node;
    while(null !== parent){
        parent = parent.getParent();
        if (null === parent || predicate(parent)) break;
    }
    return parent;
}
function manageRel(input, action, value) {
    let result;
    let mutableInput = `${input}`;
    if ('add' === action) {
        if (mutableInput.includes(value)) {
            const re = new RegExp(value, 'g');
            mutableInput = mutableInput.replace(re, '').trim();
        }
        mutableInput = mutableInput.trim();
        result = 0 === mutableInput.length ? `${value}` : `${mutableInput} ${value}`;
    } else {
        const re = new RegExp(value, 'g');
        result = mutableInput.replace(re, '').trim();
    }
    return result;
}
export { $createLinkNode, $isLinkNode, $toggleLink, LinkNode, OPEN_LINK_MODAL_COMMAND, TOGGLE_LINK_COMMAND };
