import { NodeViewWrapper } from "@tiptap/react";
import { useEffect, useState, useCallback, useRef } from "react";
import type { NodeViewProps } from "@tiptap/react";

export function BibliographyView({ editor, node, getPos }: NodeViewProps) {
  const [html, setHtml] = useState("");
  const [count, setCount] = useState(0);
  const [style, setStyle] = useState("apa");
  const cacheRef = useRef("");
  const timerRef = useRef<ReturnType<typeof setTimeout>>();

  // Sync style from collaborative Y.Map("settings")
  useEffect(() => {
    const settingsMap = (editor.storage.citation as any)?.settingsMap;
    if (!settingsMap) return;

    const sync = () => {
      const val = settingsMap.get("citationStyle");
      if (val && val !== style) setStyle(val as string);
    };
    sync();
    settingsMap.observe(sync);
    return () => settingsMap.unobserve(sync);
  }, [editor]);

  const refresh = useCallback(() => {
    const citationsMap = (editor.storage.citation as any)?.citationsMap;
    if (!citationsMap) return;

    const keys = new Set<string>();
    editor.state.doc.descendants((node) => {
      if (node.type.name === "citation" && node.attrs.key) {
        keys.add(node.attrs.key as string);
      }
    });

    const entries: any[] = [];
    for (const key of keys) {
      const entry = citationsMap.get(key);
      if (entry) entries.push({ ...entry, id: key });
    }

    setCount(entries.length);

    if (!entries.length) {
      setHtml("");
      cacheRef.current = "";
      return;
    }

    const cacheKey = entries
      .map((e) => e.id)
      .sort()
      .join(",") + `:${style}`;
    if (cacheKey === cacheRef.current) return;
    cacheRef.current = cacheKey;

    fetch("/api/citations/format", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ entries, style }),
    })
      .then((r) => r.json())
      .then((data) => {
        if (data.html) {
          setHtml(data.html);
          // Persist rendered HTML into node attrs for server-side generation
          const pos = getPos();
          if (typeof pos === "number" && node.attrs.renderedHtml !== data.html) {
            editor.commands.command(({ tr }) => {
              tr.setNodeMarkup(pos, undefined, { ...node.attrs, renderedHtml: data.html });
              return true;
            });
          }
        }
      })
      .catch(console.error);
  }, [editor, style]);

  useEffect(() => {
    const debouncedRefresh = () => {
      clearTimeout(timerRef.current);
      timerRef.current = setTimeout(refresh, 500);
    };

    refresh();

    const citationsMap = (editor.storage.citation as any)?.citationsMap;
    if (citationsMap) citationsMap.observe(debouncedRefresh);

    const onUpdate = () => debouncedRefresh();
    editor.on("update", onUpdate);

    return () => {
      clearTimeout(timerRef.current);
      if (citationsMap) citationsMap.unobserve(debouncedRefresh);
      editor.off("update", onUpdate);
    };
  }, [editor, refresh]);

  return (
    <NodeViewWrapper>
      <div className="bibliography-block" contentEditable={false}>
        <h2 className="bibliography-title">References</h2>
        {count === 0 ? (
          <p className="bibliography-empty">
            No citations yet. Use /Citation to add references.
          </p>
        ) : (
          <div
            className="bibliography-content"
            dangerouslySetInnerHTML={{ __html: html }}
          />
        )}
      </div>
    </NodeViewWrapper>
  );
}
