import React from "react";
import * as Y from "yjs";
import type { NoteId } from "~/lib/metadata";
import { useYDoc } from "./use-ydoc";
import type { WebsocketProvider } from "y-websocket";
import type { IndexeddbPersistence } from "y-indexeddb";

const NoteContext = React.createContext<{
    doc: Y.Doc,
    providers: {
        indexeddb: IndexeddbPersistence,
        websocket: WebsocketProvider,
    }
} | null>(null);

export function NoteProvider(props: { children: React.ReactNode, id: NoteId }) {
    const { ydoc, indexeddbProvider, websocketProvider } = useYDoc(`note-${props.id}`);

    // If we don't have the provider yet, delay rendering until we do.
    if (!indexeddbProvider || !websocketProvider) {
        return null;
    }

    return (
        <NoteContext.Provider value={{
            doc: ydoc,
            providers: {
                indexeddb: indexeddbProvider,
                websocket: websocketProvider,
            }
        }}>
            {props.children}
        </NoteContext.Provider>
    );
}

export function useNoteDoc() {
    const ctx = React.useContext(NoteContext);
    if (!ctx) {
        throw new Error("useNoteDoc must be used within a NoteProvider")
    }
    return ctx.doc;
}

export function useNoteMap(name: string) {
    const ctx = React.useContext(NoteContext);
    if (!ctx) {
        throw new Error("useNoteMap must be used within a NoteProvider")
    }
    const map = ctx.doc.getMap(name);
    return map;
}

export function useNoteArray(name: string) {
    const ctx = React.useContext(NoteContext);
    if (!ctx) {
        throw new Error("useNoteArray must be used within a NoteProvider")
    }
    const array = ctx.doc.getArray(name);
    return array;
}

export function useNoteProviders() {
    const ctx = React.useContext(NoteContext);

    if (!ctx) {
        throw new Error("useNoteProviders must be used within a NoteProvider")
    }

    return ctx.providers;
}

export function useNoteAwareness() {
    const ctx = React.useContext(NoteContext);
    if (!ctx) {
        throw new Error("useNoteAwareness must be used within a NoteProvider")
    }

    const awareness = ctx.providers.websocket.awareness;
    return awareness;
}
