"use client";

import * as Y from "yjs";
import { type InitialConfigType, LexicalComposer } from "@lexical/react/LexicalComposer";
import { PlainTextPlugin } from "@lexical/react/LexicalPlainTextPlugin";
import { CollaborationPlugin } from '@lexical/react/LexicalCollaborationPlugin';
import { ContentEditable } from "@lexical/react/LexicalContentEditable";
import { LexicalErrorBoundary } from "@lexical/react/LexicalErrorBoundary";
import { HeaderMarkerNode, HeaderNode } from "./nodes/header_node";
import { ParagraphPlugin } from "./plugins/paragraph_plugin";
import { HeaderPlugin } from "./plugins/header_plugin";
import { SelectionPlugin } from "./plugins/selection_plugin";
import { FormattedTextMarkerNode, FormattedTextNode } from "./nodes/formatted_text";
import { FormattedTextPlugin } from "./plugins/formatted_text_plugin";
import { TaskIconNode, TaskMarkerNode, TaskNode } from "./nodes/task_node";
import { TaskPlugin } from "./plugins/task_plugin";
import { LinkIconNode, LinkMarkerNode, LinkNode, LinkUrlNode } from "./nodes/link_node";
import { LinkPlugin } from "./plugins/link_plugin";
import { TermIconNode, TermMarkerNode, TermNode } from "./nodes/term_node";
import { TermPlugin } from "./plugins/term_plugin";
import { useCallback } from "react";
import type { Provider } from "@lexical/yjs";
import type { NoteId } from "~/lib/metadata";
import type { Klass, LexicalNode } from "lexical";
import { useNoteDoc, useNoteProviders } from "~/hooks/use-note";

export function Editor(props: { noteId: NoteId }) {
    const provider = useNoteProviders().websocket;
    const doc = useNoteDoc();

    const providerFactory = useCallback((id: string, yjsDocMap: Map<string, Y.Doc>): Provider => {
        // Just overwrite it, because we have the doc managed externally
        yjsDocMap.set(id, doc);

        return provider as any as Provider;
    }, [provider, doc]);

    return (
        <LexicalComposer initialConfig={initialEditorConfig}>
            <div className="w-full relative editor-content">
                <PlainTextPlugin
                    contentEditable={<ContentEditable className="outline-none" />}
                    placeholder={<div className="absolute top-0 left-0 pointer-events-none text-zinc-300">Enter some text...</div>}
                    ErrorBoundary={LexicalErrorBoundary}
                />
            </div>
            <CollaborationPlugin
                id={`note-${props.noteId}`}
                providerFactory={providerFactory}
                shouldBootstrap={false}
                excludedProperties={excludedProperties}
            />

            <ParagraphPlugin />
            <SelectionPlugin />

            <HeaderPlugin />
            <FormattedTextPlugin />
            <TaskPlugin />
            <LinkPlugin />
            <TermPlugin />
        </LexicalComposer>
    );
}

const excludedProperties = new Map<Klass<LexicalNode>, Set<string>>([
    [HeaderNode, new Set(["__hasFocus"])],
    [TermNode, new Set(["__hasFocus"])],
    [TaskNode, new Set(["__hasFocus"])],
    [LinkNode, new Set(["__hasFocus"])],
    [FormattedTextNode, new Set(["__hasFocus"])],
])

const theme = {
};

const initialEditorConfig: InitialConfigType = {
    namespace: "NoteEditor",
    theme,
    onError: console.error,
    editorState: null,
    nodes: [
        HeaderNode, HeaderMarkerNode,
        FormattedTextNode, FormattedTextMarkerNode,
        TaskNode, TaskMarkerNode, TaskIconNode,
        LinkNode, LinkMarkerNode, LinkUrlNode, LinkIconNode,
        TermNode, TermMarkerNode, TermIconNode,
    ],
};

