"use client";
import { jsx } from 'react/jsx-runtime';
import { Crepe, CrepeFeature } from '@milkdown/crepe';
import '@milkdown/crepe/theme/common/style.css';
import { throttle, cn } from '../../../utils.mjs';
import { editorViewCtx, parserCtx } from '@milkdown/kit/core';
import { listenerCtx, listener } from '@milkdown/kit/plugin/listener';
import { Slice } from '@milkdown/kit/prose/model';
import { Selection } from '@milkdown/kit/prose/state';
import { useRef, useState, useLayoutEffect } from 'react';

function MarkdownEditor({
  value,
  onChange,
  className,
  uploadImage,
  placeholder = "Write something..."
}) {
  const containerRef = useRef(null);
  const crepeRef = useRef(null);
  const isReadyRef = useRef(false);
  const [isReady, setIsReady] = useState(false);
  const onChangeRef = useRef(onChange);
  const initialValueRef = useRef(value ?? "");
  const throttledOnChangeRef = useRef(null);
  onChangeRef.current = onChange;
  useLayoutEffect(() => {
    if (crepeRef.current) return;
    const container = containerRef.current;
    if (!container) return;
    const crepe = new Crepe({
      root: container,
      defaultValue: initialValueRef.current,
      featureConfigs: {
        [CrepeFeature.Placeholder]: {
          text: placeholder
        },
        ...uploadImage ? {
          [CrepeFeature.ImageBlock]: {
            onUpload: async (file) => {
              const url = await uploadImage(file);
              return url;
            }
          }
        } : {}
      }
    });
    throttledOnChangeRef.current = throttle((markdown) => {
      if (onChangeRef.current) onChangeRef.current(markdown);
    }, 200);
    crepe.editor.config((ctx) => {
      ctx.get(listenerCtx).markdownUpdated((_, markdown) => {
        throttledOnChangeRef.current?.(markdown);
      });
    }).use(listener);
    crepe.create().then(() => {
      isReadyRef.current = true;
      setIsReady(true);
    });
    crepeRef.current = crepe;
    return () => {
      try {
        isReadyRef.current = false;
        throttledOnChangeRef.current?.cancel?.();
        throttledOnChangeRef.current = null;
        crepe.destroy();
      } finally {
        crepeRef.current = null;
      }
    };
  }, []);
  useLayoutEffect(() => {
    if (!isReady) return;
    if (!crepeRef.current) return;
    if (typeof value !== "string") return;
    let currentMarkdown;
    try {
      currentMarkdown = crepeRef.current?.getMarkdown?.();
    } catch {
      return;
    }
    if (currentMarkdown === value) return;
    crepeRef.current.editor.action((ctx) => {
      const view = ctx.get(editorViewCtx);
      if (view?.hasFocus?.() === true) return;
      const parser = ctx.get(parserCtx);
      const doc = parser(value);
      if (!doc) return;
      const state = view.state;
      const selection = state.selection;
      const from = selection.from;
      let tr = state.tr;
      tr = tr.replace(0, state.doc.content.size, new Slice(doc.content, 0, 0));
      const docSize = doc.content.size;
      const safeFrom = Math.max(1, Math.min(from, Math.max(1, docSize - 2)));
      tr = tr.setSelection(Selection.near(tr.doc.resolve(safeFrom)));
      view.dispatch(tr);
    });
  }, [value, isReady]);
  return /* @__PURE__ */ jsx("div", { ref: containerRef, className: cn("milkdown-custom", className) });
}

export { MarkdownEditor };
