import { DecoratorNode, ElementNode, type LexicalNode, type SerializedElementNode, type SerializedLexicalNode, type Spread } from "lexical";
import { FocusableNode } from "./focusable_node";
import type { ReactNode } from "react";
import { TermIcon } from "~/components/editor/term_icon";

type SerializedTermNode = Spread<SerializedElementNode, {
    term: string;
}>;

export class TermNode extends FocusableNode {
    __term: string;

    getTerm() {
        const self = this.getLatest();
        return self.__term;
    }
    static getType() {
        return "term";
    }
    static clone(node: TermNode) {
        return new TermNode(node.__term, node.__key, node.__hasFocus);
    }
    constructor(term: string, key?: string, hasFocus?: boolean) {
        super(key, hasFocus);
        this.__term = term;
    }
    isInline() {
        return true;
    }
    createDOM() {
        const element = super.createDOM();
        element.classList.add("term");
        return element;
    }
    updateDOM(old: TermNode, dom: HTMLElement) {
        return super.updateDOM(old, dom);
    }
    exportJSON(): SerializedTermNode {
        return {
            ...super.exportJSON(),
            type: "term",
            term: this.__term,
        };
    }
    static importJSON(serializedNode: SerializedTermNode) {
        return $createTermNode(serializedNode.term);
    }
}

export function $createTermNode(term: string) {
    return new TermNode(term);
}
export function $isTermNode(node?: LexicalNode | null): node is TermNode {
    return node instanceof TermNode;
}

export class TermMarkerNode extends ElementNode {
    static getType() {
        return "term-marker";
    }
    static clone(node: TermMarkerNode) {
        return new TermMarkerNode(node.__key);
    }
    isInline() {
        return true;
    }
    createDOM() {
        const element = document.createElement("span");
        element.classList.add("term-marker");
        return element;
    }
    updateDOM() {
        return false;
    }
    exportJSON() {
        return {
            ...super.exportJSON(),
            type: "term-marker",
        };
    }
    static importJSON() {
        return $createTermMarkerNode();
    }
}

export function $createTermMarkerNode() {
    return new TermMarkerNode();
}
export function $isTermMarkerNode(node?: LexicalNode | null): node is TermMarkerNode {
    return node instanceof TermMarkerNode;
}

type SerializedTermIconNode = Spread<SerializedLexicalNode, {
    term: string;
}>;

export class TermIconNode extends DecoratorNode<ReactNode> {
    __term: string;

    getTerm() {
        const self = this.getLatest();
        return self.__term;
    }

    static getType() {
        return "term-icon";
    }
    static clone(node: TermIconNode) {
        return new TermIconNode(node.__term, node.__key);
    }
    constructor(term: string, key?: string) {
        super(key);
        this.__term = term;
    }
    createDOM() {
        return document.createElement("span");
    }
    updateDOM() {
        return false;
    }
    decorate(): ReactNode {
        return (<TermIcon term={this.__term} />);
    }
    exportJSON(): SerializedTermIconNode {
        return {
            ...super.exportJSON(),
            type: "term-icon",
            term: this.__term,
        };
    }
    static importJSON(serializedNode: SerializedTermIconNode) {
        return $createTermIconNode(serializedNode.term);
    }
}

export function $createTermIconNode(term: string) {
    return new TermIconNode(term);
}
export function $isTermIconNode(node?: LexicalNode | null): node is TermIconNode {
    return node instanceof TermIconNode;
}

